2020-08-19 11:46:20 +00:00
package transactions
import (
"context"
"fmt"
2020-08-29 21:28:09 +00:00
"time"
2020-08-19 11:46:20 +00:00
"github.com/holiman/uint256"
2021-07-29 11:53:13 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/common"
2022-09-17 11:53:27 +00:00
"github.com/ledgerwatch/erigon/consensus/ethash"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/rpc"
2022-10-25 02:58:25 +00:00
ethapi2 "github.com/ledgerwatch/erigon/turbo/adapter/ethapi"
2022-06-12 11:44:01 +00:00
"github.com/ledgerwatch/erigon/turbo/services"
2021-07-29 10:23:23 +00:00
"github.com/ledgerwatch/log/v3"
2020-08-19 11:46:20 +00:00
)
2022-02-23 23:42:14 +00:00
func DoCall (
ctx context . Context ,
2022-10-25 02:58:25 +00:00
args ethapi2 . CallArgs ,
2022-02-23 23:42:14 +00:00
tx kv . Tx , blockNrOrHash rpc . BlockNumberOrHash ,
2022-10-25 02:58:25 +00:00
block * types . Block , overrides * ethapi2 . StateOverrides ,
2022-02-23 23:42:14 +00:00
gasCap uint64 ,
chainConfig * params . ChainConfig ,
2022-09-05 14:31:00 +00:00
stateReader state . StateReader ,
2022-09-17 06:25:27 +00:00
headerReader services . HeaderReader , callTimeout time . Duration ,
2022-02-23 23:42:14 +00:00
) ( * core . ExecutionResult , error ) {
2020-08-19 11:46:20 +00:00
// todo: Pending state is only known by the miner
/ *
if blockNrOrHash . BlockNumber != nil && * blockNrOrHash . BlockNumber == rpc . PendingBlockNumber {
block , state , _ := b . eth . miner . Pending ( )
return state , block . Header ( ) , nil
}
* /
2020-10-04 08:01:06 +00:00
state := state . New ( stateReader )
2020-08-19 11:46:20 +00:00
2021-10-12 05:04:04 +00:00
header := block . Header ( )
2020-08-19 11:46:20 +00:00
// Override the fields of specified contracts before execution.
if overrides != nil {
2022-03-01 15:40:24 +00:00
if err := overrides . Override ( state ) ; err != nil {
return nil , err
2020-08-19 11:46:20 +00:00
}
2022-03-01 15:40:24 +00:00
2020-08-19 11:46:20 +00:00
}
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
var cancel context . CancelFunc
if callTimeout > 0 {
ctx , cancel = context . WithTimeout ( ctx , callTimeout )
} else {
ctx , cancel = context . WithCancel ( ctx )
}
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel ( )
// Get a new instance of the EVM.
2021-07-11 04:05:56 +00:00
var baseFee * uint256 . Int
if header != nil && header . BaseFee != nil {
var overflow bool
baseFee , overflow = uint256 . FromBig ( header . BaseFee )
if overflow {
return nil , fmt . Errorf ( "header.BaseFee uint256 overflow" )
}
}
2021-07-17 02:09:56 +00:00
msg , err := args . ToMessage ( gasCap , baseFee )
2021-07-11 04:05:56 +00:00
if err != nil {
return nil , err
}
2022-09-01 18:49:29 +00:00
blockCtx , txCtx := GetEvmContext ( msg , header , blockNrOrHash . RequireCanonical , tx , headerReader )
2020-08-19 11:46:20 +00:00
2021-07-11 04:05:56 +00:00
evm := vm . NewEVM ( blockCtx , txCtx , state , chainConfig , vm . Config { NoBaseFee : true } )
2020-08-19 11:46:20 +00:00
// Wait for the context to be done and cancel the evm. Even if the
// EVM has finished, cancelling may be done (repeatedly)
go func ( ) {
<- ctx . Done ( )
evm . Cancel ( )
} ( )
gp := new ( core . GasPool ) . AddGas ( msg . Gas ( ) )
2021-02-12 16:47:32 +00:00
result , err := core . ApplyMessage ( evm , msg , gp , true /* refunds */ , false /* gasBailout */ )
2020-08-19 11:46:20 +00:00
if err != nil {
return nil , err
}
// If the timer caused an abort, return an appropriate error message
if evm . Cancelled ( ) {
return nil , fmt . Errorf ( "execution aborted (timeout = %v)" , callTimeout )
}
return result , nil
}
2022-09-01 18:49:29 +00:00
func GetEvmContext ( msg core . Message , header * types . Header , requireCanonical bool , tx kv . Tx , headerReader services . HeaderReader ) ( vm . BlockContext , vm . TxContext ) {
2021-07-08 17:04:31 +00:00
var baseFee uint256 . Int
2022-10-21 10:43:44 +00:00
if header . BaseFee != nil {
2021-07-08 17:04:31 +00:00
overflow := baseFee . SetFromBig ( header . BaseFee )
if overflow {
panic ( fmt . Errorf ( "header.BaseFee higher than 2^256-1" ) )
}
}
2022-09-17 11:53:27 +00:00
return core . NewEVMBlockContext ( header , getHashGetter ( requireCanonical , tx , headerReader ) , ethash . NewFaker ( ) /* TODO Discover correcrt engine type */ , nil /* author */ ) ,
2021-03-14 18:52:15 +00:00
vm . TxContext {
Origin : msg . From ( ) ,
GasPrice : msg . GasPrice ( ) . ToBig ( ) ,
}
2020-08-19 11:46:20 +00:00
}
2022-06-12 11:44:01 +00:00
func getHashGetter ( requireCanonical bool , tx kv . Tx , headerReader services . HeaderReader ) func ( uint64 ) common . Hash {
2020-08-19 11:46:20 +00:00
return func ( n uint64 ) common . Hash {
2022-06-12 11:44:01 +00:00
h , err := headerReader . HeaderByNumber ( context . Background ( ) , tx , n )
2020-08-19 11:46:20 +00:00
if err != nil {
2022-06-12 11:44:01 +00:00
log . Error ( "Can't get block hash by number" , "number" , n , "only-canonical" , requireCanonical )
return common . Hash { }
2020-08-19 11:46:20 +00:00
}
2022-06-12 11:44:01 +00:00
return h . Hash ( )
2020-08-19 11:46:20 +00:00
}
}