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.

120 lines
3.1 KiB

6 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. // Tx is an arbitrary byte array.
  12. // NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
  13. // Might we want types here ?
  14. type Tx []byte
  15. // Hash computes the TMHASH hash of the wire encoded transaction.
  16. func (tx Tx) Hash() []byte {
  17. return tmhash.Sum(tx)
  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. // These allocations will be removed once Txs is switched to [][]byte,
  28. // ref #2603. This is because golang does not allow type casting slices without unsafe
  29. txBzs := make([][]byte, len(txs))
  30. for i := 0; i < len(txs); i++ {
  31. txBzs[i] = txs[i]
  32. }
  33. return merkle.SimpleHashFromByteSlices(txBzs)
  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. // IndexByHash 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. // Panics if i < 0 or i >= len(txs)
  55. // TODO: optimize this!
  56. func (txs Txs) Proof(i int) TxProof {
  57. l := len(txs)
  58. bzs := make([][]byte, l)
  59. for i := 0; i < l; i++ {
  60. bzs[i] = txs[i]
  61. }
  62. root, proofs := merkle.SimpleProofsFromByteSlices(bzs)
  63. return TxProof{
  64. RootHash: root,
  65. Data: txs[i],
  66. Proof: *proofs[i],
  67. }
  68. }
  69. // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
  70. type TxProof struct {
  71. RootHash cmn.HexBytes
  72. Data Tx
  73. Proof merkle.SimpleProof
  74. }
  75. // LeadHash returns the hash of the this proof refers to.
  76. func (tp TxProof) LeafHash() []byte {
  77. return tp.Data.Hash()
  78. }
  79. // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
  80. // and if the proof is internally consistent. Otherwise, it returns a sensible error.
  81. func (tp TxProof) Validate(dataHash []byte) error {
  82. if !bytes.Equal(dataHash, tp.RootHash) {
  83. return errors.New("Proof matches different data hash")
  84. }
  85. if tp.Proof.Index < 0 {
  86. return errors.New("Proof index cannot be negative")
  87. }
  88. if tp.Proof.Total <= 0 {
  89. return errors.New("Proof total must be positive")
  90. }
  91. valid := tp.Proof.Verify(tp.RootHash, tp.LeafHash())
  92. if valid != nil {
  93. return errors.New("Proof is not internally consistent")
  94. }
  95. return nil
  96. }
  97. // TxResult contains results of executing the transaction.
  98. //
  99. // One usage is indexing transaction results.
  100. type TxResult struct {
  101. Height int64 `json:"height"`
  102. Index uint32 `json:"index"`
  103. Tx Tx `json:"tx"`
  104. Result abci.ResponseDeliverTx `json:"result"`
  105. }