internal/ethapi: fix prev hashes in eth_simulate

This commit is contained in:
Sina Mahmoodi 2025-02-03 14:38:36 +01:00
parent fc12dbe40b
commit 71b86a994e
3 changed files with 42 additions and 10 deletions

View File

@ -770,7 +770,7 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN
//
// Note, this function doesn't make any changes in the state/blockchain and is
// useful to execute and retrieve values.
func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]*simBlockResult, error) {
if len(opts.BlockStateCalls) == 0 {
return nil, &invalidParamsError{message: "empty input"}
} else if len(opts.BlockStateCalls) > maxSimulateBlocks {

View File

@ -73,6 +73,19 @@ func (r *simCallResult) MarshalJSON() ([]byte, error) {
return json.Marshal((*callResultAlias)(r))
}
// simBlockResult is the result of a simulated block.
type simBlockResult struct {
sim *simulator
Block *types.Block
Calls []simCallResult
}
func (r *simBlockResult) MarshalJSON() ([]byte, error) {
blockData := RPCMarshalBlock(r.Block, true, r.sim.fullTx, r.sim.chainConfig)
blockData["calls"] = r.Calls
return json.Marshal(blockData)
}
// simOpts are the inputs to eth_simulateV1.
type simOpts struct {
BlockStateCalls []simBlock
@ -95,7 +108,7 @@ type simulator struct {
}
// execute runs the simulation of a series of blocks.
func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[string]interface{}, error) {
func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlockResult, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
@ -123,19 +136,21 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str
return nil, err
}
var (
results = make([]map[string]interface{}, len(blocks))
results = make([]*simBlockResult, len(blocks))
// prevHeaders is the header for all previously simulated blocks.
// It is "filled" compared to the barebone header available prior to execution.
// It will be used for serving the BLOCKHASH opcode.
prevHeaders = make([]*types.Header, 0, len(blocks))
parent = sim.base
)
for bi, block := range blocks {
result, callResults, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout)
result, callResults, err := sim.processBlock(ctx, &block, headers[bi], parent, prevHeaders, timeout)
if err != nil {
return nil, err
}
enc := RPCMarshalBlock(result, true, sim.fullTx, sim.chainConfig)
enc["calls"] = callResults
results[bi] = enc
parent = headers[bi]
results[bi] = &simBlockResult{sim: sim, Block: result, Calls: callResults}
parent = result.Header()
prevHeaders = append(prevHeaders, parent)
}
return results, nil
}

View File

@ -17,9 +17,11 @@
package ethapi
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi/override"
@ -119,3 +121,18 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
func newInt(n int64) *hexutil.Big {
return (*hexutil.Big)(big.NewInt(n))
}
func TestHeaderPassing(t *testing.T) {
sl := []*types.Header{new(types.Header)}
procHeader(sl[0])
fmt.Printf("sl[0].Number: %v\n", sl[0].Number)
fmt.Printf("sl[0].ParentHash: %v\n", sl[0].ParentHash)
if sl[0].Number.Cmp(big.NewInt(100)) != 0 {
t.Errorf("Header not processed")
}
}
func procHeader(h *types.Header) {
h.Number = big.NewInt(100)
h.ParentHash = common.HexToHash("0x1")
}