github.com/okex/exchain@v1.8.0/libs/tendermint/types/tx.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 ethcmn "github.com/ethereum/go-ethereum/common" 9 10 "github.com/tendermint/go-amino" 11 12 abci "github.com/okex/exchain/libs/tendermint/abci/types" 13 "github.com/okex/exchain/libs/tendermint/crypto/etherhash" 14 "github.com/okex/exchain/libs/tendermint/crypto/merkle" 15 "github.com/okex/exchain/libs/tendermint/crypto/tmhash" 16 tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes" 17 ) 18 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 type Tx []byte 23 24 func Bytes2Hash(txBytes []byte, height int64) string { 25 txHash := Tx(txBytes).Hash(height) 26 return ethcmn.BytesToHash(txHash).String() 27 } 28 29 // Hash computes the TMHASH hash of the wire encoded transaction. 30 func (tx Tx) Hash(height int64) []byte { 31 if HigherThanVenus(height) { 32 return etherhash.Sum(tx) 33 } 34 return tmhash.Sum(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(height int64) []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(height) 53 } 54 return merkle.SimpleHashFromByteSlices(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, height int64) int { 69 for i := range txs { 70 if bytes.Equal(txs[i].Hash(height), 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, height int64) TxProof { 81 l := len(txs) 82 bzs := make([][]byte, l) 83 for i := 0; i < l; i++ { 84 bzs[i] = txs[i].Hash(height) 85 } 86 root, proofs := merkle.SimpleProofsFromByteSlices(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.SimpleProof `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(height int64) []byte { 104 return tp.Data.Hash(height) 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, height int64) 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(height)) 120 if valid != nil { 121 return errors.New("proof is not internally consistent") 122 } 123 return nil 124 } 125 126 // TxResult contains results of executing the transaction. 127 // 128 // One usage is indexing transaction results. 129 type TxResult struct { 130 Height int64 `json:"height"` 131 Index uint32 `json:"index"` 132 Tx Tx `json:"tx"` 133 Result abci.ResponseDeliverTx `json:"result"` 134 } 135 136 func (txResult *TxResult) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error { 137 var dataLen uint64 = 0 138 var subData []byte 139 140 for { 141 data = data[dataLen:] 142 143 if len(data) == 0 { 144 break 145 } 146 147 pos, aminoType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0]) 148 if err != nil { 149 return err 150 } 151 data = data[1:] 152 153 if aminoType == amino.Typ3_ByteLength { 154 var n int 155 dataLen, n, err = amino.DecodeUvarint(data) 156 if err != nil { 157 return err 158 } 159 160 data = data[n:] 161 if len(data) < int(dataLen) { 162 return fmt.Errorf("invalid data length: %d", dataLen) 163 } 164 subData = data[:dataLen] 165 } 166 167 switch pos { 168 case 1: 169 var n int 170 var uvint uint64 171 uvint, n, err = amino.DecodeUvarint(data) 172 if err != nil { 173 return err 174 } 175 txResult.Height = int64(uvint) 176 dataLen = uint64(n) 177 case 2: 178 var n int 179 var uvint uint64 180 uvint, n, err = amino.DecodeUvarint(data) 181 if err != nil { 182 return err 183 } 184 txResult.Index = uint32(uvint) 185 dataLen = uint64(n) 186 case 3: 187 txResult.Tx = make(Tx, dataLen) 188 copy(txResult.Tx, subData) 189 case 4: 190 err = txResult.Result.UnmarshalFromAmino(cdc, subData) 191 if err != nil { 192 return err 193 } 194 default: 195 return fmt.Errorf("unexpect feild num %d", pos) 196 } 197 } 198 return nil 199 } 200 201 // ComputeAminoOverhead calculates the overhead for amino encoding a transaction. 202 // The overhead consists of varint encoding the field number and the wire type 203 // (= length-delimited = 2), and another varint encoding the length of the 204 // transaction. 205 // The field number can be the field number of the particular transaction, or 206 // the field number of the parenting struct that contains the transactions []Tx 207 // as a field (this field number is repeated for each contained Tx). 208 // If some []Tx are encoded directly (without a parenting struct), the default 209 // fieldNum is also 1 (see BinFieldNum in amino.MarshalBinaryBare). 210 func ComputeAminoOverhead(tx Tx, fieldNum int) int64 { 211 fnum := uint64(fieldNum) 212 typ3AndFieldNum := (fnum << 3) | uint64(amino.Typ3_ByteLength) 213 return int64(amino.UvarintSize(typ3AndFieldNum)) + int64(amino.UvarintSize(uint64(len(tx)))) 214 } 215 216 type WrappedMempoolTx struct { 217 Height int64 `json:"height"` 218 GasWanted int64 `json:"gas_wanted"` 219 GasLimit int64 `json:"gas_limit"` 220 Tx Tx `json:"tx"` 221 NodeKey []byte `json:"node_key"` 222 Signature []byte `json:"signature"` 223 From string `json:"from"` 224 SenderNonce uint64 `json:"sender_nonce"` 225 Outdated uint32 `json:"outdated"` 226 IsSim uint32 `json:"is_sim"` 227 IsWrapCMTx bool `json:"is_wrap_cm_tx"` 228 WrapCMNonce uint64 `json:"wrap_cm_nonce"` 229 }