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.

170 lines
4.4 KiB

7 years ago
7 years ago
7 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "errors"
  6. "fmt"
  7. "github.com/tendermint/tendermint/crypto/merkle"
  8. "github.com/tendermint/tendermint/crypto/tmhash"
  9. tmbytes "github.com/tendermint/tendermint/libs/bytes"
  10. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  11. )
  12. // Tx is an arbitrary byte array.
  13. // NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
  14. // Might we want types here ?
  15. type Tx []byte
  16. // Key produces a fixed-length key for use in indexing.
  17. func (tx Tx) Key() TxKey { return sha256.Sum256(tx) }
  18. // Hash computes the TMHASH hash of the wire encoded transaction.
  19. func (tx Tx) Hash() []byte { return tmhash.Sum(tx) }
  20. // String returns the hex-encoded transaction as a string.
  21. func (tx Tx) String() string { return fmt.Sprintf("Tx{%X}", []byte(tx)) }
  22. // Txs is a slice of Tx.
  23. type Txs []Tx
  24. // Hash returns the Merkle root hash of the transaction hashes.
  25. // i.e. the leaves of the tree are the hashes of the txs.
  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].Hash()
  32. }
  33. return merkle.HashFromByteSlices(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].Hash()
  61. }
  62. root, proofs := merkle.ProofsFromByteSlices(bzs)
  63. return TxProof{
  64. RootHash: root,
  65. Data: txs[i],
  66. Proof: *proofs[i],
  67. }
  68. }
  69. // ToSliceOfBytes converts a Txs to slice of byte slices.
  70. //
  71. // NOTE: This method should become obsolete once Txs is switched to [][]byte.
  72. // ref: #2603
  73. // TODO This function is to disappear when TxRecord is introduced
  74. func (txs Txs) ToSliceOfBytes() [][]byte {
  75. txBzs := make([][]byte, len(txs))
  76. for i := 0; i < len(txs); i++ {
  77. txBzs[i] = txs[i]
  78. }
  79. return txBzs
  80. }
  81. // ToTxs converts a raw slice of byte slices into a Txs type.
  82. // TODO This function is to disappear when TxRecord is introduced
  83. func ToTxs(txs [][]byte) Txs {
  84. txBzs := make(Txs, len(txs))
  85. for i := 0; i < len(txs); i++ {
  86. txBzs[i] = txs[i]
  87. }
  88. return txBzs
  89. }
  90. // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
  91. type TxProof struct {
  92. RootHash tmbytes.HexBytes `json:"root_hash"`
  93. Data Tx `json:"data"`
  94. Proof merkle.Proof `json:"proof"`
  95. }
  96. // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to.
  97. func (tp TxProof) Leaf() []byte {
  98. return tp.Data.Hash()
  99. }
  100. // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
  101. // and if the proof is internally consistent. Otherwise, it returns a sensible error.
  102. func (tp TxProof) Validate(dataHash []byte) error {
  103. if !bytes.Equal(dataHash, tp.RootHash) {
  104. return errors.New("proof matches different data hash")
  105. }
  106. if tp.Proof.Index < 0 {
  107. return errors.New("proof index cannot be negative")
  108. }
  109. if tp.Proof.Total <= 0 {
  110. return errors.New("proof total must be positive")
  111. }
  112. valid := tp.Proof.Verify(tp.RootHash, tp.Leaf())
  113. if valid != nil {
  114. return errors.New("proof is not internally consistent")
  115. }
  116. return nil
  117. }
  118. func (tp TxProof) ToProto() tmproto.TxProof {
  119. pbProof := tp.Proof.ToProto()
  120. pbtp := tmproto.TxProof{
  121. RootHash: tp.RootHash,
  122. Data: tp.Data,
  123. Proof: pbProof,
  124. }
  125. return pbtp
  126. }
  127. func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) {
  128. pbProof, err := merkle.ProofFromProto(pb.Proof)
  129. if err != nil {
  130. return TxProof{}, err
  131. }
  132. pbtp := TxProof{
  133. RootHash: pb.RootHash,
  134. Data: pb.Data,
  135. Proof: *pbProof,
  136. }
  137. return pbtp, nil
  138. }
  139. // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size.
  140. // https://developers.google.com/protocol-buffers/docs/encoding
  141. func ComputeProtoSizeForTxs(txs []Tx) int64 {
  142. data := Data{Txs: txs}
  143. pdData := data.ToProto()
  144. return int64(pdData.Size())
  145. }