gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/types/tx.go (about)

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