github.com/okex/exchain@v1.8.0/libs/tendermint/types/tx.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	ethcmn "github.com/ethereum/go-ethereum/common"
     9  
    10  	"github.com/tendermint/go-amino"
    11  
    12  	abci "github.com/okex/exchain/libs/tendermint/abci/types"
    13  	"github.com/okex/exchain/libs/tendermint/crypto/etherhash"
    14  	"github.com/okex/exchain/libs/tendermint/crypto/merkle"
    15  	"github.com/okex/exchain/libs/tendermint/crypto/tmhash"
    16  	tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes"
    17  )
    18  
    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  type Tx []byte
    23  
    24  func Bytes2Hash(txBytes []byte, height int64) string {
    25  	txHash := Tx(txBytes).Hash(height)
    26  	return ethcmn.BytesToHash(txHash).String()
    27  }
    28  
    29  // Hash computes the TMHASH hash of the wire encoded transaction.
    30  func (tx Tx) Hash(height int64) []byte {
    31  	if HigherThanVenus(height) {
    32  		return etherhash.Sum(tx)
    33  	}
    34  	return tmhash.Sum(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(height int64) []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(height)
    53  	}
    54  	return merkle.SimpleHashFromByteSlices(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, height int64) int {
    69  	for i := range txs {
    70  		if bytes.Equal(txs[i].Hash(height), 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, height int64) TxProof {
    81  	l := len(txs)
    82  	bzs := make([][]byte, l)
    83  	for i := 0; i < l; i++ {
    84  		bzs[i] = txs[i].Hash(height)
    85  	}
    86  	root, proofs := merkle.SimpleProofsFromByteSlices(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.SimpleProof `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(height int64) []byte {
   104  	return tp.Data.Hash(height)
   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, height int64) 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(height))
   120  	if valid != nil {
   121  		return errors.New("proof is not internally consistent")
   122  	}
   123  	return nil
   124  }
   125  
   126  // TxResult contains results of executing the transaction.
   127  //
   128  // One usage is indexing transaction results.
   129  type TxResult struct {
   130  	Height int64                  `json:"height"`
   131  	Index  uint32                 `json:"index"`
   132  	Tx     Tx                     `json:"tx"`
   133  	Result abci.ResponseDeliverTx `json:"result"`
   134  }
   135  
   136  func (txResult *TxResult) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error {
   137  	var dataLen uint64 = 0
   138  	var subData []byte
   139  
   140  	for {
   141  		data = data[dataLen:]
   142  
   143  		if len(data) == 0 {
   144  			break
   145  		}
   146  
   147  		pos, aminoType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0])
   148  		if err != nil {
   149  			return err
   150  		}
   151  		data = data[1:]
   152  
   153  		if aminoType == amino.Typ3_ByteLength {
   154  			var n int
   155  			dataLen, n, err = amino.DecodeUvarint(data)
   156  			if err != nil {
   157  				return err
   158  			}
   159  
   160  			data = data[n:]
   161  			if len(data) < int(dataLen) {
   162  				return fmt.Errorf("invalid data length: %d", dataLen)
   163  			}
   164  			subData = data[:dataLen]
   165  		}
   166  
   167  		switch pos {
   168  		case 1:
   169  			var n int
   170  			var uvint uint64
   171  			uvint, n, err = amino.DecodeUvarint(data)
   172  			if err != nil {
   173  				return err
   174  			}
   175  			txResult.Height = int64(uvint)
   176  			dataLen = uint64(n)
   177  		case 2:
   178  			var n int
   179  			var uvint uint64
   180  			uvint, n, err = amino.DecodeUvarint(data)
   181  			if err != nil {
   182  				return err
   183  			}
   184  			txResult.Index = uint32(uvint)
   185  			dataLen = uint64(n)
   186  		case 3:
   187  			txResult.Tx = make(Tx, dataLen)
   188  			copy(txResult.Tx, subData)
   189  		case 4:
   190  			err = txResult.Result.UnmarshalFromAmino(cdc, subData)
   191  			if err != nil {
   192  				return err
   193  			}
   194  		default:
   195  			return fmt.Errorf("unexpect feild num %d", pos)
   196  		}
   197  	}
   198  	return nil
   199  }
   200  
   201  // ComputeAminoOverhead calculates the overhead for amino encoding a transaction.
   202  // The overhead consists of varint encoding the field number and the wire type
   203  // (= length-delimited = 2), and another varint encoding the length of the
   204  // transaction.
   205  // The field number can be the field number of the particular transaction, or
   206  // the field number of the parenting struct that contains the transactions []Tx
   207  // as a field (this field number is repeated for each contained Tx).
   208  // If some []Tx are encoded directly (without a parenting struct), the default
   209  // fieldNum is also 1 (see BinFieldNum in amino.MarshalBinaryBare).
   210  func ComputeAminoOverhead(tx Tx, fieldNum int) int64 {
   211  	fnum := uint64(fieldNum)
   212  	typ3AndFieldNum := (fnum << 3) | uint64(amino.Typ3_ByteLength)
   213  	return int64(amino.UvarintSize(typ3AndFieldNum)) + int64(amino.UvarintSize(uint64(len(tx))))
   214  }
   215  
   216  type WrappedMempoolTx struct {
   217  	Height      int64  `json:"height"`
   218  	GasWanted   int64  `json:"gas_wanted"`
   219  	GasLimit    int64  `json:"gas_limit"`
   220  	Tx          Tx     `json:"tx"`
   221  	NodeKey     []byte `json:"node_key"`
   222  	Signature   []byte `json:"signature"`
   223  	From        string `json:"from"`
   224  	SenderNonce uint64 `json:"sender_nonce"`
   225  	Outdated    uint32 `json:"outdated"`
   226  	IsSim       uint32 `json:"is_sim"`
   227  	IsWrapCMTx  bool   `json:"is_wrap_cm_tx"`
   228  	WrapCMNonce uint64 `json:"wrap_cm_nonce"`
   229  }