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.

119 lines
2.7 KiB

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