github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/types/tx.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	amino "github.com/tendermint/go-amino"
     9  
    10  	abci "github.com/franono/tendermint/abci/types"
    11  	"github.com/franono/tendermint/crypto/merkle"
    12  	"github.com/franono/tendermint/crypto/tmhash"
    13  	tmbytes "github.com/franono/tendermint/libs/bytes"
    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 tmbytes.HexBytes   `json:"root_hash"`
    87  	Data     Tx                 `json:"data"`
    88  	Proof    merkle.SimpleProof `json:"proof"`
    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 := (fnum << 3) | uint64(amino.Typ3_ByteLength)
   137  	return int64(amino.UvarintSize(typ3AndFieldNum)) + int64(amino.UvarintSize(uint64(len(tx))))
   138  }