github.com/Oyster-zx/tendermint@v0.34.24-fork/types/tx.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "errors" 7 "fmt" 8 9 "github.com/tendermint/tendermint/crypto/merkle" 10 "github.com/tendermint/tendermint/crypto/tmhash" 11 tmbytes "github.com/tendermint/tendermint/libs/bytes" 12 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 13 ) 14 15 // TxKeySize is the size of the transaction key index 16 const TxKeySize = sha256.Size 17 18 type ( 19 // Tx is an arbitrary byte array. 20 // NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed. 21 // Might we want types here ? 22 Tx []byte 23 24 // TxKey is the fixed length array key used as an index. 25 TxKey [TxKeySize]byte 26 ) 27 28 // Hash computes the TMHASH hash of the wire encoded transaction. 29 func (tx Tx) Hash() []byte { 30 return tmhash.Sum(tx) 31 } 32 33 func (tx Tx) Key() TxKey { 34 return sha256.Sum256(tx) 35 } 36 37 // String returns the hex-encoded transaction as a string. 38 func (tx Tx) String() string { 39 return fmt.Sprintf("Tx{%X}", []byte(tx)) 40 } 41 42 // Txs is a slice of Tx. 43 type Txs []Tx 44 45 // Hash returns the Merkle root hash of the transaction hashes. 46 // i.e. the leaves of the tree are the hashes of the txs. 47 func (txs Txs) Hash() []byte { 48 // These allocations will be removed once Txs is switched to [][]byte, 49 // ref #2603. This is because golang does not allow type casting slices without unsafe 50 txBzs := make([][]byte, len(txs)) 51 for i := 0; i < len(txs); i++ { 52 txBzs[i] = txs[i].Hash() 53 } 54 return merkle.HashFromByteSlices(txBzs) 55 } 56 57 // Index returns the index of this transaction in the list, or -1 if not found 58 func (txs Txs) Index(tx Tx) int { 59 for i := range txs { 60 if bytes.Equal(txs[i], tx) { 61 return i 62 } 63 } 64 return -1 65 } 66 67 // IndexByHash returns the index of this transaction hash in the list, or -1 if not found 68 func (txs Txs) IndexByHash(hash []byte) int { 69 for i := range txs { 70 if bytes.Equal(txs[i].Hash(), hash) { 71 return i 72 } 73 } 74 return -1 75 } 76 77 // Proof returns a simple merkle proof for this node. 78 // Panics if i < 0 or i >= len(txs) 79 // TODO: optimize this! 80 func (txs Txs) Proof(i int) TxProof { 81 l := len(txs) 82 bzs := make([][]byte, l) 83 for i := 0; i < l; i++ { 84 bzs[i] = txs[i].Hash() 85 } 86 root, proofs := merkle.ProofsFromByteSlices(bzs) 87 88 return TxProof{ 89 RootHash: root, 90 Data: txs[i], 91 Proof: *proofs[i], 92 } 93 } 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 102 // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to. 103 func (tp TxProof) Leaf() []byte { 104 return tp.Data.Hash() 105 } 106 107 // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument, 108 // and if the proof is internally consistent. Otherwise, it returns a sensible error. 109 func (tp TxProof) Validate(dataHash []byte) error { 110 if !bytes.Equal(dataHash, tp.RootHash) { 111 return errors.New("proof matches different data hash") 112 } 113 if tp.Proof.Index < 0 { 114 return errors.New("proof index cannot be negative") 115 } 116 if tp.Proof.Total <= 0 { 117 return errors.New("proof total must be positive") 118 } 119 valid := tp.Proof.Verify(tp.RootHash, tp.Leaf()) 120 if valid != nil { 121 return errors.New("proof is not internally consistent") 122 } 123 return nil 124 } 125 126 func (tp TxProof) ToProto() tmproto.TxProof { 127 128 pbProof := tp.Proof.ToProto() 129 130 pbtp := tmproto.TxProof{ 131 RootHash: tp.RootHash, 132 Data: tp.Data, 133 Proof: pbProof, 134 } 135 136 return pbtp 137 } 138 func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { 139 140 pbProof, err := merkle.ProofFromProto(pb.Proof) 141 if err != nil { 142 return TxProof{}, err 143 } 144 145 pbtp := TxProof{ 146 RootHash: pb.RootHash, 147 Data: pb.Data, 148 Proof: *pbProof, 149 } 150 151 return pbtp, nil 152 } 153 154 // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size. 155 // https://developers.google.com/protocol-buffers/docs/encoding 156 func ComputeProtoSizeForTxs(txs []Tx) int64 { 157 data := Data{Txs: txs} 158 pdData := data.ToProto() 159 return int64(pdData.Size()) 160 }