Skip to content

Commit aea59c3

Browse files
chiphamskymavisrjl493456442holiman
committed
internal/ethapi: eth_multicall (#27720)
This is a successor PR to #25743. This PR is based on a new iteration of the spec: ethereum/execution-apis#484. `eth_multicall` takes in a list of blocks, each optionally overriding fields like number, timestamp, etc. of a base block. Each block can include calls. At each block users can override the state. There are extra features, such as: - Include ether transfers as part of the logs - Overriding precompile codes with evm bytecode - Redirecting accounts to another address This PR includes the following breaking changes: - Block override fields of eth_call and debug_traceCall have had the following fields renamed - `coinbase` -> `feeRecipient` - `random` -> `prevRandao` - `baseFee` -> `baseFeePerGas` --------- Co-authored-by: Gary Rong <[email protected]> Co-authored-by: Martin Holst Swende <[email protected]>
1 parent 1a570dd commit aea59c3

File tree

14 files changed

+1190
-118
lines changed

14 files changed

+1190
-118
lines changed

core/state_processor.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,19 @@ func ApplyMessageWithEVM(
196196

197197
// Create a new receipt for the transaction, storing the intermediate root and gas used
198198
// by the tx.
199-
receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
199+
receipt = MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root)
200+
201+
// create the bloom filter
202+
receiptProcessor.Apply(receipt)
203+
204+
return receipt, result, err
205+
}
206+
207+
// MakeReceipt generates the receipt object for a transaction given its execution result.
208+
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 {
209+
// Create a new receipt for the transaction, storing the intermediate root and gas used
210+
// by the tx.
211+
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
200212
if result.Failed() {
201213
receipt.Status = types.ReceiptStatusFailed
202214
} else {
@@ -211,19 +223,17 @@ func ApplyMessageWithEVM(
211223
}
212224

213225
// If the transaction created a contract, store the creation address in the receipt.
214-
if msg.To == nil {
226+
if tx.To() == nil {
215227
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
216228
}
217229

218230
// Set the receipt logs and create the bloom filter.
219231
receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash)
232+
receipt.Bloom = types.CreateReceiptBloom(receipt)
220233
receipt.BlockHash = blockHash
221234
receipt.BlockNumber = blockNumber
222235
receipt.TransactionIndex = uint(statedb.TxIndex())
223-
// create the bloom filter
224-
receiptProcessor.Apply(receipt)
225-
226-
return receipt, result, err
236+
return receipt
227237
}
228238

229239
// ApplyTransaction attempts to apply a transaction to the given state database

core/types/block.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ import (
3434
"github.com/ethereum/go-ethereum/rlp"
3535
)
3636

37-
var (
38-
EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
39-
EmptyUncleHash = rlpHash([]*Header(nil))
40-
)
41-
4237
// A BlockNonce is a 64-bit hash which proves (combined with the
4338
// mix-hash) that a sufficient amount of computation has been carried
4439
// out on a block.

core/types/bloom9.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ func CreateBloom(receipts Receipts) Bloom {
117117
return bin
118118
}
119119

120+
// CreateReceiptBloom creates a bloom filter for a receipt
121+
func CreateReceiptBloom(receipt *Receipt) Bloom {
122+
var (
123+
bin Bloom
124+
buf = make([]byte, 6)
125+
)
126+
for _, log := range receipt.Logs {
127+
bin.add(log.Address.Bytes(), buf)
128+
for _, b := range log.Topics {
129+
bin.add(b[:], buf)
130+
}
131+
}
132+
return bin
133+
}
134+
120135
// MergeBloom assumes all receipts contain calculated bloom filters and
121136
// merge them to create the final bloom filter instead of recalculating
122137
// like CreateBloom

core/types/hashes.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package types
1818

1919
import (
2020
"github.com/ethereum/go-ethereum/common"
21+
"github.com/ethereum/go-ethereum/crypto"
2122
"github.com/ethereum/go-ethereum/log"
2223
)
2324

@@ -30,3 +31,29 @@ func TrieRootHash(hash common.Hash) common.Hash {
3031
}
3132
return hash
3233
}
34+
35+
var (
36+
// EmptyRootHash is the known root hash of an empty merkle trie.
37+
EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
38+
39+
// EmptyUncleHash is the known hash of the empty uncle set.
40+
EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
41+
42+
// EmptyCodeHash is the known hash of the empty EVM bytecode.
43+
EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
44+
45+
// EmptyTxsHash is the known hash of the empty transaction set.
46+
EmptyTxsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
47+
48+
// EmptyReceiptsHash is the known hash of the empty receipt set.
49+
EmptyReceiptsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
50+
51+
// EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
52+
EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
53+
54+
// EmptyRequestsHash is the known hash of an empty request set, sha256("").
55+
EmptyRequestsHash = common.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
56+
57+
// EmptyVerkleHash is the known hash of an empty verkle trie.
58+
EmptyVerkleHash = common.Hash{}
59+
)

core/vm/contracts.go

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"encoding/binary"
2222
"errors"
2323
"fmt"
24+
"maps"
2425
"math/big"
2526

2627
"github.com/ethereum/go-ethereum/common"
@@ -45,6 +46,9 @@ type PrecompiledContract interface {
4546
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
4647
}
4748

49+
// PrecompiledContracts contains the precompiled contracts supported at the given fork.
50+
type PrecompiledContracts map[common.Address]PrecompiledContract
51+
4852
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
4953
// contracts specified in EIP-2537. These are exported for testing purposes.
5054
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
@@ -70,35 +74,39 @@ var (
7074

7175
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
7276
// contracts used in the Frontier and Homestead releases.
73-
PrecompiledContractsHomestead map[common.Address]PrecompiledContract
77+
PrecompiledContractsHomestead PrecompiledContracts
7478

7579
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
7680
// contracts used in the Byzantium release.
77-
PrecompiledContractsByzantium map[common.Address]PrecompiledContract
81+
PrecompiledContractsByzantium PrecompiledContracts
7882

7983
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
8084
// contracts used in the Istanbul release.
81-
PrecompiledContractsIstanbul map[common.Address]PrecompiledContract
85+
PrecompiledContractsIstanbul PrecompiledContracts
8286

8387
// PrecompiledContractsConsortium contains additional Consortium precompiled contract
8488
// beside PrecompiledContractsIstanbul
85-
PrecompiledContractsConsortium map[common.Address]PrecompiledContract
89+
PrecompiledContractsConsortium PrecompiledContracts
8690

8791
// PrecompiledContractsConsortium contains proof of possession precompiled contract
8892
// beside PrecompiledContractsConsortium
89-
PrecompiledContractsConsortiumMiko map[common.Address]PrecompiledContract
93+
PrecompiledContractsConsortiumMiko PrecompiledContracts
9094

9195
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
9296
// contracts used in the Berlin release.
93-
PrecompiledContractsBerlin map[common.Address]PrecompiledContract
97+
PrecompiledContractsBerlin PrecompiledContracts
9498

9599
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
96100
// contracts used in the Cancun release.
97-
PrecompiledContractsCancun map[common.Address]PrecompiledContract
101+
PrecompiledContractsCancun PrecompiledContracts
102+
103+
// PrecompiledContractsPrague contains the default set of pre-compiled Ethereum
104+
// contracts used in the Prague release.
105+
PrecompiledContractsPrague PrecompiledContracts
98106
)
99107

100-
func copyPrecompiledContract(contracts map[common.Address]PrecompiledContract) map[common.Address]PrecompiledContract {
101-
cpy := make(map[common.Address]PrecompiledContract)
108+
func copyPrecompiledContract(contracts PrecompiledContracts) PrecompiledContracts {
109+
cpy := make(PrecompiledContracts)
102110

103111
for address, contract := range contracts {
104112
cpy[address] = contract
@@ -108,7 +116,7 @@ func copyPrecompiledContract(contracts map[common.Address]PrecompiledContract) m
108116
}
109117

110118
func init() {
111-
PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
119+
PrecompiledContractsHomestead = PrecompiledContracts{
112120
common.BytesToAddress([]byte{1}): &ecrecover{},
113121
common.BytesToAddress([]byte{2}): &sha256hash{},
114122
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -202,6 +210,30 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
202210
}
203211
}
204212

213+
func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
214+
switch {
215+
case rules.IsCancun:
216+
return PrecompiledContractsCancun
217+
case rules.IsBerlin:
218+
return PrecompiledContractsBerlin
219+
case rules.IsMiko:
220+
return PrecompiledContractsConsortiumMiko
221+
case rules.IsLastConsortiumV1Block, rules.IsConsortiumV2:
222+
return PrecompiledContractsConsortium
223+
case rules.IsIstanbul:
224+
return PrecompiledContractsIstanbul
225+
case rules.IsByzantium:
226+
return PrecompiledContractsByzantium
227+
default:
228+
return PrecompiledContractsHomestead
229+
}
230+
}
231+
232+
// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration.
233+
func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
234+
return maps.Clone(activePrecompiledContracts(rules))
235+
}
236+
205237
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
206238
// It returns
207239
// - the returned bytes,
@@ -220,9 +252,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin
220252
return output, suppliedGas, err
221253
}
222254

223-
var (
224-
errBlacklistedAddress = errors.New("address is blacklisted")
225-
)
255+
var errBlacklistedAddress = errors.New("address is blacklisted")
226256

227257
type blacklistedAddress struct{}
228258

@@ -282,6 +312,7 @@ type sha256hash struct{}
282312
func (c *sha256hash) RequiredGas(input []byte) uint64 {
283313
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
284314
}
315+
285316
func (c *sha256hash) Run(input []byte) ([]byte, error) {
286317
h := sha256.Sum256(input)
287318
return h[:], nil
@@ -297,6 +328,7 @@ type ripemd160hash struct{}
297328
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
298329
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
299330
}
331+
300332
func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
301333
ripemd := ripemd160.New()
302334
ripemd.Write(input)
@@ -313,6 +345,7 @@ type dataCopy struct{}
313345
func (c *dataCopy) RequiredGas(input []byte) uint64 {
314346
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
315347
}
348+
316349
func (c *dataCopy) Run(in []byte) ([]byte, error) {
317350
return common.CopyBytes(in), nil
318351
}

core/vm/evm.go

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -71,31 +71,7 @@ func (evm *EVM) precompile(caller ContractRef, addr common.Address) (Precompiled
7171
}
7272
}
7373

74-
var precompiles map[common.Address]PrecompiledContract
75-
switch {
76-
case evm.chainRules.IsCancun:
77-
precompiles = PrecompiledContractsCancun
78-
case evm.chainRules.IsBerlin:
79-
precompiles = PrecompiledContractsBerlin
80-
case evm.chainRules.IsMiko:
81-
precompiles = PrecompiledContractsConsortiumMiko
82-
case evm.chainRules.IsLastConsortiumV1Block, evm.chainRules.IsConsortiumV2:
83-
precompiles = PrecompiledContractsConsortium
84-
case evm.chainRules.IsIstanbul:
85-
precompiles = PrecompiledContractsIstanbul
86-
case evm.chainRules.IsByzantium:
87-
precompiles = PrecompiledContractsByzantium
88-
default:
89-
precompiles = PrecompiledContractsHomestead
90-
}
91-
92-
p, ok := precompiles[addr]
93-
if ok {
94-
if pWithInit, hasInit := p.(PrecompiledContractWithInit); hasInit {
95-
pWithInit.Init(caller, evm)
96-
}
97-
}
98-
74+
p, ok := evm.precompiles[addr]
9975
return p, ok
10076
}
10177

@@ -176,6 +152,8 @@ type EVM struct {
176152
// applied in opCall*.
177153
callGasTemp uint64
178154

155+
precompiles PrecompiledContracts
156+
179157
evmHook EVMHook
180158
}
181159

@@ -195,6 +173,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
195173
chainConfig: chainConfig,
196174
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
197175
}
176+
evm.precompiles = activePrecompiledContracts(evm.chainRules)
198177
evm.interpreter = NewEVMInterpreter(evm, config)
199178
return evm
200179
}
@@ -222,6 +201,13 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
222201
return evm.interpreter
223202
}
224203

204+
// SetPrecompiles sets the precompiled contracts for the EVM.
205+
// This method is only used through RPC calls.
206+
// It is not thread-safe.
207+
func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) {
208+
evm.precompiles = precompiles
209+
}
210+
225211
// Call executes the contract associated with the addr with the given input as
226212
// parameters. It also handles any necessary value transfer required and takes
227213
// the necessary steps to create accounts and reverses the state in case of an
@@ -323,7 +309,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
323309
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
324310
return nil, gas, ErrInsufficientBalance
325311
}
326-
var snapshot = evm.StateDB.Snapshot()
312+
snapshot := evm.StateDB.Snapshot()
327313

328314
// It is allowed to call precompiles, even via delegatecall
329315
if p, isPrecompile := evm.precompile(caller, addr); isPrecompile {
@@ -374,7 +360,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
374360
if evm.depth > int(params.CallCreateDepth) {
375361
return nil, gas, ErrDepth
376362
}
377-
var snapshot = evm.StateDB.Snapshot()
363+
snapshot := evm.StateDB.Snapshot()
378364

379365
// It is allowed to call precompiles, even via delegatecall
380366
if p, isPrecompile := evm.precompile(caller, addr); isPrecompile {
@@ -423,7 +409,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
423409
// after all empty accounts were deleted, so this is not required. However, if we omit this,
424410
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
425411
// We could change this, but for now it's left for legacy reasons
426-
var snapshot = evm.StateDB.Snapshot()
412+
snapshot := evm.StateDB.Snapshot()
427413

428414
// We do an AddBalance of zero here, just in order to trigger a touch.
429415
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,

core/vm/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ type StateDB interface {
8585
ValidDeployer(common.Address) bool
8686
ValidDeployerV2(common.Address, uint64, *common.Address) bool
8787
Blacklisted(*common.Address, *common.Address) bool
88+
89+
// Finalise must be invoked at the end of a transaction
90+
Finalise(bool)
8891
}
8992

9093
// CallContext provides a basic interface for the EVM calling conventions. The EVM

eth/gasestimator/gasestimator.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,19 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
217217
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
218218

219219
dirtyState = opts.State.Copy()
220-
evm = vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
221220
)
221+
222+
// TODO(kuro): Check if this fee logic is needed.
223+
// Lower the basefee to 0 to avoid breaking EVM
224+
// invariants (basefee < feecap).
225+
// if msgContext.GasPrice.Sign() == 0 {
226+
// evmContext.BaseFee = new(big.Int)
227+
// }
228+
// if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 {
229+
// evmContext.BlobBaseFee = new(big.Int)
230+
// }
231+
evm := vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
232+
222233
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
223234
// a dangling goroutine until the outer estimation finishes, create an internal
224235
// context for the lifetime of this method call.

0 commit comments

Comments
 (0)