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.

113 lines
2.5 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. abci "github.com/tendermint/abci/types"
  6. "github.com/tendermint/go-merkle"
  7. )
  8. type Tx []byte
  9. // NOTE: this is the hash of the go-wire encoded Tx.
  10. // Tx has no types at this level, so just length-prefixed.
  11. // Alternatively, it may make sense to add types here and let
  12. // []byte be type 0x1 so we can have versioned txs if need be in the future.
  13. func (tx Tx) Hash() []byte {
  14. return merkle.SimpleHashFromBinary(tx)
  15. }
  16. type Txs []Tx
  17. func (txs Txs) Hash() []byte {
  18. // Recursive impl.
  19. // Copied from go-merkle to avoid allocations
  20. switch len(txs) {
  21. case 0:
  22. return nil
  23. case 1:
  24. return txs[0].Hash()
  25. default:
  26. left := Txs(txs[:(len(txs)+1)/2]).Hash()
  27. right := Txs(txs[(len(txs)+1)/2:]).Hash()
  28. return merkle.SimpleHashFromTwoHashes(left, right)
  29. }
  30. }
  31. // Index returns the index of this transaction in the list, or -1 if not found
  32. func (txs Txs) Index(tx Tx) int {
  33. for i := range txs {
  34. if bytes.Equal(txs[i], tx) {
  35. return i
  36. }
  37. }
  38. return -1
  39. }
  40. // Index returns the index of this transaction hash in the list, or -1 if not found
  41. func (txs Txs) IndexByHash(hash []byte) int {
  42. for i := range txs {
  43. if bytes.Equal(txs[i].Hash(), hash) {
  44. return i
  45. }
  46. }
  47. return -1
  48. }
  49. // Proof returns a simple merkle proof for this node.
  50. //
  51. // Panics if i < 0 or i >= len(txs)
  52. //
  53. // TODO: optimize this!
  54. func (txs Txs) Proof(i int) TxProof {
  55. l := len(txs)
  56. hashables := make([]merkle.Hashable, l)
  57. for i := 0; i < l; i++ {
  58. hashables[i] = txs[i]
  59. }
  60. root, proofs := merkle.SimpleProofsFromHashables(hashables)
  61. return TxProof{
  62. Index: i,
  63. Total: l,
  64. RootHash: root,
  65. Data: txs[i],
  66. Proof: *proofs[i],
  67. }
  68. }
  69. type TxProof struct {
  70. Index, Total int
  71. RootHash []byte
  72. Data Tx
  73. Proof merkle.SimpleProof
  74. }
  75. func (tp TxProof) LeafHash() []byte {
  76. return tp.Data.Hash()
  77. }
  78. // Validate returns nil if it matches the dataHash, and is internally consistent
  79. // otherwise, returns a sensible error
  80. func (tp TxProof) Validate(dataHash []byte) error {
  81. if !bytes.Equal(dataHash, tp.RootHash) {
  82. return errors.New("Proof matches different data hash")
  83. }
  84. valid := tp.Proof.Verify(tp.Index, tp.Total, tp.LeafHash(), tp.RootHash)
  85. if !valid {
  86. return errors.New("Proof is not internally consistent")
  87. }
  88. return nil
  89. }
  90. // TxResult contains results of executing the transaction.
  91. //
  92. // One usage is indexing transaction results.
  93. type TxResult struct {
  94. Height uint64 `json:"height"`
  95. Index uint32 `json:"index"`
  96. Tx Tx `json:"tx"`
  97. Result abci.ResponseDeliverTx `json:"result"`
  98. }