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.

175 lines
4.7 KiB

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