github.com/vipernet-xyz/tm@v0.34.24/types/tx.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/vipernet-xyz/tm/crypto/merkle"
    10  	"github.com/vipernet-xyz/tm/crypto/tmhash"
    11  	tmbytes "github.com/vipernet-xyz/tm/libs/bytes"
    12  	tmproto "github.com/vipernet-xyz/tm/proto/tendermint/types"
    13  )
    14  
    15  // TxKeySize is the size of the transaction key index
    16  const TxKeySize = sha256.Size
    17  
    18  type (
    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  	Tx []byte
    23  
    24  	// TxKey is the fixed length array key used as an index.
    25  	TxKey [TxKeySize]byte
    26  )
    27  
    28  // Hash computes the TMHASH hash of the wire encoded transaction.
    29  func (tx Tx) Hash() []byte {
    30  	return tmhash.Sum(tx)
    31  }
    32  
    33  func (tx Tx) Key() TxKey {
    34  	return sha256.Sum256(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() []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()
    53  	}
    54  	return merkle.HashFromByteSlices(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) int {
    69  	for i := range txs {
    70  		if bytes.Equal(txs[i].Hash(), 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) TxProof {
    81  	l := len(txs)
    82  	bzs := make([][]byte, l)
    83  	for i := 0; i < l; i++ {
    84  		bzs[i] = txs[i].Hash()
    85  	}
    86  	root, proofs := merkle.ProofsFromByteSlices(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.Proof     `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() []byte {
   104  	return tp.Data.Hash()
   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) 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())
   120  	if valid != nil {
   121  		return errors.New("proof is not internally consistent")
   122  	}
   123  	return nil
   124  }
   125  
   126  func (tp TxProof) ToProto() tmproto.TxProof {
   127  
   128  	pbProof := tp.Proof.ToProto()
   129  
   130  	pbtp := tmproto.TxProof{
   131  		RootHash: tp.RootHash,
   132  		Data:     tp.Data,
   133  		Proof:    pbProof,
   134  	}
   135  
   136  	return pbtp
   137  }
   138  func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) {
   139  
   140  	pbProof, err := merkle.ProofFromProto(pb.Proof)
   141  	if err != nil {
   142  		return TxProof{}, err
   143  	}
   144  
   145  	pbtp := TxProof{
   146  		RootHash: pb.RootHash,
   147  		Data:     pb.Data,
   148  		Proof:    *pbProof,
   149  	}
   150  
   151  	return pbtp, nil
   152  }
   153  
   154  // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size.
   155  // https://developers.google.com/protocol-buffers/docs/encoding
   156  func ComputeProtoSizeForTxs(txs []Tx) int64 {
   157  	data := Data{Txs: txs}
   158  	pdData := data.ToProto()
   159  	return int64(pdData.Size())
   160  }