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.

118 lines
2.6 KiB

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