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. "github.com/tendermint/tendermint/config"
  9. )
  10. var (
  11. ErrTxInvalidAddress = errors.New("Error invalid address")
  12. ErrTxDuplicateAddress = errors.New("Error duplicate address")
  13. ErrTxInvalidAmount = errors.New("Error invalid amount")
  14. ErrTxInsufficientFunds = errors.New("Error insufficient funds")
  15. ErrTxInsufficientGasPrice = errors.New("Error insufficient gas price")
  16. ErrTxUnknownPubKey = errors.New("Error unknown pubkey")
  17. ErrTxInvalidPubKey = errors.New("Error invalid pubkey")
  18. ErrTxInvalidSignature = errors.New("Error invalid signature")
  19. )
  20. type ErrTxInvalidSequence struct {
  21. Got uint64
  22. Expected uint64
  23. }
  24. func (e ErrTxInvalidSequence) Error() string {
  25. return Fmt("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
  26. }
  27. /*
  28. Tx (Transaction) is an atomic operation on the ledger state.
  29. Account Txs:
  30. - SendTx Send coins to address
  31. - CallTx Send a msg to a contract that runs in the vm
  32. Validation Txs:
  33. - BondTx New validator posts a bond
  34. - UnbondTx Validator leaves
  35. - DupeoutTx Validator dupes out (equivocates)
  36. */
  37. type Tx interface {
  38. WriteSignBytes(w io.Writer, n *int64, err *error)
  39. }
  40. // Types of Tx implementations
  41. const (
  42. // Account transactions
  43. TxTypeSend = byte(0x01)
  44. TxTypeCall = byte(0x02)
  45. // Validation transactions
  46. TxTypeBond = byte(0x11)
  47. TxTypeUnbond = byte(0x12)
  48. TxTypeRebond = byte(0x13)
  49. TxTypeDupeout = byte(0x14)
  50. )
  51. // for binary.readReflect
  52. var _ = binary.RegisterInterface(
  53. struct{ Tx }{},
  54. binary.ConcreteType{&SendTx{}, TxTypeSend},
  55. binary.ConcreteType{&CallTx{}, TxTypeCall},
  56. binary.ConcreteType{&BondTx{}, TxTypeBond},
  57. binary.ConcreteType{&UnbondTx{}, TxTypeUnbond},
  58. binary.ConcreteType{&RebondTx{}, TxTypeRebond},
  59. binary.ConcreteType{&DupeoutTx{}, TxTypeDupeout},
  60. )
  61. //-----------------------------------------------------------------------------
  62. type TxInput struct {
  63. Address []byte `json:"address"` // Hash of the PubKey
  64. Amount uint64 `json:"amount"` // Must not exceed account balance
  65. Sequence uint `json:"sequence"` // Must be 1 greater than the last committed TxInput
  66. Signature account.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
  67. PubKey account.PubKey `json:"pub_key"` // Must not be nil, may be nil
  68. }
  69. func (txIn *TxInput) ValidateBasic() error {
  70. if len(txIn.Address) != 20 {
  71. return ErrTxInvalidAddress
  72. }
  73. if txIn.Amount == 0 {
  74. return ErrTxInvalidAmount
  75. }
  76. return nil
  77. }
  78. func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int64, err *error) {
  79. binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
  80. }
  81. func (txIn *TxInput) String() string {
  82. return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey)
  83. }
  84. //-----------------------------------------------------------------------------
  85. type TxOutput struct {
  86. Address []byte `json:"address"` // Hash of the PubKey
  87. Amount uint64 `json:"amount"` // The sum of all outputs must not exceed the inputs.
  88. }
  89. func (txOut *TxOutput) ValidateBasic() error {
  90. if len(txOut.Address) != 20 {
  91. return ErrTxInvalidAddress
  92. }
  93. if txOut.Amount == 0 {
  94. return ErrTxInvalidAmount
  95. }
  96. return nil
  97. }
  98. func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int64, err *error) {
  99. binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
  100. }
  101. func (txOut *TxOutput) String() string {
  102. return Fmt("TxOutput{%X,%v}", txOut.Address, txOut.Amount)
  103. }
  104. //-----------------------------------------------------------------------------
  105. type SendTx struct {
  106. Inputs []*TxInput `json:"inputs"`
  107. Outputs []*TxOutput `json:"outputs"`
  108. }
  109. func (tx *SendTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  110. // We hex encode the network name so we don't deal with escaping issues.
  111. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err)
  112. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
  113. for i, in := range tx.Inputs {
  114. in.WriteSignBytes(w, n, err)
  115. if i != len(tx.Inputs)-1 {
  116. binary.WriteTo([]byte(","), w, n, err)
  117. }
  118. }
  119. binary.WriteTo([]byte(`],"outputs":[`), w, n, err)
  120. for i, out := range tx.Outputs {
  121. out.WriteSignBytes(w, n, err)
  122. if i != len(tx.Outputs)-1 {
  123. binary.WriteTo([]byte(","), w, n, err)
  124. }
  125. }
  126. binary.WriteTo([]byte(`]}]}`), w, n, err)
  127. }
  128. func (tx *SendTx) String() string {
  129. return Fmt("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
  130. }
  131. //-----------------------------------------------------------------------------
  132. type CallTx struct {
  133. Input *TxInput `json:"input"`
  134. Address []byte `json:"address"`
  135. GasLimit uint64 `json:"gas_limit"`
  136. Fee uint64 `json:"fee"`
  137. Data []byte `json:"data"`
  138. }
  139. func (tx *CallTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
  140. // We hex encode the network name so we don't deal with escaping issues.
  141. binary.WriteTo([]byte(Fmt(`{"network":"%X"`, config.App().GetString("network"))), w, n, err)
  142. binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
  143. binary.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
  144. tx.Input.WriteSignBytes(w, n, err)
  145. binary.WriteTo([]byte(`}]}`), w, n, err)
  146. }
  147. func (tx *CallTx) String() string {
  148. return Fmt("CallTx{%v -> %x: %x}", tx.Input, tx.Address, tx.Data)
  149. }
  150. //-----------------------------------------------------------------------------
  151. type BondTx struct {
  152. PubKey account.PubKeyEd25519 `json:"pub_key"`
  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.App().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.App().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.App().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. }