github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/types/call.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	gethCommon "github.com/onflow/go-ethereum/common"
     8  	gethCore "github.com/onflow/go-ethereum/core"
     9  	gethTypes "github.com/onflow/go-ethereum/core/types"
    10  	gethParams "github.com/onflow/go-ethereum/params"
    11  	"github.com/onflow/go-ethereum/rlp"
    12  )
    13  
    14  const (
    15  	// tx type 255 is used for direct calls from COAs
    16  	DirectCallTxType = byte(255)
    17  
    18  	UnknownCallSubType  = byte(0)
    19  	DepositCallSubType  = byte(1)
    20  	WithdrawCallSubType = byte(2)
    21  	TransferCallSubType = byte(3)
    22  	DeployCallSubType   = byte(4)
    23  	ContractCallSubType = byte(5)
    24  
    25  	// Note that these gas values might need to change if we
    26  	// change the transaction (e.g. add accesslist),
    27  	// then it has to be updated to use Intrinsic function
    28  	// to calculate the minimum gas needed to run the transaction.
    29  	IntrinsicFeeForTokenTransfer = gethParams.TxGas
    30  
    31  	// 21_000 is the minimum for a transaction + max gas allowed for receive/fallback methods
    32  	DefaultGasLimitForTokenTransfer = IntrinsicFeeForTokenTransfer + 2_300
    33  
    34  	// the value is set to the gas limit for transfer to facilitate transfers
    35  	// to smart contract addresses.
    36  	DepositCallGasLimit  = DefaultGasLimitForTokenTransfer
    37  	WithdrawCallGasLimit = DefaultGasLimitForTokenTransfer
    38  )
    39  
    40  // DirectCall captures all the data related to a direct call to evm
    41  // direct calls are similar to transactions but they don't have
    42  // signatures and don't need sequence number checks
    43  // Note that eventhough we don't check the nonce, it impacts
    44  // hash calculation and also impacts the address of resulting contract
    45  // when deployed through direct calls.
    46  // Users don't have the worry about the nonce, handler sets
    47  // it to the right value.
    48  type DirectCall struct {
    49  	Type     byte
    50  	SubType  byte
    51  	From     Address
    52  	To       Address
    53  	Data     []byte
    54  	Value    *big.Int
    55  	GasLimit uint64
    56  	Nonce    uint64
    57  }
    58  
    59  // DirectCallFromEncoded constructs a DirectCall from encoded data
    60  func DirectCallFromEncoded(encoded []byte) (*DirectCall, error) {
    61  	if encoded[0] != DirectCallTxType {
    62  		return nil, fmt.Errorf("tx type mismatch")
    63  	}
    64  	dc := &DirectCall{}
    65  	return dc, rlp.DecodeBytes(encoded[1:], dc)
    66  }
    67  
    68  // Encode encodes the direct call it also adds the type
    69  // as the very first byte, similar to how evm encodes types.
    70  func (dc *DirectCall) Encode() ([]byte, error) {
    71  	encoded, err := rlp.EncodeToBytes(dc)
    72  	return append([]byte{dc.Type}, encoded...), err
    73  }
    74  
    75  // Hash computes the hash of a direct call
    76  func (dc *DirectCall) Hash() (gethCommon.Hash, error) {
    77  	// we use geth transaction hash calculation since direct call hash is included in the
    78  	// block transaction hashes, and thus observed as any other transaction
    79  	return dc.Transaction().Hash(), nil
    80  }
    81  
    82  // Message constructs a core.Message from the direct call
    83  func (dc *DirectCall) Message() *gethCore.Message {
    84  	return &gethCore.Message{
    85  		From:      dc.From.ToCommon(),
    86  		To:        dc.to(),
    87  		Value:     dc.Value,
    88  		Data:      dc.Data,
    89  		Nonce:     dc.Nonce,
    90  		GasLimit:  dc.GasLimit,
    91  		GasPrice:  big.NewInt(0), // price is set to zero fo direct calls
    92  		GasTipCap: big.NewInt(0), // also known as maxPriorityFeePerGas (in GWei)
    93  		GasFeeCap: big.NewInt(0), // also known as maxFeePerGas (in GWei)
    94  		// AccessList:        tx.AccessList(), // TODO revisit this value, the cost matter but performance might
    95  		SkipAccountChecks: true, // this would let us not set the nonce
    96  	}
    97  }
    98  
    99  // Transaction constructs a geth.Transaction from the direct call
   100  func (dc *DirectCall) Transaction() *gethTypes.Transaction {
   101  	return gethTypes.NewTx(&gethTypes.LegacyTx{
   102  		GasPrice: big.NewInt(0),
   103  		Gas:      dc.GasLimit,
   104  		To:       dc.to(),
   105  		Value:    dc.Value,
   106  		Data:     dc.Data,
   107  		Nonce:    dc.Nonce,
   108  	})
   109  }
   110  
   111  // EmptyToField returns true if `to` field contains an empty address
   112  func (dc *DirectCall) EmptyToField() bool {
   113  	return dc.To == EmptyAddress
   114  }
   115  
   116  func (dc *DirectCall) to() *gethCommon.Address {
   117  	if !dc.EmptyToField() {
   118  		ct := dc.To.ToCommon()
   119  		return &ct
   120  	}
   121  	return nil
   122  }
   123  
   124  func NewDepositCall(
   125  	bridge Address,
   126  	address Address,
   127  	amount *big.Int,
   128  	nonce uint64,
   129  ) *DirectCall {
   130  	return &DirectCall{
   131  		Type:     DirectCallTxType,
   132  		SubType:  DepositCallSubType,
   133  		From:     bridge,
   134  		To:       address,
   135  		Data:     nil,
   136  		Value:    amount,
   137  		GasLimit: DepositCallGasLimit,
   138  		Nonce:    nonce,
   139  	}
   140  }
   141  
   142  func NewWithdrawCall(
   143  	bridge Address,
   144  	address Address,
   145  	amount *big.Int,
   146  	nonce uint64,
   147  ) *DirectCall {
   148  	return &DirectCall{
   149  		Type:     DirectCallTxType,
   150  		SubType:  WithdrawCallSubType,
   151  		From:     address,
   152  		To:       bridge,
   153  		Data:     nil,
   154  		Value:    amount,
   155  		GasLimit: WithdrawCallGasLimit,
   156  		Nonce:    nonce,
   157  	}
   158  }
   159  
   160  func NewTransferCall(
   161  	from Address,
   162  	to Address,
   163  	amount *big.Int,
   164  	nonce uint64,
   165  ) *DirectCall {
   166  	return &DirectCall{
   167  		Type:     DirectCallTxType,
   168  		SubType:  TransferCallSubType,
   169  		From:     from,
   170  		To:       to,
   171  		Data:     nil,
   172  		Value:    amount,
   173  		GasLimit: DefaultGasLimitForTokenTransfer,
   174  		Nonce:    nonce,
   175  	}
   176  }
   177  
   178  func NewDeployCall(
   179  	caller Address,
   180  	code Code,
   181  	gasLimit uint64,
   182  	value *big.Int,
   183  	nonce uint64,
   184  ) *DirectCall {
   185  	return &DirectCall{
   186  		Type:     DirectCallTxType,
   187  		SubType:  DeployCallSubType,
   188  		From:     caller,
   189  		To:       EmptyAddress,
   190  		Data:     code,
   191  		Value:    value,
   192  		GasLimit: gasLimit,
   193  		Nonce:    nonce,
   194  	}
   195  }
   196  
   197  // this subtype should only be used internally for
   198  // deploying contracts at given addresses (e.g. COA account init setup)
   199  // should not be used for other means.
   200  func NewDeployCallWithTargetAddress(
   201  	caller Address,
   202  	to Address,
   203  	code Code,
   204  	gasLimit uint64,
   205  	value *big.Int,
   206  	nonce uint64,
   207  ) *DirectCall {
   208  	return &DirectCall{
   209  		Type:     DirectCallTxType,
   210  		SubType:  DeployCallSubType,
   211  		From:     caller,
   212  		To:       to,
   213  		Data:     code,
   214  		Value:    value,
   215  		GasLimit: gasLimit,
   216  		Nonce:    nonce,
   217  	}
   218  }
   219  
   220  func NewContractCall(
   221  	caller Address,
   222  	to Address,
   223  	data Data,
   224  	gasLimit uint64,
   225  	value *big.Int,
   226  	nonce uint64,
   227  ) *DirectCall {
   228  	return &DirectCall{
   229  		Type:     DirectCallTxType,
   230  		SubType:  ContractCallSubType,
   231  		From:     caller,
   232  		To:       to,
   233  		Data:     data,
   234  		Value:    value,
   235  		GasLimit: gasLimit,
   236  		Nonce:    nonce,
   237  	}
   238  }
   239  
   240  type GasLimit uint64
   241  
   242  type Code []byte
   243  
   244  type Data []byte
   245  
   246  // AsBigInt process the data and return it as a big integer
   247  func (d Data) AsBigInt() *big.Int {
   248  	return new(big.Int).SetBytes(d)
   249  }