Skip to content

Commit 3af6290

Browse files
authored
internal/ethapi: eth_simulateV1 ethereum#27720 (#1606)
1 parent 4c22aa9 commit 3af6290

File tree

18 files changed

+1097
-164
lines changed

18 files changed

+1097
-164
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -742,16 +742,17 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
742742

743743
// Execute the call.
744744
msg := &core.Message{
745-
From: call.From,
746-
To: call.To,
747-
Value: call.Value,
748-
GasLimit: call.Gas,
749-
GasPrice: call.GasPrice,
750-
GasFeeCap: call.GasFeeCap,
751-
GasTipCap: call.GasTipCap,
752-
Data: call.Data,
753-
AccessList: call.AccessList,
754-
SkipAccountChecks: true,
745+
From: call.From,
746+
To: call.To,
747+
Value: call.Value,
748+
GasLimit: call.Gas,
749+
GasPrice: call.GasPrice,
750+
GasFeeCap: call.GasFeeCap,
751+
GasTipCap: call.GasTipCap,
752+
Data: call.Data,
753+
AccessList: call.AccessList,
754+
SkipNonceChecks: true,
755+
SkipFromEOACheck: true,
755756
}
756757
feeCapacity := state.GetTRC21FeeCapacityFromState(stateDB)
757758
if msg.To != nil {

core/state_processor.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,18 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
440440
}
441441
*usedGas += result.UsedGas
442442

443+
if balanceFee != nil && result.Failed() {
444+
state.PayFeeWithTRC21TxFail(statedb, msg.From, *to)
445+
}
446+
447+
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), result.UsedGas, balanceFee != nil, nil
448+
}
449+
450+
// MakeReceipt generates the receipt object for a transaction given its execution result.
451+
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
443452
// Create a new receipt for the transaction, storing the intermediate root and gas used
444453
// by the tx.
445-
receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
454+
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
446455
if result.Failed() {
447456
receipt.Status = types.ReceiptStatusFailed
448457
} else {
@@ -452,7 +461,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
452461
receipt.GasUsed = result.UsedGas
453462

454463
// If the transaction created a contract, store the creation address in the receipt.
455-
if msg.To == nil {
464+
if tx.To() == nil {
456465
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
457466
}
458467

@@ -462,10 +471,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
462471
receipt.BlockHash = blockHash
463472
receipt.BlockNumber = blockNumber
464473
receipt.TransactionIndex = uint(statedb.TxIndex())
465-
if balanceFee != nil && result.Failed() {
466-
state.PayFeeWithTRC21TxFail(statedb, msg.From, *to)
467-
}
468-
return receipt, result.UsedGas, balanceFee != nil, nil
474+
return receipt
469475
}
470476

471477
func getCoinbaseOwner(bc *BlockChain, statedb *state.StateDB, header *types.Header, author *common.Address) common.Address {

core/state_transition.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,26 +128,30 @@ type Message struct {
128128
Data []byte
129129
AccessList types.AccessList
130130

131-
// When SkipAccountCheckss is true, the message nonce is not checked against the
132-
// account nonce in state. It also disables checking that the sender is an EOA.
131+
// When SkipNonceChecks is true, the message nonce is not checked against the
132+
// account nonce in state.
133133
// This field will be set to true for operations like RPC eth_call.
134-
SkipAccountChecks bool
134+
SkipNonceChecks bool
135+
136+
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
137+
SkipFromEOACheck bool
135138
}
136139

137140
// TransactionToMessage converts a transaction into a Message.
138141
func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blockNumber, baseFee *big.Int) (*Message, error) {
139142
msg := &Message{
140-
Nonce: tx.Nonce(),
141-
GasLimit: tx.Gas(),
142-
GasPrice: new(big.Int).Set(tx.GasPrice()),
143-
GasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
144-
GasTipCap: new(big.Int).Set(tx.GasTipCap()),
145-
To: tx.To(),
146-
Value: tx.Value(),
147-
Data: tx.Data(),
148-
AccessList: tx.AccessList(),
149-
SkipAccountChecks: false,
150-
BalanceTokenFee: balanceFee,
143+
Nonce: tx.Nonce(),
144+
GasLimit: tx.Gas(),
145+
GasPrice: new(big.Int).Set(tx.GasPrice()),
146+
GasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
147+
GasTipCap: new(big.Int).Set(tx.GasTipCap()),
148+
To: tx.To(),
149+
Value: tx.Value(),
150+
Data: tx.Data(),
151+
AccessList: tx.AccessList(),
152+
SkipNonceChecks: false,
153+
SkipFromEOACheck: false,
154+
BalanceTokenFee: balanceFee,
151155
}
152156

153157
if balanceFee != nil {
@@ -282,7 +286,7 @@ func (st *StateTransition) buyGas() error {
282286
func (st *StateTransition) preCheck() error {
283287
// Only check transactions that are not fake
284288
msg := st.msg
285-
if !msg.SkipAccountChecks {
289+
if !msg.SkipNonceChecks {
286290
// Make sure this transaction's nonce is correct.
287291
stNonce := st.state.GetNonce(msg.From)
288292
if msgNonce := msg.Nonce; stNonce < msgNonce {
@@ -295,13 +299,15 @@ func (st *StateTransition) preCheck() error {
295299
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
296300
msg.From.Hex(), stNonce)
297301
}
302+
}
303+
if !msg.SkipFromEOACheck {
298304
// Make sure the sender is an EOA
299-
if codeHash := st.state.GetCodeHash(msg.From); codeHash != types.EmptyCodeHash && codeHash != (common.Hash{}) {
305+
codeHash := st.state.GetCodeHash(msg.From)
306+
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
300307
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
301308
msg.From.Hex(), codeHash)
302309
}
303310
}
304-
305311
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
306312
if st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
307313
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)

core/token_validator.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,17 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,
8787

8888
// Execute the call.
8989
msg := &Message{
90-
From: call.From,
91-
To: call.To,
92-
Value: call.Value,
93-
GasLimit: call.Gas,
94-
GasPrice: call.GasPrice,
95-
GasFeeCap: call.GasFeeCap,
96-
GasTipCap: call.GasTipCap,
97-
Data: call.Data,
98-
AccessList: call.AccessList,
99-
SkipAccountChecks: true,
90+
From: call.From,
91+
To: call.To,
92+
Value: call.Value,
93+
GasLimit: call.Gas,
94+
GasPrice: call.GasPrice,
95+
GasFeeCap: call.GasFeeCap,
96+
GasTipCap: call.GasTipCap,
97+
Data: call.Data,
98+
AccessList: call.AccessList,
99+
SkipNonceChecks: true,
100+
SkipFromEOACheck: true,
100101
}
101102
feeCapacity := state.GetTRC21FeeCapacityFromState(statedb)
102103
if msg.To != nil {

core/vm/contracts.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"crypto/sha256"
2121
"encoding/binary"
2222
"errors"
23+
"maps"
2324
"math"
2425
"math/big"
2526

@@ -41,9 +42,12 @@ type PrecompiledContract interface {
4142
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
4243
}
4344

45+
// PrecompiledContracts contains the precompiled contracts supported at the given fork.
46+
type PrecompiledContracts map[common.Address]PrecompiledContract
47+
4448
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
4549
// contracts used in the Frontier and Homestead releases.
46-
var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
50+
var PrecompiledContractsHomestead = PrecompiledContracts{
4751
common.BytesToAddress([]byte{1}): &ecrecover{},
4852
common.BytesToAddress([]byte{2}): &sha256hash{},
4953
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -52,7 +56,7 @@ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
5256

5357
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
5458
// contracts used in the Byzantium release.
55-
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
59+
var PrecompiledContractsByzantium = PrecompiledContracts{
5660
common.BytesToAddress([]byte{1}): &ecrecover{},
5761
common.BytesToAddress([]byte{2}): &sha256hash{},
5862
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -69,7 +73,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
6973

7074
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
7175
// contracts used in the Istanbul release.
72-
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
76+
var PrecompiledContractsIstanbul = PrecompiledContracts{
7377
common.BytesToAddress([]byte{1}): &ecrecover{},
7478
common.BytesToAddress([]byte{2}): &sha256hash{},
7579
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -85,7 +89,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
8589
common.BytesToAddress([]byte{42}): &XDCxEpochPrice{},
8690
}
8791

88-
var PrecompiledContractsXDCv2 = map[common.Address]PrecompiledContract{
92+
var PrecompiledContractsXDCv2 = PrecompiledContracts{
8993
common.BytesToAddress([]byte{1}): &ecrecover{},
9094
common.BytesToAddress([]byte{2}): &sha256hash{},
9195
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -97,7 +101,7 @@ var PrecompiledContractsXDCv2 = map[common.Address]PrecompiledContract{
97101
common.BytesToAddress([]byte{9}): &blake2F{},
98102
}
99103

100-
var PrecompiledContractsEIP1559 = map[common.Address]PrecompiledContract{
104+
var PrecompiledContractsEIP1559 = PrecompiledContracts{
101105
common.BytesToAddress([]byte{1}): &ecrecover{},
102106
common.BytesToAddress([]byte{2}): &sha256hash{},
103107
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -135,7 +139,27 @@ func init() {
135139
}
136140
}
137141

138-
// ActivePrecompiles returns the precompiles enabled with the current configuration.
142+
func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
143+
switch {
144+
case rules.IsEIP1559:
145+
return PrecompiledContractsEIP1559
146+
case rules.IsXDCxDisable:
147+
return PrecompiledContractsXDCv2
148+
case rules.IsIstanbul:
149+
return PrecompiledContractsIstanbul
150+
case rules.IsByzantium:
151+
return PrecompiledContractsByzantium
152+
default:
153+
return PrecompiledContractsHomestead
154+
}
155+
}
156+
157+
// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration.
158+
func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
159+
return maps.Clone(activePrecompiledContracts(rules))
160+
}
161+
162+
// ActivePrecompiles returns the precompile addresses enabled with the current configuration.
139163
func ActivePrecompiles(rules params.Rules) []common.Address {
140164
switch {
141165
case rules.IsEIP1559:

core/vm/evm.go

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,7 @@ type (
4141
)
4242

4343
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
44-
var precompiles map[common.Address]PrecompiledContract
45-
switch {
46-
case evm.chainRules.IsEIP1559:
47-
precompiles = PrecompiledContractsEIP1559
48-
case evm.chainRules.IsXDCxDisable:
49-
precompiles = PrecompiledContractsXDCv2
50-
case evm.chainRules.IsIstanbul:
51-
precompiles = PrecompiledContractsIstanbul
52-
case evm.chainRules.IsByzantium:
53-
precompiles = PrecompiledContractsByzantium
54-
default:
55-
precompiles = PrecompiledContractsHomestead
56-
}
57-
p, ok := precompiles[addr]
44+
p, ok := evm.precompiles[addr]
5845
return p, ok
5946
}
6047

@@ -124,19 +111,13 @@ type EVM struct {
124111
// available gas is calculated in gasCall* according to the 63/64 rule and later
125112
// applied in opCall*.
126113
callGasTemp uint64
114+
// precompiles holds the precompiled contracts for the current epoch
115+
precompiles map[common.Address]PrecompiledContract
127116
}
128117

129118
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
130119
// only ever be used *once*.
131120
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStateDB *tradingstate.TradingStateDB, chainConfig *params.ChainConfig, config Config) *EVM {
132-
// If basefee tracking is disabled (eth_call, eth_estimateGas, etc), and no
133-
// gas prices were specified, lower the basefee to 0 to avoid breaking EVM
134-
// invariants (basefee < feecap)
135-
if config.NoBaseFee {
136-
if txCtx.GasPrice.BitLen() == 0 {
137-
blockCtx.BaseFee = new(big.Int)
138-
}
139-
}
140121
evm := &EVM{
141122
Context: blockCtx,
142123
TxContext: txCtx,
@@ -146,11 +127,18 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
146127
chainConfig: chainConfig,
147128
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
148129
}
149-
130+
evm.precompiles = activePrecompiledContracts(evm.chainRules)
150131
evm.interpreter = NewEVMInterpreter(evm)
151132
return evm
152133
}
153134

135+
// SetPrecompiles sets the precompiled contracts for the EVM.
136+
// This method is only used through RPC calls.
137+
// It is not thread-safe.
138+
func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) {
139+
evm.precompiles = precompiles
140+
}
141+
154142
// Reset resets the EVM with a new transaction context.Reset
155143
// This is not threadsafe and should only be done very cautiously.
156144
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {

eth/gasestimator/gasestimator.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,13 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
170170
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
171171

172172
dirtyState = opts.State.Copy()
173-
evm = vm.NewEVM(evmContext, msgContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true})
174173
)
174+
// Lower the basefee to 0 to avoid breaking EVM
175+
// invariants (basefee < feecap).
176+
if msgContext.GasPrice.Sign() == 0 {
177+
evmContext.BaseFee = new(big.Int)
178+
}
179+
evm := vm.NewEVM(evmContext, msgContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true})
175180
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
176181
// a dangling goroutine until the outer estimation finishes, create an internal
177182
// context for the lifetime of this method call.

eth/tracers/api.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -812,20 +812,28 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
812812
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
813813
// Apply the customization rules if required.
814814
if config != nil {
815-
if err := config.StateOverrides.Apply(statedb); err != nil {
815+
config.BlockOverrides.Apply(&vmctx)
816+
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber)
817+
818+
precompiles := vm.ActivePrecompiledContracts(rules)
819+
if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
816820
return nil, err
817821
}
818-
config.BlockOverrides.Apply(&vmctx)
819822
}
820823
// Execute the trace
821824
if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
822825
return nil, err
823826
}
824827
var (
825-
msg = args.ToMessage(api.backend, vmctx.BaseFee)
826-
tx = args.ToTransaction()
828+
msg = args.ToMessage(api.backend, vmctx.BaseFee, true, true)
829+
tx = args.ToTransaction(types.LegacyTxType)
827830
traceConfig *TraceConfig
828831
)
832+
// Lower the basefee to 0 to avoid breaking EVM
833+
// invariants (basefee < feecap).
834+
if msg.GasPrice.Sign() == 0 {
835+
vmctx.BaseFee = new(big.Int)
836+
}
829837
if config != nil {
830838
traceConfig = &config.TraceConfig
831839
}

ethclient/gethclient/gethclient.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,9 @@ func (o BlockOverrides) MarshalJSON() ([]byte, error) {
287287
Difficulty *hexutil.Big `json:"difficulty,omitempty"`
288288
Time hexutil.Uint64 `json:"time,omitempty"`
289289
GasLimit hexutil.Uint64 `json:"gasLimit,omitempty"`
290-
Coinbase *common.Address `json:"coinbase,omitempty"`
291-
Random *common.Hash `json:"random,omitempty"`
292-
BaseFee *hexutil.Big `json:"baseFee,omitempty"`
290+
Coinbase *common.Address `json:"feeRecipient,omitempty"`
291+
Random *common.Hash `json:"prevRandao,omitempty"`
292+
BaseFee *hexutil.Big `json:"baseFeePerGas,omitempty"`
293293
}
294294

295295
output := override{

ethclient/gethclient/gethclient_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func TestBlockOverridesMarshal(t *testing.T) {
8787
bo: BlockOverrides{
8888
Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"),
8989
},
90-
want: `{"coinbase":"0x1111111111111111111111111111111111111111"}`,
90+
want: `{"feeRecipient":"0x1111111111111111111111111111111111111111"}`,
9191
},
9292
{
9393
bo: BlockOverrides{
@@ -97,7 +97,7 @@ func TestBlockOverridesMarshal(t *testing.T) {
9797
GasLimit: 4,
9898
BaseFee: big.NewInt(5),
9999
},
100-
want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFee":"0x5"}`,
100+
want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFeePerGas":"0x5"}`,
101101
},
102102
} {
103103
marshalled, err := json.Marshal(&tt.bo)

0 commit comments

Comments
 (0)