github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/consensus/ipbft/types/tx.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 7 "github.com/intfoundation/go-merkle" 8 ) 9 10 type Tx []byte 11 12 // NOTE: this is the hash of the go-wire encoded Tx. 13 // Tx has no types at this level, so just length-prefixed. 14 // Alternatively, it may make sense to add types here and let 15 // []byte be type 0x1 so we can have versioned txs if need be in the future. 16 func (tx Tx) Hash() []byte { 17 return merkle.SimpleHashFromBinary(tx) 18 } 19 20 type Txs []Tx 21 22 func (txs Txs) Hash() []byte { 23 // Recursive impl. 24 // Copied from go-merkle to avoid allocations 25 switch len(txs) { 26 case 0: 27 return nil 28 case 1: 29 return txs[0].Hash() 30 default: 31 left := Txs(txs[:(len(txs)+1)/2]).Hash() 32 right := Txs(txs[(len(txs)+1)/2:]).Hash() 33 return merkle.SimpleHashFromTwoHashes(left, right) 34 } 35 } 36 37 // Index returns the index of this transaction in the list, or -1 if not found 38 func (txs Txs) Index(tx Tx) int { 39 for i := range txs { 40 if bytes.Equal(txs[i], tx) { 41 return i 42 } 43 } 44 return -1 45 } 46 47 // Index returns the index of this transaction hash in the list, or -1 if not found 48 func (txs Txs) IndexByHash(hash []byte) int { 49 for i := range txs { 50 if bytes.Equal(txs[i].Hash(), hash) { 51 return i 52 } 53 } 54 return -1 55 } 56 57 // Proof returns a simple merkle proof for this node. 58 // 59 // Panics if i < 0 or i >= len(txs) 60 // 61 // TODO: optimize this! 62 func (txs Txs) Proof(i int) TxProof { 63 l := len(txs) 64 hashables := make([]merkle.Hashable, l) 65 for i := 0; i < l; i++ { 66 hashables[i] = txs[i] 67 } 68 root, proofs := merkle.SimpleProofsFromHashables(hashables) 69 70 return TxProof{ 71 Index: i, 72 Total: l, 73 RootHash: root, 74 Data: txs[i], 75 Proof: *proofs[i], 76 } 77 } 78 79 type TxProof struct { 80 Index, Total int 81 RootHash []byte 82 Data Tx 83 Proof merkle.SimpleProof 84 } 85 86 func (tp TxProof) LeafHash() []byte { 87 return tp.Data.Hash() 88 } 89 90 // Validate returns nil if it matches the dataHash, and is internally consistent 91 // otherwise, returns a sensible error 92 func (tp TxProof) Validate(dataHash []byte) error { 93 if !bytes.Equal(dataHash, tp.RootHash) { 94 return errors.New("Proof matches different data hash") 95 } 96 97 valid := tp.Proof.Verify(tp.Index, tp.Total, tp.LeafHash(), tp.RootHash) 98 if !valid { 99 return errors.New("Proof is not internally consistent") 100 } 101 return nil 102 }