github.com/evdatsion/aphelion-dpos-bft@v0.32.1/types/tx.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 amino "github.com/evdatsion/go-amino" 9 10 abci "github.com/evdatsion/aphelion-dpos-bft/abci/types" 11 "github.com/evdatsion/aphelion-dpos-bft/crypto/merkle" 12 "github.com/evdatsion/aphelion-dpos-bft/crypto/tmhash" 13 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 14 ) 15 16 // Tx is an arbitrary byte array. 17 // NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed. 18 // Might we want types here ? 19 type Tx []byte 20 21 // Hash computes the TMHASH hash of the wire encoded transaction. 22 func (tx Tx) Hash() []byte { 23 return tmhash.Sum(tx) 24 } 25 26 // String returns the hex-encoded transaction as a string. 27 func (tx Tx) String() string { 28 return fmt.Sprintf("Tx{%X}", []byte(tx)) 29 } 30 31 // Txs is a slice of Tx. 32 type Txs []Tx 33 34 // Hash returns the Merkle root hash of the transaction hashes. 35 // i.e. the leaves of the tree are the hashes of the txs. 36 func (txs Txs) Hash() []byte { 37 // These allocations will be removed once Txs is switched to [][]byte, 38 // ref #2603. This is because golang does not allow type casting slices without unsafe 39 txBzs := make([][]byte, len(txs)) 40 for i := 0; i < len(txs); i++ { 41 txBzs[i] = txs[i].Hash() 42 } 43 return merkle.SimpleHashFromByteSlices(txBzs) 44 } 45 46 // Index returns the index of this transaction in the list, or -1 if not found 47 func (txs Txs) Index(tx Tx) int { 48 for i := range txs { 49 if bytes.Equal(txs[i], tx) { 50 return i 51 } 52 } 53 return -1 54 } 55 56 // IndexByHash returns the index of this transaction hash in the list, or -1 if not found 57 func (txs Txs) IndexByHash(hash []byte) int { 58 for i := range txs { 59 if bytes.Equal(txs[i].Hash(), hash) { 60 return i 61 } 62 } 63 return -1 64 } 65 66 // Proof returns a simple merkle proof for this node. 67 // Panics if i < 0 or i >= len(txs) 68 // TODO: optimize this! 69 func (txs Txs) Proof(i int) TxProof { 70 l := len(txs) 71 bzs := make([][]byte, l) 72 for i := 0; i < l; i++ { 73 bzs[i] = txs[i].Hash() 74 } 75 root, proofs := merkle.SimpleProofsFromByteSlices(bzs) 76 77 return TxProof{ 78 RootHash: root, 79 Data: txs[i], 80 Proof: *proofs[i], 81 } 82 } 83 84 // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. 85 type TxProof struct { 86 RootHash cmn.HexBytes 87 Data Tx 88 Proof merkle.SimpleProof 89 } 90 91 // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to. 92 func (tp TxProof) Leaf() []byte { 93 return tp.Data.Hash() 94 } 95 96 // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument, 97 // and if the proof is internally consistent. Otherwise, it returns a sensible error. 98 func (tp TxProof) Validate(dataHash []byte) error { 99 if !bytes.Equal(dataHash, tp.RootHash) { 100 return errors.New("Proof matches different data hash") 101 } 102 if tp.Proof.Index < 0 { 103 return errors.New("Proof index cannot be negative") 104 } 105 if tp.Proof.Total <= 0 { 106 return errors.New("Proof total must be positive") 107 } 108 valid := tp.Proof.Verify(tp.RootHash, tp.Leaf()) 109 if valid != nil { 110 return errors.New("Proof is not internally consistent") 111 } 112 return nil 113 } 114 115 // TxResult contains results of executing the transaction. 116 // 117 // One usage is indexing transaction results. 118 type TxResult struct { 119 Height int64 `json:"height"` 120 Index uint32 `json:"index"` 121 Tx Tx `json:"tx"` 122 Result abci.ResponseDeliverTx `json:"result"` 123 } 124 125 // ComputeAminoOverhead calculates the overhead for amino encoding a transaction. 126 // The overhead consists of varint encoding the field number and the wire type 127 // (= length-delimited = 2), and another varint encoding the length of the 128 // transaction. 129 // The field number can be the field number of the particular transaction, or 130 // the field number of the parenting struct that contains the transactions []Tx 131 // as a field (this field number is repeated for each contained Tx). 132 // If some []Tx are encoded directly (without a parenting struct), the default 133 // fieldNum is also 1 (see BinFieldNum in amino.MarshalBinaryBare). 134 func ComputeAminoOverhead(tx Tx, fieldNum int) int64 { 135 fnum := uint64(fieldNum) 136 typ3AndFieldNum := (uint64(fnum) << 3) | uint64(amino.Typ3_ByteLength) 137 return int64(amino.UvarintSize(typ3AndFieldNum)) + int64(amino.UvarintSize(uint64(len(tx)))) 138 }