gitlab.com/flarenetwork/coreth@v0.1.1/plugin/evm/tx.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package evm
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"math/big"
    11  	"sort"
    12  
    13  	"github.com/ethereum/go-ethereum/common"
    14  
    15  	"gitlab.com/flarenetwork/coreth/core/state"
    16  	"gitlab.com/flarenetwork/coreth/params"
    17  
    18  	"github.com/ava-labs/avalanchego/codec"
    19  	"github.com/ava-labs/avalanchego/database"
    20  	"github.com/ava-labs/avalanchego/ids"
    21  	"github.com/ava-labs/avalanchego/snow"
    22  	"github.com/ava-labs/avalanchego/utils"
    23  	"github.com/ava-labs/avalanchego/utils/crypto"
    24  	"github.com/ava-labs/avalanchego/utils/hashing"
    25  	"github.com/ava-labs/avalanchego/utils/wrappers"
    26  	"github.com/ava-labs/avalanchego/vms/components/verify"
    27  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    28  )
    29  
    30  var (
    31  	errWrongBlockchainID = errors.New("wrong blockchain ID provided")
    32  	errWrongNetworkID    = errors.New("tx was issued with a different network ID")
    33  	errNilTx             = errors.New("tx is nil")
    34  	errNoValueOutput     = errors.New("output has no value")
    35  	errNoValueInput      = errors.New("input has no value")
    36  	errNilOutput         = errors.New("nil output")
    37  	errNilInput          = errors.New("nil input")
    38  	errEmptyAssetID      = errors.New("empty asset ID is not valid")
    39  	errNilBaseFee        = errors.New("cannot calculate dynamic fee with nil baseFee")
    40  	errFeeOverflow       = errors.New("overflow occurred while calculating the fee")
    41  )
    42  
    43  // Constants for calculating the gas consumed by atomic transactions
    44  var (
    45  	TxBytesGas   uint64 = 1
    46  	EVMOutputGas uint64 = (common.AddressLength + wrappers.LongLen + hashing.HashLen) * TxBytesGas
    47  	EVMInputGas  uint64 = (common.AddressLength+wrappers.LongLen+hashing.HashLen+wrappers.LongLen)*TxBytesGas + secp256k1fx.CostPerSignature
    48  )
    49  
    50  // EVMOutput defines an output that is added to the EVM state created by import transactions
    51  type EVMOutput struct {
    52  	Address common.Address `serialize:"true" json:"address"`
    53  	Amount  uint64         `serialize:"true" json:"amount"`
    54  	AssetID ids.ID         `serialize:"true" json:"assetID"`
    55  }
    56  
    57  // EVMInput defines an input created from the EVM state to fund export transactions
    58  type EVMInput struct {
    59  	Address common.Address `serialize:"true" json:"address"`
    60  	Amount  uint64         `serialize:"true" json:"amount"`
    61  	AssetID ids.ID         `serialize:"true" json:"assetID"`
    62  	Nonce   uint64         `serialize:"true" json:"nonce"`
    63  }
    64  
    65  // Verify ...
    66  func (out *EVMOutput) Verify() error {
    67  	switch {
    68  	case out == nil:
    69  		return errNilOutput
    70  	case out.Amount == 0:
    71  		return errNoValueOutput
    72  	case out.AssetID == ids.Empty:
    73  		return errEmptyAssetID
    74  	}
    75  	return nil
    76  }
    77  
    78  // Verify ...
    79  func (in *EVMInput) Verify() error {
    80  	switch {
    81  	case in == nil:
    82  		return errNilInput
    83  	case in.Amount == 0:
    84  		return errNoValueInput
    85  	case in.AssetID == ids.Empty:
    86  		return errEmptyAssetID
    87  	}
    88  	return nil
    89  }
    90  
    91  // UnsignedTx is an unsigned transaction
    92  type UnsignedTx interface {
    93  	Initialize(unsignedBytes, signedBytes []byte)
    94  	ID() ids.ID
    95  	Cost() (uint64, error)
    96  	UnsignedBytes() []byte
    97  	Bytes() []byte
    98  }
    99  
   100  // UnsignedAtomicTx is an unsigned operation that can be atomically accepted
   101  type UnsignedAtomicTx interface {
   102  	UnsignedTx
   103  
   104  	// UTXOs this tx consumes
   105  	InputUTXOs() ids.Set
   106  	// Attempts to verify this transaction with the provided state.
   107  	SemanticVerify(vm *VM, stx *Tx, parent *Block, baseFee *big.Int, rules params.Rules) error
   108  
   109  	// Accept this transaction with the additionally provided state transitions.
   110  	Accept(ctx *snow.Context, batch database.Batch) error
   111  
   112  	EVMStateTransfer(ctx *snow.Context, state *state.StateDB) error
   113  }
   114  
   115  // Tx is a signed transaction
   116  type Tx struct {
   117  	// The body of this transaction
   118  	UnsignedAtomicTx `serialize:"true" json:"unsignedTx"`
   119  
   120  	// The credentials of this transaction
   121  	Creds []verify.Verifiable `serialize:"true" json:"credentials"`
   122  }
   123  
   124  // Sign this transaction with the provided signers
   125  func (tx *Tx) Sign(c codec.Manager, signers [][]*crypto.PrivateKeySECP256K1R) error {
   126  	unsignedBytes, err := c.Marshal(codecVersion, &tx.UnsignedAtomicTx)
   127  	if err != nil {
   128  		return fmt.Errorf("couldn't marshal UnsignedAtomicTx: %w", err)
   129  	}
   130  
   131  	// Attach credentials
   132  	hash := hashing.ComputeHash256(unsignedBytes)
   133  	for _, keys := range signers {
   134  		cred := &secp256k1fx.Credential{
   135  			Sigs: make([][crypto.SECP256K1RSigLen]byte, len(keys)),
   136  		}
   137  		for i, key := range keys {
   138  			sig, err := key.SignHash(hash) // Sign hash
   139  			if err != nil {
   140  				return fmt.Errorf("problem generating credential: %w", err)
   141  			}
   142  			copy(cred.Sigs[i][:], sig)
   143  		}
   144  		tx.Creds = append(tx.Creds, cred) // Attach credential
   145  	}
   146  
   147  	signedBytes, err := c.Marshal(codecVersion, tx)
   148  	if err != nil {
   149  		return fmt.Errorf("couldn't marshal Tx: %w", err)
   150  	}
   151  	tx.Initialize(unsignedBytes, signedBytes)
   152  	return nil
   153  }
   154  
   155  // innerSortInputsAndSigners implements sort.Interface for EVMInput
   156  type innerSortInputsAndSigners struct {
   157  	inputs  []EVMInput
   158  	signers [][]*crypto.PrivateKeySECP256K1R
   159  }
   160  
   161  func (ins *innerSortInputsAndSigners) Less(i, j int) bool {
   162  	addrComp := bytes.Compare(ins.inputs[i].Address.Bytes(), ins.inputs[j].Address.Bytes())
   163  	if addrComp != 0 {
   164  		return addrComp < 0
   165  	}
   166  	return bytes.Compare(ins.inputs[i].AssetID[:], ins.inputs[j].AssetID[:]) < 0
   167  }
   168  
   169  func (ins *innerSortInputsAndSigners) Len() int { return len(ins.inputs) }
   170  
   171  func (ins *innerSortInputsAndSigners) Swap(i, j int) {
   172  	ins.inputs[j], ins.inputs[i] = ins.inputs[i], ins.inputs[j]
   173  	ins.signers[j], ins.signers[i] = ins.signers[i], ins.signers[j]
   174  }
   175  
   176  // SortEVMInputsAndSigners sorts the list of EVMInputs based on the addresses and assetIDs
   177  func SortEVMInputsAndSigners(inputs []EVMInput, signers [][]*crypto.PrivateKeySECP256K1R) {
   178  	sort.Sort(&innerSortInputsAndSigners{inputs: inputs, signers: signers})
   179  }
   180  
   181  // IsSortedAndUniqueEVMInputs returns true if the EVM Inputs are sorted and unique
   182  // based on the account addresses
   183  func IsSortedAndUniqueEVMInputs(inputs []EVMInput) bool {
   184  	return utils.IsSortedAndUnique(&innerSortInputsAndSigners{inputs: inputs})
   185  }
   186  
   187  // innerSortEVMOutputs implements sort.Interface for EVMOutput
   188  type innerSortEVMOutputs struct {
   189  	outputs []EVMOutput
   190  }
   191  
   192  func (outs *innerSortEVMOutputs) Less(i, j int) bool {
   193  	addrComp := bytes.Compare(outs.outputs[i].Address.Bytes(), outs.outputs[j].Address.Bytes())
   194  	if addrComp != 0 {
   195  		return addrComp < 0
   196  	}
   197  	return bytes.Compare(outs.outputs[i].AssetID[:], outs.outputs[j].AssetID[:]) < 0
   198  }
   199  
   200  func (outs *innerSortEVMOutputs) Len() int { return len(outs.outputs) }
   201  
   202  func (outs *innerSortEVMOutputs) Swap(i, j int) {
   203  	outs.outputs[j], outs.outputs[i] = outs.outputs[i], outs.outputs[j]
   204  }
   205  
   206  // SortEVMOutputs sorts the list of EVMOutputs based on the addresses and assetIDs
   207  // of the outputs
   208  func SortEVMOutputs(outputs []EVMOutput) {
   209  	sort.Sort(&innerSortEVMOutputs{outputs: outputs})
   210  }
   211  
   212  // IsSortedEVMOutputs returns true if the EVMOutputs are sorted
   213  // based on the account addresses and assetIDs
   214  func IsSortedEVMOutputs(outputs []EVMOutput) bool {
   215  	return sort.IsSorted(&innerSortEVMOutputs{outputs: outputs})
   216  }
   217  
   218  // IsSortedAndUniqueEVMOutputs returns true if the EVMOutputs are sorted
   219  // and unique based on the account addresses and assetIDs
   220  func IsSortedAndUniqueEVMOutputs(outputs []EVMOutput) bool {
   221  	return utils.IsSortedAndUnique(&innerSortEVMOutputs{outputs: outputs})
   222  }
   223  
   224  // calculates the amount of AVAX that must be burned by an atomic transaction
   225  // that consumes [cost] at [baseFee].
   226  func calculateDynamicFee(cost uint64, baseFee *big.Int) (uint64, error) {
   227  	if baseFee == nil {
   228  		return 0, errNilBaseFee
   229  	}
   230  	bigCost := new(big.Int).SetUint64(cost)
   231  	fee := new(big.Int).Mul(bigCost, baseFee)
   232  	feeToRoundUp := new(big.Int).Add(fee, x2cRateMinus1)
   233  	feeInNAVAX := new(big.Int).Div(feeToRoundUp, x2cRate)
   234  	if !feeInNAVAX.IsUint64() {
   235  		// the fee is more than can fit in a uint64
   236  		return 0, errFeeOverflow
   237  	}
   238  	return feeInNAVAX.Uint64(), nil
   239  }
   240  
   241  func calcBytesCost(len int) uint64 {
   242  	return uint64(len) * TxBytesGas
   243  }