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.

125 lines
3.1 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. abci "github.com/tendermint/abci/types"
  7. cmn "github.com/tendermint/tmlibs/common"
  8. "github.com/tendermint/tmlibs/merkle"
  9. )
  10. // Tx is an arbitrary byte array.
  11. // NOTE: Tx has no types at this level, so when go-wire encoded it's 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. type Tx []byte
  15. // Hash computes the RIPEMD160 hash of the go-wire encoded transaction.
  16. func (tx Tx) Hash() []byte {
  17. return wireHasher(tx).Hash()
  18. }
  19. // String returns the hex-encoded transaction as a string.
  20. func (tx Tx) String() string {
  21. return fmt.Sprintf("Tx{%X}", []byte(tx))
  22. }
  23. // Txs is a slice of Tx.
  24. type Txs []Tx
  25. // Hash returns the simple Merkle root hash of the transactions.
  26. func (txs Txs) Hash() []byte {
  27. // Recursive impl.
  28. // Copied from tmlibs/merkle to avoid allocations
  29. switch len(txs) {
  30. case 0:
  31. return nil
  32. case 1:
  33. return txs[0].Hash()
  34. default:
  35. left := Txs(txs[:(len(txs)+1)/2]).Hash()
  36. right := Txs(txs[(len(txs)+1)/2:]).Hash()
  37. return merkle.SimpleHashFromTwoHashes(left, right)
  38. }
  39. }
  40. // Index returns the index of this transaction in the list, or -1 if not found
  41. func (txs Txs) Index(tx Tx) int {
  42. for i := range txs {
  43. if bytes.Equal(txs[i], tx) {
  44. return i
  45. }
  46. }
  47. return -1
  48. }
  49. // IndexByHash returns the index of this transaction hash in the list, or -1 if not found
  50. func (txs Txs) IndexByHash(hash []byte) int {
  51. for i := range txs {
  52. if bytes.Equal(txs[i].Hash(), hash) {
  53. return i
  54. }
  55. }
  56. return -1
  57. }
  58. // Proof returns a simple merkle proof for this node.
  59. //
  60. // Panics if i < 0 or i >= len(txs)
  61. //
  62. // TODO: optimize this!
  63. func (txs Txs) Proof(i int) TxProof {
  64. l := len(txs)
  65. hashers := make([]merkle.Hasher, l)
  66. for i := 0; i < l; i++ {
  67. hashers[i] = txs[i]
  68. }
  69. root, proofs := merkle.SimpleProofsFromHashers(hashers)
  70. return TxProof{
  71. Index: i,
  72. Total: l,
  73. RootHash: root,
  74. Data: txs[i],
  75. Proof: *proofs[i],
  76. }
  77. }
  78. // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
  79. type TxProof struct {
  80. Index, Total int
  81. RootHash cmn.HexBytes
  82. Data Tx
  83. Proof merkle.SimpleProof
  84. }
  85. // LeadHash returns the hash of the transaction this proof refers to.
  86. func (tp TxProof) LeafHash() []byte {
  87. return tp.Data.Hash()
  88. }
  89. // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
  90. // and if the proof is internally consistent. Otherwise, it returns a sensible error.
  91. func (tp TxProof) Validate(dataHash []byte) error {
  92. if !bytes.Equal(dataHash, tp.RootHash) {
  93. return errors.New("Proof matches different data hash")
  94. }
  95. valid := tp.Proof.Verify(tp.Index, tp.Total, tp.LeafHash(), tp.RootHash)
  96. if !valid {
  97. return errors.New("Proof is not internally consistent")
  98. }
  99. return nil
  100. }
  101. // TxResult contains results of executing the transaction.
  102. //
  103. // One usage is indexing transaction results.
  104. type TxResult struct {
  105. Height int64 `json:"height"`
  106. Index uint32 `json:"index"`
  107. Tx Tx `json:"tx"`
  108. Result abci.ResponseDeliverTx `json:"result"`
  109. }