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.

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