diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e1a5fdec00..c061b1700c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1247,31 +1247,26 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. defer cancel() + blockContexts, err := makeBlockContexts(ctx, s.b, blocks, header) + if err != nil { + return nil, err + } var ( results = make([]blockResult, len(blocks)) // Each tx and all the series of txes shouldn't consume more gas than cap globalGasCap = s.b.RPCGasCap() gp = new(core.GasPool).AddGas(globalGasCap) - prevNumber = header.Number.Uint64() blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil) rules = s.b.ChainConfig().Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time) precompiles = vm.ActivePrecompiledContracts(rules).Copy() ) for bi, block := range blocks { - blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil) - if block.BlockOverrides != nil { - block.BlockOverrides.Apply(&blockContext) - } - // TODO: Consider hoisting this check up - if blockContext.BlockNumber.Uint64() < prevNumber { - return nil, fmt.Errorf("block numbers must be in order") - } - prevNumber = blockContext.BlockNumber.Uint64() + blockContext = blockContexts[bi] + hash := crypto.Keccak256Hash(blockContext.BlockNumber.Bytes()) // State overrides are applied prior to execution of a block if err := block.StateOverrides.ApplyMulticall(state, precompiles); err != nil { return nil, err } - hash := crypto.Keccak256Hash(blockContext.BlockNumber.Bytes()) results[bi] = blockResult{ Number: hexutil.Uint64(blockContext.BlockNumber.Uint64()), Hash: hash, @@ -1324,6 +1319,39 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo return results, nil } +func makeBlockContexts(ctx context.Context, b Backend, blocks []CallBatch, header *types.Header) ([]vm.BlockContext, error) { + res := make([]vm.BlockContext, len(blocks)) + var ( + prevNumber = header.Number.Uint64() + prevTimestamp = header.Time + ) + for bi, block := range blocks { + blockContext := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) + if block.BlockOverrides == nil { + block.BlockOverrides = new(BlockOverrides) + } + if block.BlockOverrides.Number == nil { + n := new(big.Int).Add(big.NewInt(int64(prevNumber)), big.NewInt(1)) + block.BlockOverrides.Number = (*hexutil.Big)(n) + } + if block.BlockOverrides.Time == nil { + t := prevTimestamp + 1 + block.BlockOverrides.Time = (*hexutil.Uint64)(&t) + } + block.BlockOverrides.Apply(&blockContext) + if blockContext.BlockNumber.Uint64() <= prevNumber { + return nil, fmt.Errorf("block numbers must be in order") + } + prevNumber = blockContext.BlockNumber.Uint64() + if blockContext.Time <= prevTimestamp { + return nil, fmt.Errorf("timestamps must be in order") + } + prevTimestamp = blockContext.Time + res[bi] = blockContext + } + return res, nil +} + func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap uint64) (hexutil.Uint64, error) { // Binary search the gas requirement, as it may be higher than the amount used var ( diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 42a3a1f2ca..bb4296436a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -682,7 +682,7 @@ func TestMulticallV1(t *testing.T) { }, }, } - n10hash = crypto.Keccak256Hash([]byte{0xa}).Hex() + n11hash = crypto.Keccak256Hash([]byte{0xb}).Hex() sha256Address = common.BytesToAddress([]byte{0x02}) ) api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { @@ -754,8 +754,8 @@ func TestMulticallV1(t *testing.T) { }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xa410", FeeRecipient: coinbase, @@ -807,8 +807,8 @@ func TestMulticallV1(t *testing.T) { }, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xa410", FeeRecipient: coinbase, @@ -824,8 +824,8 @@ func TestMulticallV1(t *testing.T) { Status: "0x1", }}, }, { - Number: "0xa", - Hash: n10hash, + Number: "0xc", + Hash: crypto.Keccak256Hash([]byte{0xc}).Hex(), GasLimit: "0x47e7c4", GasUsed: "0x5208", FeeRecipient: coinbase, @@ -876,7 +876,7 @@ func TestMulticallV1(t *testing.T) { }}, want: []blockRes{{ Number: "0xb", - Hash: crypto.Keccak256Hash([]byte{0xb}).Hex(), + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xe891", FeeRecipient: strings.ToLower(cac.String()), @@ -956,8 +956,8 @@ func TestMulticallV1(t *testing.T) { }, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0x10683", FeeRecipient: coinbase, @@ -998,8 +998,8 @@ func TestMulticallV1(t *testing.T) { }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0x5508", FeeRecipient: coinbase, @@ -1008,7 +1008,7 @@ func TestMulticallV1(t *testing.T) { Logs: []types.Log{{ Address: randomAccounts[2].addr, Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, - BlockNumber: 10, + BlockNumber: 11, Data: []byte{}, }}, GasUsed: "0x5508", @@ -1061,15 +1061,14 @@ func TestMulticallV1(t *testing.T) { Code: hex2Bytes("33806000526014600cf3"), }, }, - BlockOverrides: &BlockOverrides{}, Calls: []TransactionArgs{{ From: &randomAccounts[0].addr, To: &randomAccounts[2].addr, }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0x52f6", FeeRecipient: coinbase, @@ -1119,8 +1118,8 @@ func TestMulticallV1(t *testing.T) { }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xa58c", FeeRecipient: coinbase, @@ -1168,8 +1167,8 @@ func TestMulticallV1(t *testing.T) { }}, includeTransfers: &includeTransfers, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xd984", FeeRecipient: coinbase, @@ -1227,8 +1226,8 @@ func TestMulticallV1(t *testing.T) { }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0x1b83f", FeeRecipient: coinbase, @@ -1244,8 +1243,8 @@ func TestMulticallV1(t *testing.T) { Status: "0x1", }}, }, { - Number: "0xa", - Hash: n10hash, + Number: "0xc", + Hash: crypto.Keccak256Hash([]byte{0xc}).Hex(), GasLimit: "0x47e7c4", GasUsed: "0xe6d9", FeeRecipient: coinbase, @@ -1270,8 +1269,8 @@ func TestMulticallV1(t *testing.T) { }}, validation: &validation, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0x0", FeeRecipient: coinbase, @@ -1324,8 +1323,8 @@ func TestMulticallV1(t *testing.T) { }}, }}, want: []blockRes{{ - Number: "0xa", - Hash: n10hash, + Number: "0xb", + Hash: n11hash, GasLimit: "0x47e7c4", GasUsed: "0xc542", FeeRecipient: coinbase, @@ -1341,8 +1340,8 @@ func TestMulticallV1(t *testing.T) { Status: "0x1", }}, }, { - Number: "0xa", - Hash: n10hash, + Number: "0xc", + Hash: crypto.Keccak256Hash([]byte{0xc}).Hex(), GasLimit: "0x47e7c4", GasUsed: "0x62a1", FeeRecipient: coinbase,