You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
8.7 KiB

10 years ago
  1. package types
  2. import (
  3. "errors"
  4. "io"
  5. "github.com/tendermint/tendermint/account"
  6. "github.com/tendermint/tendermint/binary"
  7. . "github.com/tendermint/tendermint/common"
  8. )
  9. var (
  10. ErrTxInvalidAddress = errors.New("Error invalid address")
  11. ErrTxDuplicateAddress = errors.New("Error duplicate address")
  12. ErrTxInvalidAmount = errors.New("Error invalid amount")
  13. ErrTxInsufficientFunds = errors.New("Error insufficient funds")
  14. ErrTxInsufficientGasPrice = errors.New("Error insufficient gas price")
  15. ErrTxUnknownPubKey = errors.New("Error unknown pubkey")
  16. ErrTxInvalidPubKey = errors.New("Error invalid pubkey")
  17. ErrTxInvalidSignature = errors.New("Error invalid signature")
  18. )
  19. type ErrTxInvalidSequence struct {
  20. Got uint64
  21. Expected uint64
  22. }
  23. func (e ErrTxInvalidSequence) Error() string {
  24. return Fmt("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
  25. }
  26. /*
  27. Tx (Transaction) is an atomic operation on the ledger state.
  28. Account Txs:
  29. - SendTx Send coins to address
  30. - CallTx Send a msg to a contract that runs in the vm
  31. Validation Txs:
  32. - BondTx New validator posts a bond
  33. - UnbondTx Validator leaves
  34. - DupeoutTx Validator dupes out (equivocates)
  35. */
  36. type Tx interface {
  37. WriteSignBytes(w io.Writer, n *int64, err *error)
  38. }
  39. // Types of Tx implementations
  40. const (
  41. // Account transactions
  42. TxTypeSend = byte(0x01)
  43. TxTypeCall = byte(0x02)
  44. // Validation transactions
  45. TxTypeBond = byte(0x11)
  46. TxTypeUnbond = byte(0x12)
  47. TxTypeRebond = byte(0x13)
  48. TxTypeDupeout = byte(0x14)
  49. )
  50. // for binary.readReflect
  51. var _ = binary.RegisterInterface(
  52. struct{ Tx }{},
  53. binary.ConcreteType{&SendTx{}, TxTypeSend},
  54. binary.ConcreteType{&CallTx{}, TxTypeCall},
  55. binary.ConcreteType{&BondTx{}, TxTypeBond},
  56. binary.ConcreteType{&UnbondTx{}, TxTypeUnbond},
  57. binary.ConcreteType{&RebondTx{}, TxTypeRebond},
  58. binary.ConcreteType{&DupeoutTx{}, TxTypeDupeout},
  59. )
  60. //-----------------------------------------------------------------------------
  61. type TxInput struct {
  62. Address []byte `json:"address"` // Hash of the PubKey
  63. Amount uint64 `json:"amount"` // Must not exceed account balance
  64. Sequence uint `json:"sequence"` // Must be 1 greater than the last committed TxInput
  65. Signature account.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
  66. PubKey account.PubKey `json:"pub_key"` // Must not be nil, may be nil
  67. }
  68. func (txIn *TxInput) ValidateBasic() error {
  69. if len(txIn.Address) != 20 {
  70. return ErrTxInvalidAddress
  71. }
  72. if txIn.Amount == 0 {
  73. return ErrTxInvalidAmount
  74. }
  75. return nil
  76. }
  77. func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int64, err *error) {
  78. binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
  79. }
  80. func (txIn *TxInput) String() string {
  81. return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey)
  82. }
  83. //-----------------------------------------------------------------------------
  84. type TxOutput struct {
  85. Address []byte `json:"address"` // Hash of the PubKey
  86. Amount uint64 `json:"amount"` // The sum of all outputs must not exceed the inputs.
  87. }
  88. func (txOut *TxOutput) ValidateBasic() error {
  89. if len(txOut.Address) != 20 {
  90. return ErrTxInvalidAddress
  91. }
  92. if txOut.Amount == 0 {
  93. return ErrTxInvalidAmount
  94. }
  95. return nil
  96. }
  97. func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int64, err *error) {
  98. binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
  99. }
  100. func (txOut *TxOutput) String() string {
  101. return Fmt("TxOutput{%X,%v}", txOut.Address, txOut.Amount)
  102. }
  103. //-----------------------------------------------------------------------------
  104. type SendTx struct {
  105. Inputs []*TxInput `json:"inputs"`
  106. Outputs []*TxOutput `json:"outputs"`
  107. }
  108. func (tx *SendTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  109. // We hex encode the network name so we don't deal with escaping issues.
  110. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
  111. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
  112. for i, in := range tx.Inputs {
  113. in.WriteSignBytes(w, n, err)
  114. if i != len(tx.Inputs)-1 {
  115. binary.WriteTo([]byte(","), w, n, err)
  116. }
  117. }
  118. binary.WriteTo([]byte(`],"outputs":[`), w, n, err)
  119. for i, out := range tx.Outputs {
  120. out.WriteSignBytes(w, n, err)
  121. if i != len(tx.Outputs)-1 {
  122. binary.WriteTo([]byte(","), w, n, err)
  123. }
  124. }
  125. binary.WriteTo([]byte(`]}]}`), w, n, err)
  126. }
  127. func (tx *SendTx) String() string {
  128. return Fmt("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
  129. }
  130. //-----------------------------------------------------------------------------
  131. type CallTx struct {
  132. Input *TxInput `json:"input"`
  133. Address []byte `json:"address"`
  134. GasLimit uint64 `json:"gas_limit"`
  135. Fee uint64 `json:"fee"`
  136. Data []byte `json:"data"`
  137. }
  138. func (tx *CallTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  139. // We hex encode the network name so we don't deal with escaping issues.
  140. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
  141. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
  142. binary.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
  143. tx.Input.WriteSignBytes(w, n, err)
  144. binary.WriteTo([]byte(`}]}`), w, n, err)
  145. }
  146. func (tx *CallTx) String() string {
  147. return Fmt("CallTx{%v -> %x: %x}", tx.Input, tx.Address, tx.Data)
  148. }
  149. //-----------------------------------------------------------------------------
  150. type BondTx struct {
  151. PubKey account.PubKeyEd25519 `json:"pub_key"`
  152. Signature account.SignatureEd25519 `json:"signature"`
  153. Inputs []*TxInput `json:"inputs"`
  154. UnbondTo []*TxOutput `json:"unbond_to"`
  155. }
  156. func (tx *BondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  157. // We hex encode the network name so we don't deal with escaping issues.
  158. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
  159. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
  160. for i, in := range tx.Inputs {
  161. in.WriteSignBytes(w, n, err)
  162. if i != len(tx.Inputs)-1 {
  163. binary.WriteTo([]byte(","), w, n, err)
  164. }
  165. }
  166. binary.WriteTo([]byte(Fmt(`],"pub_key":`)), w, n, err)
  167. binary.WriteTo(binary.JSONBytes(tx.PubKey), w, n, err)
  168. binary.WriteTo([]byte(`,"unbond_to":[`), w, n, err)
  169. for i, out := range tx.UnbondTo {
  170. out.WriteSignBytes(w, n, err)
  171. if i != len(tx.UnbondTo)-1 {
  172. binary.WriteTo([]byte(","), w, n, err)
  173. }
  174. }
  175. binary.WriteTo([]byte(`]}]}`), w, n, err)
  176. }
  177. func (tx *BondTx) String() string {
  178. return Fmt("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo)
  179. }
  180. //-----------------------------------------------------------------------------
  181. type UnbondTx struct {
  182. Address []byte `json:"address"`
  183. Height uint `json:"height"`
  184. Signature account.SignatureEd25519 `json:"signature"`
  185. }
  186. func (tx *UnbondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  187. // We hex encode the network name so we don't deal with escaping issues.
  188. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
  189. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
  190. }
  191. func (tx *UnbondTx) String() string {
  192. return Fmt("UnbondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature)
  193. }
  194. //-----------------------------------------------------------------------------
  195. type RebondTx struct {
  196. Address []byte `json:"address"`
  197. Height uint `json:"height"`
  198. Signature account.SignatureEd25519 `json:"signature"`
  199. }
  200. func (tx *RebondTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  201. // We hex encode the network name so we don't deal with escaping issues.
  202. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.GetString("network"))), w, n, err)
  203. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
  204. }
  205. func (tx *RebondTx) String() string {
  206. return Fmt("RebondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature)
  207. }
  208. //-----------------------------------------------------------------------------
  209. type DupeoutTx struct {
  210. Address []byte `json:"address"`
  211. VoteA Vote `json:"vote_a"`
  212. VoteB Vote `json:"vote_b"`
  213. }
  214. func (tx *DupeoutTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  215. panic("DupeoutTx has no sign bytes")
  216. }
  217. func (tx *DupeoutTx) String() string {
  218. return Fmt("DupeoutTx{%X,%v,%v}", tx.Address, tx.VoteA, tx.VoteB)
  219. }
  220. //-----------------------------------------------------------------------------
  221. func TxId(tx Tx) []byte {
  222. signBytes := account.SignBytes(tx)
  223. return binary.BinaryRipemd160(signBytes)
  224. }