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  }