Patch for concurrent iterator & others (onto v1.11.6) #386
@ -644,20 +644,33 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||||||
if call.Value == nil {
|
if call.Value == nil {
|
||||||
call.Value = new(big.Int)
|
call.Value = new(big.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set infinite balance to the fake caller account.
|
// Set infinite balance to the fake caller account.
|
||||||
from := stateDB.GetOrNewStateObject(call.From)
|
from := stateDB.GetOrNewStateObject(call.From)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
// Execute the call.
|
|
||||||
msg := callMsg{call}
|
|
||||||
|
|
||||||
txContext := core.NewEVMTxContext(msg)
|
// Execute the call.
|
||||||
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
msg := &core.Message{
|
||||||
|
From: call.From,
|
||||||
|
To: call.To,
|
||||||
|
Value: call.Value,
|
||||||
|
GasLimit: call.Gas,
|
||||||
|
GasPrice: call.GasPrice,
|
||||||
|
GasFeeCap: call.GasFeeCap,
|
||||||
|
GasTipCap: call.GasTipCap,
|
||||||
|
Data: call.Data,
|
||||||
|
AccessList: call.AccessList,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
|
txContext := core.NewEVMTxContext(msg)
|
||||||
|
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
||||||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
return core.ApplyMessage(vmEnv, msg, gasPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
// SendTransaction updates the pending block to include the given transaction.
|
||||||
@ -821,23 +834,6 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain {
|
|||||||
return b.blockchain
|
return b.blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
// callMsg implements core.Message to allow passing it as a transaction simulator.
|
|
||||||
type callMsg struct {
|
|
||||||
ethereum.CallMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
|
||||||
func (m callMsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m callMsg) IsFake() bool { return true }
|
|
||||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
|
||||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
|
||||||
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
|
|
||||||
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
|
|
||||||
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
|
||||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
|
||||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
|
||||||
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
|
|
||||||
|
|
||||||
// filterBackend implements filters.Backend to support filtering for logs without
|
// filterBackend implements filters.Backend to support filtering for logs without
|
||||||
// taking bloom-bits acceleration structures into account.
|
// taking bloom-bits acceleration structures into account.
|
||||||
type filterBackend struct {
|
type filterBackend struct {
|
||||||
|
@ -163,7 +163,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
|
msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
@ -188,7 +188,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
gaspool.SetGas(prevGas)
|
gaspool.SetGas(prevGas)
|
||||||
continue
|
continue
|
||||||
@ -220,7 +220,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
receipt.GasUsed = msgResult.UsedGas
|
receipt.GasUsed = msgResult.UsedGas
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To() == nil {
|
if msg.To == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +70,10 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewEVMTxContext creates a new transaction context for a single transaction.
|
// NewEVMTxContext creates a new transaction context for a single transaction.
|
||||||
func NewEVMTxContext(msg Message) vm.TxContext {
|
func NewEVMTxContext(msg *Message) vm.TxContext {
|
||||||
return vm.TxContext{
|
return vm.TxContext{
|
||||||
Origin: msg.From(),
|
Origin: msg.From,
|
||||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
GasPrice: new(big.Int).Set(msg.GasPrice),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Convert the transaction into an executable message and pre-cache its sender
|
// Convert the transaction into an executable message and pre-cache its sender
|
||||||
msg, err := tx.AsMessage(signer, header.BaseFee)
|
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return // Also invalid block, bail out
|
return // Also invalid block, bail out
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||||||
// precacheTransaction attempts to apply a transaction to the given state database
|
// precacheTransaction attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment. The goal is not to execute
|
// and uses the input parameters for its environment. The goal is not to execute
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
||||||
// Update the evm with the new transaction context.
|
// Update the evm with the new transaction context.
|
||||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||||
// Add addresses to access list if applicable
|
// Add addresses to access list if applicable
|
||||||
|
@ -74,7 +74,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||||||
return receipts, allLogs, *usedGas, nil
|
return receipts, allLogs, *usedGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||||
// Create a new context to be used in the EVM environment.
|
// Create a new context to be used in the EVM environment.
|
||||||
txContext := NewEVMTxContext(msg)
|
txContext := NewEVMTxContext(msg)
|
||||||
evm.Reset(txContext, statedb)
|
evm.Reset(txContext, statedb)
|
||||||
@ -129,7 +129,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
|||||||
receipt.GasUsed = result.UsedGas
|
receipt.GasUsed = result.UsedGas
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To() == nil {
|
if msg.To == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
|||||||
// for the transaction, gas used and an error if the transaction failed,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// indicating the block was invalid.
|
||||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -25,65 +25,9 @@ import (
|
|||||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var emptyCodeHash = crypto.Keccak256Hash(nil)
|
|
||||||
|
|
||||||
// StateTransition represents a state transition.
|
|
||||||
//
|
|
||||||
// == The State Transitioning Model
|
|
||||||
//
|
|
||||||
// A state transition is a change made when a transaction is applied to the current world
|
|
||||||
// state. The state transitioning model does all the necessary work to work out a valid new
|
|
||||||
// state root.
|
|
||||||
//
|
|
||||||
// 1. Nonce handling
|
|
||||||
// 2. Pre pay gas
|
|
||||||
// 3. Create a new state object if the recipient is nil
|
|
||||||
// 4. Value transfer
|
|
||||||
//
|
|
||||||
// == If contract creation ==
|
|
||||||
//
|
|
||||||
// 4a. Attempt to run transaction data
|
|
||||||
// 4b. If valid, use result as code for the new state object
|
|
||||||
//
|
|
||||||
// == end ==
|
|
||||||
//
|
|
||||||
// 5. Run Script section
|
|
||||||
// 6. Derive new state root
|
|
||||||
type StateTransition struct {
|
|
||||||
gp *GasPool
|
|
||||||
msg Message
|
|
||||||
gas uint64
|
|
||||||
gasPrice *big.Int
|
|
||||||
gasFeeCap *big.Int
|
|
||||||
gasTipCap *big.Int
|
|
||||||
initialGas uint64
|
|
||||||
value *big.Int
|
|
||||||
data []byte
|
|
||||||
state vm.StateDB
|
|
||||||
evm *vm.EVM
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message represents a message sent to a contract.
|
|
||||||
type Message interface {
|
|
||||||
From() common.Address
|
|
||||||
To() *common.Address
|
|
||||||
|
|
||||||
GasPrice() *big.Int
|
|
||||||
GasFeeCap() *big.Int
|
|
||||||
GasTipCap() *big.Int
|
|
||||||
Gas() uint64
|
|
||||||
Value() *big.Int
|
|
||||||
|
|
||||||
Nonce() uint64
|
|
||||||
IsFake() bool
|
|
||||||
Data() []byte
|
|
||||||
AccessList() types.AccessList
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
// message no matter the execution itself is successful or not.
|
// message no matter the execution itself is successful or not.
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
@ -178,19 +122,47 @@ func toWordSize(size uint64) uint64 {
|
|||||||
return (size + 31) / 32
|
return (size + 31) / 32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateTransition initialises and returns a new state transition object.
|
// A Message contains the data derived from a single transaction that is relevant to state
|
||||||
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
// processing.
|
||||||
return &StateTransition{
|
type Message struct {
|
||||||
gp: gp,
|
To *common.Address
|
||||||
evm: evm,
|
From common.Address
|
||||||
msg: msg,
|
Nonce uint64
|
||||||
gasPrice: msg.GasPrice(),
|
Value *big.Int
|
||||||
gasFeeCap: msg.GasFeeCap(),
|
GasLimit uint64
|
||||||
gasTipCap: msg.GasTipCap(),
|
GasPrice *big.Int
|
||||||
value: msg.Value(),
|
GasFeeCap *big.Int
|
||||||
data: msg.Data(),
|
GasTipCap *big.Int
|
||||||
state: evm.StateDB,
|
Data []byte
|
||||||
|
AccessList types.AccessList
|
||||||
|
|
||||||
|
// When SkipAccountCheckss is true, the message nonce is not checked against the
|
||||||
|
// account nonce in state. It also disables checking that the sender is an EOA.
|
||||||
|
// This field will be set to true for operations like RPC eth_call.
|
||||||
|
SkipAccountChecks bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactionToMessage converts a transaction into a Message.
|
||||||
|
func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
|
||||||
|
msg := &Message{
|
||||||
|
Nonce: tx.Nonce(),
|
||||||
|
GasLimit: tx.Gas(),
|
||||||
|
GasPrice: new(big.Int).Set(tx.GasPrice()),
|
||||||
|
GasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
||||||
|
GasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
||||||
|
To: tx.To(),
|
||||||
|
Value: tx.Value(),
|
||||||
|
Data: tx.Data(),
|
||||||
|
AccessList: tx.AccessList(),
|
||||||
|
SkipAccountChecks: false,
|
||||||
}
|
}
|
||||||
|
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
||||||
|
if baseFee != nil {
|
||||||
|
msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
msg.From, err = types.Sender(s, tx)
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyMessage computes the new state by applying the given message
|
// ApplyMessage computes the new state by applying the given message
|
||||||
@ -200,82 +172,126 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
|||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateTransition represents a state transition.
|
||||||
|
//
|
||||||
|
// == The State Transitioning Model
|
||||||
|
//
|
||||||
|
// A state transition is a change made when a transaction is applied to the current world
|
||||||
|
// state. The state transitioning model does all the necessary work to work out a valid new
|
||||||
|
// state root.
|
||||||
|
//
|
||||||
|
// 1. Nonce handling
|
||||||
|
// 2. Pre pay gas
|
||||||
|
// 3. Create a new state object if the recipient is nil
|
||||||
|
// 4. Value transfer
|
||||||
|
//
|
||||||
|
// == If contract creation ==
|
||||||
|
//
|
||||||
|
// 4a. Attempt to run transaction data
|
||||||
|
// 4b. If valid, use result as code for the new state object
|
||||||
|
//
|
||||||
|
// == end ==
|
||||||
|
//
|
||||||
|
// 5. Run Script section
|
||||||
|
// 6. Derive new state root
|
||||||
|
type StateTransition struct {
|
||||||
|
gp *GasPool
|
||||||
|
msg *Message
|
||||||
|
gasRemaining uint64
|
||||||
|
initialGas uint64
|
||||||
|
state vm.StateDB
|
||||||
|
evm *vm.EVM
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateTransition initialises and returns a new state transition object.
|
||||||
|
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
|
||||||
|
return &StateTransition{
|
||||||
|
gp: gp,
|
||||||
|
evm: evm,
|
||||||
|
msg: msg,
|
||||||
|
state: evm.StateDB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// to returns the recipient of the message.
|
// to returns the recipient of the message.
|
||||||
func (st *StateTransition) to() common.Address {
|
func (st *StateTransition) to() common.Address {
|
||||||
if st.msg == nil || st.msg.To() == nil /* contract creation */ {
|
if st.msg == nil || st.msg.To == nil /* contract creation */ {
|
||||||
return common.Address{}
|
return common.Address{}
|
||||||
}
|
}
|
||||||
return *st.msg.To()
|
return *st.msg.To
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) buyGas() error {
|
func (st *StateTransition) buyGas() error {
|
||||||
mgval := new(big.Int).SetUint64(st.msg.Gas())
|
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
mgval = mgval.Mul(mgval, st.gasPrice)
|
mgval = mgval.Mul(mgval, st.msg.GasPrice)
|
||||||
balanceCheck := mgval
|
balanceCheck := mgval
|
||||||
if st.gasFeeCap != nil {
|
if st.msg.GasFeeCap != nil {
|
||||||
balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
|
balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
|
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
|
||||||
balanceCheck.Add(balanceCheck, st.value)
|
balanceCheck.Add(balanceCheck, st.msg.Value)
|
||||||
}
|
}
|
||||||
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||||
}
|
}
|
||||||
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
|
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st.gas += st.msg.Gas()
|
st.gasRemaining += st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = st.msg.Gas()
|
st.initialGas = st.msg.GasLimit
|
||||||
st.state.SubBalance(st.msg.From(), mgval)
|
st.state.SubBalance(st.msg.From, mgval)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) preCheck() error {
|
func (st *StateTransition) preCheck() error {
|
||||||
// Only check transactions that are not fake
|
// Only check transactions that are not fake
|
||||||
if !st.msg.IsFake() {
|
msg := st.msg
|
||||||
|
if !msg.SkipAccountChecks {
|
||||||
// Make sure this transaction's nonce is correct.
|
// Make sure this transaction's nonce is correct.
|
||||||
stNonce := st.state.GetNonce(st.msg.From())
|
stNonce := st.state.GetNonce(msg.From)
|
||||||
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
|
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
||||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
|
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
|
||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
msg.From.Hex(), msgNonce, stNonce)
|
||||||
} else if stNonce > msgNonce {
|
} else if stNonce > msgNonce {
|
||||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
msg.From.Hex(), msgNonce, stNonce)
|
||||||
} else if stNonce+1 < stNonce {
|
} else if stNonce+1 < stNonce {
|
||||||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||||
st.msg.From().Hex(), stNonce)
|
msg.From.Hex(), stNonce)
|
||||||
}
|
}
|
||||||
// Make sure the sender is an EOA
|
// Make sure the sender is an EOA
|
||||||
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
codeHash := st.state.GetCodeHash(msg.From)
|
||||||
|
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||||
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
||||||
st.msg.From().Hex(), codeHash)
|
msg.From.Hex(), codeHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
||||||
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
|
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
|
||||||
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
||||||
if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
|
if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
|
||||||
if l := st.gasFeeCap.BitLen(); l > 256 {
|
if l := msg.GasFeeCap.BitLen(); l > 256 {
|
||||||
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
||||||
st.msg.From().Hex(), l)
|
msg.From.Hex(), l)
|
||||||
}
|
}
|
||||||
if l := st.gasTipCap.BitLen(); l > 256 {
|
if l := msg.GasTipCap.BitLen(); l > 256 {
|
||||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
||||||
st.msg.From().Hex(), l)
|
msg.From.Hex(), l)
|
||||||
}
|
}
|
||||||
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
|
if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 {
|
||||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
||||||
st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
|
msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap)
|
||||||
}
|
}
|
||||||
// This will panic if baseFee is nil, but basefee presence is verified
|
// This will panic if baseFee is nil, but basefee presence is verified
|
||||||
// as part of header validation.
|
// as part of header validation.
|
||||||
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||||
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
||||||
st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
|
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,52 +327,52 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||||||
if st.evm.Config.Debug {
|
if st.evm.Config.Debug {
|
||||||
st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
|
st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
|
||||||
defer func() {
|
defer func() {
|
||||||
st.evm.Config.Tracer.CaptureTxEnd(st.gas)
|
st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
msg = st.msg
|
msg = st.msg
|
||||||
sender = vm.AccountRef(msg.From())
|
sender = vm.AccountRef(msg.From)
|
||||||
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
|
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
|
||||||
contractCreation = msg.To() == nil
|
contractCreation = msg.To == nil
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
||||||
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if st.gas < gas {
|
if st.gasRemaining < gas {
|
||||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
|
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
|
||||||
}
|
}
|
||||||
st.gas -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
// Check clause 6
|
// Check clause 6
|
||||||
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
|
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
|
||||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
|
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the init code size has been exceeded.
|
// Check whether the init code size has been exceeded.
|
||||||
if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize {
|
if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
|
||||||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
|
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the preparatory steps for state transition which includes:
|
// Execute the preparatory steps for state transition which includes:
|
||||||
// - prepare accessList(post-berlin)
|
// - prepare accessList(post-berlin)
|
||||||
// - reset transient storage(eip 1153)
|
// - reset transient storage(eip 1153)
|
||||||
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ret []byte
|
ret []byte
|
||||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
|
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
|
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
||||||
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
|
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rules.IsLondon {
|
if !rules.IsLondon {
|
||||||
@ -366,12 +382,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||||||
// After EIP-3529: refunds are capped to gasUsed / 5
|
// After EIP-3529: refunds are capped to gasUsed / 5
|
||||||
st.refundGas(params.RefundQuotientEIP3529)
|
st.refundGas(params.RefundQuotientEIP3529)
|
||||||
}
|
}
|
||||||
effectiveTip := st.gasPrice
|
effectiveTip := msg.GasPrice
|
||||||
if rules.IsLondon {
|
if rules.IsLondon {
|
||||||
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
|
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 {
|
if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
|
||||||
// Skip fee payment when NoBaseFee is set and the fee fields
|
// Skip fee payment when NoBaseFee is set and the fee fields
|
||||||
// are 0. This avoids a negative effectiveTip being applied to
|
// are 0. This avoids a negative effectiveTip being applied to
|
||||||
// the coinbase when simulating calls.
|
// the coinbase when simulating calls.
|
||||||
@ -394,18 +410,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
|
|||||||
if refund > st.state.GetRefund() {
|
if refund > st.state.GetRefund() {
|
||||||
refund = st.state.GetRefund()
|
refund = st.state.GetRefund()
|
||||||
}
|
}
|
||||||
st.gas += refund
|
st.gasRemaining += refund
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
// Return ETH for remaining gas, exchanged at the original rate.
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
|
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
||||||
st.state.AddBalance(st.msg.From(), remaining)
|
st.state.AddBalance(st.msg.From, remaining)
|
||||||
|
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
// available for the next transaction.
|
// available for the next transaction.
|
||||||
st.gp.AddGas(st.gas)
|
st.gp.AddGas(st.gasRemaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gasUsed returns the amount of gas used up by the state transition.
|
// gasUsed returns the amount of gas used up by the state transition.
|
||||||
func (st *StateTransition) gasUsed() uint64 {
|
func (st *StateTransition) gasUsed() uint64 {
|
||||||
return st.initialGas - st.gas
|
return st.initialGas - st.gasRemaining
|
||||||
}
|
}
|
||||||
|
@ -589,74 +589,6 @@ func (t *TransactionsByPriceAndNonce) Pop() {
|
|||||||
heap.Pop(&t.heads)
|
heap.Pop(&t.heads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is a fully derived transaction and implements core.Message
|
|
||||||
//
|
|
||||||
// NOTE: In a future PR this will be removed.
|
|
||||||
type Message struct {
|
|
||||||
to *common.Address
|
|
||||||
from common.Address
|
|
||||||
nonce uint64
|
|
||||||
amount *big.Int
|
|
||||||
gasLimit uint64
|
|
||||||
gasPrice *big.Int
|
|
||||||
gasFeeCap *big.Int
|
|
||||||
gasTipCap *big.Int
|
|
||||||
data []byte
|
|
||||||
accessList AccessList
|
|
||||||
isFake bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, isFake bool) Message {
|
|
||||||
return Message{
|
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
nonce: nonce,
|
|
||||||
amount: amount,
|
|
||||||
gasLimit: gasLimit,
|
|
||||||
gasPrice: gasPrice,
|
|
||||||
gasFeeCap: gasFeeCap,
|
|
||||||
gasTipCap: gasTipCap,
|
|
||||||
data: data,
|
|
||||||
accessList: accessList,
|
|
||||||
isFake: isFake,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AsMessage returns the transaction as a core.Message.
|
|
||||||
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
|
|
||||||
msg := Message{
|
|
||||||
nonce: tx.Nonce(),
|
|
||||||
gasLimit: tx.Gas(),
|
|
||||||
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
|
||||||
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
|
||||||
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
|
||||||
to: tx.To(),
|
|
||||||
amount: tx.Value(),
|
|
||||||
data: tx.Data(),
|
|
||||||
accessList: tx.AccessList(),
|
|
||||||
isFake: false,
|
|
||||||
}
|
|
||||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
|
||||||
if baseFee != nil {
|
|
||||||
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
msg.from, err = Sender(s, tx)
|
|
||||||
return msg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Message) From() common.Address { return m.from }
|
|
||||||
func (m Message) To() *common.Address { return m.to }
|
|
||||||
func (m Message) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap }
|
|
||||||
func (m Message) GasTipCap() *big.Int { return m.gasTipCap }
|
|
||||||
func (m Message) Value() *big.Int { return m.amount }
|
|
||||||
func (m Message) Gas() uint64 { return m.gasLimit }
|
|
||||||
func (m Message) Nonce() uint64 { return m.nonce }
|
|
||||||
func (m Message) Data() []byte { return m.data }
|
|
||||||
func (m Message) AccessList() AccessList { return m.accessList }
|
|
||||||
func (m Message) IsFake() bool { return m.isFake }
|
|
||||||
|
|
||||||
// copyAddressPtr copies an address.
|
// copyAddressPtr copies an address.
|
||||||
func copyAddressPtr(a *common.Address) *common.Address {
|
func copyAddressPtr(a *common.Address) *common.Address {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
|
@ -228,7 +228,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
if vmConfig == nil {
|
if vmConfig == nil {
|
||||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||||
}
|
}
|
||||||
@ -382,6 +382,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
|||||||
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||||
@ -212,7 +212,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
|||||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
if idx == txIndex {
|
if idx == txIndex {
|
||||||
|
@ -87,7 +87,7 @@ type Backend interface {
|
|||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
ChainDb() ethdb.Database
|
ChainDb() ethdb.Database
|
||||||
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
||||||
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||||
@ -293,7 +293,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
|||||||
)
|
)
|
||||||
// Trace all the transactions contained within
|
// Trace all the transactions contained within
|
||||||
for i, tx := range task.block.Transactions() {
|
for i, tx := range task.block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: task.block.Hash(),
|
BlockHash: task.block.Hash(),
|
||||||
BlockNumber: task.block.Number(),
|
BlockNumber: task.block.Number(),
|
||||||
@ -554,12 +554,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg, _ = tx.AsMessage(signer, block.BaseFee())
|
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
txContext = core.NewEVMTxContext(msg)
|
||||||
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
||||||
)
|
)
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
// We intentionally don't return the error here: if we do, then the RPC server will not
|
// We intentionally don't return the error here: if we do, then the RPC server will not
|
||||||
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
||||||
@ -628,7 +628,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||||||
)
|
)
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockHash: blockHash,
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
@ -671,7 +671,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
|||||||
defer pend.Done()
|
defer pend.Done()
|
||||||
// Fetch and execute the next transaction trace tasks
|
// Fetch and execute the next transaction trace tasks
|
||||||
for task := range jobs {
|
for task := range jobs {
|
||||||
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockHash: blockHash,
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
@ -702,10 +702,10 @@ txloop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break txloop
|
break txloop
|
||||||
}
|
}
|
||||||
@ -782,7 +782,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the transaction for un-traced execution
|
// Prepare the transaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
msg, _ = tx.AsMessage(signer, block.BaseFee())
|
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
txContext = core.NewEVMTxContext(msg)
|
||||||
vmConf vm.Config
|
vmConf vm.Config
|
||||||
dump *os.File
|
dump *os.File
|
||||||
@ -813,7 +813,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||||||
// Execute the transaction and flush any traces to disk
|
// Execute the transaction and flush any traces to disk
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if writer != nil {
|
if writer != nil {
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
}
|
}
|
||||||
@ -947,7 +947,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||||||
// traceTx configures a new tracer according to the provided configuration, and
|
// traceTx configures a new tracer according to the provided configuration, and
|
||||||
// executes the given message in the provided environment. The return value will
|
// executes the given message in the provided environment. The return value will
|
||||||
// be tracer dependent.
|
// be tracer dependent.
|
||||||
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||||
var (
|
var (
|
||||||
tracer Tracer
|
tracer Tracer
|
||||||
err error
|
err error
|
||||||
@ -986,7 +986,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
|
|||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call Prepare to clear out the statedb access list
|
||||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil {
|
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
return tracer.GetResult()
|
return tracer.GetResult()
|
||||||
|
@ -156,7 +156,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex
|
|||||||
return statedb, release, nil
|
return statedb, release, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
||||||
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
||||||
@ -171,7 +171,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
|||||||
// Recompute transactions up to the target index.
|
// Recompute transactions up to the target index.
|
||||||
signer := types.MakeSigner(b.chainConfig, block.Number())
|
signer := types.MakeSigner(b.chainConfig, block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||||
if idx == txIndex {
|
if idx == txIndex {
|
||||||
|
@ -145,7 +145,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||||||
b.Fatalf("failed to parse testcase input: %v", err)
|
b.Fatalf("failed to parse testcase input: %v", err)
|
||||||
}
|
}
|
||||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
@ -314,7 +314,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
|||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
|||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
|
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
|||||||
//EnableReturnData: false,
|
//EnableReturnData: false,
|
||||||
})
|
})
|
||||||
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1005,7 +1005,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
|
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit)
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@ -1478,7 +1478,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ type Backend interface {
|
|||||||
PendingBlockAndReceipts() (*types.Block, types.Receipts)
|
PendingBlockAndReceipts() (*types.Block, types.Receipts)
|
||||||
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
||||||
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||||
GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
|
GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
|
||||||
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
||||||
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||||
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
@ -199,10 +200,10 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ
|
|||||||
// ToMessage converts the transaction arguments to the Message type used by the
|
// ToMessage converts the transaction arguments to the Message type used by the
|
||||||
// core evm. This method is used in calls and traces that do not require a real
|
// core evm. This method is used in calls and traces that do not require a real
|
||||||
// live transaction.
|
// live transaction.
|
||||||
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
|
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) {
|
||||||
// Reject invalid combinations of pre- and post-1559 fee styles
|
// Reject invalid combinations of pre- and post-1559 fee styles
|
||||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||||
return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||||
}
|
}
|
||||||
// Set sender address or use zero address if none specified.
|
// Set sender address or use zero address if none specified.
|
||||||
addr := args.from()
|
addr := args.from()
|
||||||
@ -263,7 +264,18 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t
|
|||||||
if args.AccessList != nil {
|
if args.AccessList != nil {
|
||||||
accessList = *args.AccessList
|
accessList = *args.AccessList
|
||||||
}
|
}
|
||||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true)
|
msg := &core.Message{
|
||||||
|
From: addr,
|
||||||
|
To: args.To,
|
||||||
|
Value: value,
|
||||||
|
GasLimit: gas,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
GasFeeCap: gasFeeCap,
|
||||||
|
GasTipCap: gasTipCap,
|
||||||
|
Data: data,
|
||||||
|
AccessList: accessList,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
|
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
|
||||||
func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
|
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
|
||||||
|
@ -184,7 +184,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
if vmConfig == nil {
|
if vmConfig == nil {
|
||||||
vmConfig = new(vm.Config)
|
vmConfig = new(vm.Config)
|
||||||
}
|
}
|
||||||
@ -330,6 +330,6 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
|||||||
return b.eth.stateAtBlock(ctx, block, reexec)
|
return b.eth.stateAtBlock(ctx, block, reexec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||||
}
|
}
|
||||||
|
@ -116,12 +116,6 @@ func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, true, odrContractC
|
|||||||
func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) }
|
func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) }
|
||||||
func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) }
|
func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) }
|
||||||
|
|
||||||
type callmsg struct {
|
|
||||||
types.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (callmsg) CheckNonce() bool { return false }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
||||||
@ -136,7 +130,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||||||
from := statedb.GetOrNewStateObject(bankAddr)
|
from := statedb.GetOrNewStateObject(bankAddr)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
|
|
||||||
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
msg := &core.Message{
|
||||||
|
From: from.Address(),
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 100000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
|
|
||||||
context := core.NewEVMBlockContext(header, bc, nil)
|
context := core.NewEVMBlockContext(header, bc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
@ -151,7 +155,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||||||
header := lc.GetHeaderByHash(bhash)
|
header := lc.GetHeaderByHash(bhash)
|
||||||
state := light.NewState(ctx, header, lc.Odr())
|
state := light.NewState(ctx, header, lc.Odr())
|
||||||
state.SetBalance(bankAddr, math.MaxBig256)
|
state.SetBalance(bankAddr, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
msg := &core.Message{
|
||||||
|
From: bankAddr,
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 100000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
context := core.NewEVMBlockContext(header, lc, nil)
|
context := core.NewEVMBlockContext(header, lc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||||
|
@ -39,7 +39,7 @@ func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||||
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||||
@ -60,7 +60,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
|||||||
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||||
statedb.SetTxContext(tx.Hash(), idx)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
|
@ -174,12 +174,6 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
|
|||||||
|
|
||||||
func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) }
|
func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) }
|
||||||
|
|
||||||
type callmsg struct {
|
|
||||||
types.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (callmsg) CheckNonce() bool { return false }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
|
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
config := params.TestChainConfig
|
config := params.TestChainConfig
|
||||||
@ -205,7 +199,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
|||||||
|
|
||||||
// Perform read-only call.
|
// Perform read-only call.
|
||||||
st.SetBalance(testBankAddress, math.MaxBig256)
|
st.SetBalance(testBankAddress, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
msg := &core.Message{
|
||||||
|
From: testBankAddress,
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 1000000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(header, chain, nil)
|
context := core.NewEVMBlockContext(header, chain, nil)
|
||||||
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||||
|
@ -228,7 +228,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
|||||||
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
|
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
|
||||||
|
|
||||||
// Create "contract" for sender to cache code analysis.
|
// Create "contract" for sender to cache code analysis.
|
||||||
sender := vm.NewContract(vm.AccountRef(msg.From()), vm.AccountRef(msg.From()),
|
sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From),
|
||||||
nil, 0)
|
nil, 0)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -239,12 +239,12 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
statedb.Prepare(rules, msg.From(), context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
_, leftOverGas, err := evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value())
|
_, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, msg.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
@ -253,7 +253,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
elapsed += uint64(time.Since(start))
|
elapsed += uint64(time.Since(start))
|
||||||
refund += statedb.GetRefund()
|
refund += statedb.GetRefund()
|
||||||
gasUsed += msg.Gas() - leftOverGas
|
gasUsed += msg.GasLimit - leftOverGas
|
||||||
|
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
|
|||||||
return genesis
|
return genesis
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) {
|
func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) {
|
||||||
// Derive sender from private key if present.
|
// Derive sender from private key if present.
|
||||||
var from common.Address
|
var from common.Address
|
||||||
if len(tx.PrivateKey) > 0 {
|
if len(tx.PrivateKey) > 0 {
|
||||||
@ -397,8 +397,18 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Messa
|
|||||||
return nil, fmt.Errorf("no gas price provided")
|
return nil, fmt.Errorf("no gas price provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice,
|
msg := &core.Message{
|
||||||
tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false)
|
From: from,
|
||||||
|
To: to,
|
||||||
|
Nonce: tx.Nonce,
|
||||||
|
Value: value,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
GasFeeCap: tx.MaxFeePerGas,
|
||||||
|
GasTipCap: tx.MaxPriorityFeePerGas,
|
||||||
|
Data: data,
|
||||||
|
AccessList: accessList,
|
||||||
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user