return full header

This commit is contained in:
Sina Mahmoodi 2024-05-28 21:45:43 +02:00
parent 263cfd76e3
commit e3827828fd
3 changed files with 123 additions and 159 deletions

View file

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

View file

@ -1110,7 +1110,7 @@ func TestSimulateV1(t *testing.T) {
// Ignore timestamp
GasLimit string
GasUsed string
FeeRecipient string
Miner string
BaseFee string
Calls []callRes
}
@ -1149,7 +1149,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xf618",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
@ -1202,7 +1202,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xa410",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
@ -1218,7 +1218,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xc",
GasLimit: "0x47e7c4",
GasUsed: "0x5208",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
@ -1256,7 +1256,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x47e7c4",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
Error: callErr{Message: "stack underflow (0 <=> 2)", Code: errCodeVMError},
@ -1301,7 +1301,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xe891",
FeeRecipient: strings.ToLower(cac.String()),
Miner: strings.ToLower(cac.String()),
Calls: []callRes{{
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b",
GasUsed: "0xe891",
@ -1312,7 +1312,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xc",
GasLimit: "0x47e7c4",
GasUsed: "0xe891",
FeeRecipient: strings.ToLower(cac.String()),
Miner: strings.ToLower(cac.String()),
Calls: []callRes{{
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
GasUsed: "0xe891",
@ -1380,7 +1380,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x10683",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xaacc",
@ -1421,7 +1421,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x5508",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
Logs: []log{{
@ -1489,7 +1489,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x52f6",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
// Caller is in this case the contract that invokes ecrecover.
ReturnValue: strings.ToLower(randomAccounts[2].addr.String()),
@ -1539,7 +1539,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xa58c",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5",
GasUsed: "0x52dc",
@ -1587,7 +1587,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xd984",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xd984",
@ -1653,7 +1653,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x1b83f",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xd166",
@ -1669,7 +1669,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xc",
GasLimit: "0x47e7c4",
GasUsed: "0xe6d9",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xe6d9",
@ -1716,7 +1716,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x5208",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
@ -1768,7 +1768,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0xc542",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x0000000000000000000000000000000200000000000000000000000000000003",
GasUsed: "0x62a1",
@ -1784,7 +1784,7 @@ func TestSimulateV1(t *testing.T) {
Number: "0xc",
GasLimit: "0x47e7c4",
GasUsed: "0x62a1",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x0000000000000000000000000000000500000000000000000000000000000000",
GasUsed: "0x62a1",
@ -1841,13 +1841,13 @@ func TestSimulateV1(t *testing.T) {
Number: "0xb",
GasLimit: "0x47e7c4",
GasUsed: "0x0",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{},
}, {
Number: "0xc",
GasLimit: "0x47e7c4",
GasUsed: "0xf864",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x52cc",
@ -1869,25 +1869,25 @@ func TestSimulateV1(t *testing.T) {
Number: "0xd",
GasLimit: "0x47e7c4",
GasUsed: "0x0",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{},
}, {
Number: "0xe",
GasLimit: "0x47e7c4",
GasUsed: "0x0",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{},
}, {
Number: "0xf",
GasLimit: "0x47e7c4",
GasUsed: "0x0",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{},
}, {
Number: "0x10",
GasLimit: "0x47e7c4",
GasUsed: "0xa598",
FeeRecipient: coinbase,
Miner: coinbase,
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x52cc",

View file

@ -50,53 +50,6 @@ type simBlock struct {
Calls []TransactionArgs
}
type simBlockResult struct {
Number hexutil.Uint64 `json:"number"`
Hash common.Hash `json:"hash"`
Time hexutil.Uint64 `json:"timestamp"`
GasLimit hexutil.Uint64 `json:"gasLimit"`
GasUsed hexutil.Uint64 `json:"gasUsed"`
FeeRecipient common.Address `json:"feeRecipient"`
BaseFee *hexutil.Big `json:"baseFeePerGas"`
PrevRandao common.Hash `json:"prevRandao"`
Withdrawals types.Withdrawals `json:"withdrawals"`
BlobGasUsed hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas hexutil.Uint64 `json:"excessBlobGas"`
Calls []simCallResult `json:"calls"`
}
func simBlockResultFromHeader(header *types.Header, callResults []simCallResult) simBlockResult {
r := simBlockResult{
Number: hexutil.Uint64(header.Number.Uint64()),
Hash: header.Hash(),
Time: hexutil.Uint64(header.Time),
GasLimit: hexutil.Uint64(header.GasLimit),
GasUsed: hexutil.Uint64(header.GasUsed),
FeeRecipient: header.Coinbase,
BaseFee: (*hexutil.Big)(header.BaseFee),
PrevRandao: header.MixDigest,
// Withdrawals will be always empty in the context of a simulated block.
Withdrawals: make(types.Withdrawals, 0),
Calls: callResults,
}
if header.BlobGasUsed != nil && header.ExcessBlobGas != nil {
r.BlobGasUsed = hexutil.Uint64(*header.BlobGasUsed)
r.ExcessBlobGas = hexutil.Uint64(*header.ExcessBlobGas)
}
return r
}
// repairLogs updates the block hash in the logs present in the result of
// a simulated block. This is needed as during execution when logs are collected
// the block hash is not known.
func (b *simBlockResult) repairLogs() {
for i := range b.Calls {
for j := range b.Calls[i].Logs {
b.Calls[i].Logs[j].BlockHash = b.Hash
}
}
}
type simCallResult struct {
ReturnValue hexutil.Bytes `json:"returnData"`
Logs []*types.Log `json:"logs"`
@ -129,7 +82,7 @@ type simulator struct {
validate bool
}
func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]simBlockResult, error) {
func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[string]interface{}, error) {
// Setup context so it may be cancelled before the calls completed
// or, in case of unmetered gas, setup a context with a timeout.
var (
@ -155,7 +108,7 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]simBloc
return nil, err
}
var (
results = make([]simBlockResult, len(blocks))
results = make([]map[string]interface{}, len(blocks))
// Each tx and all the series of txes shouldn't consume more gas than cap
gp = new(core.GasPool).AddGas(sim.b.RPCGasCap())
precompiles = sim.activePrecompiles(ctx, sim.base)
@ -169,13 +122,13 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]simBloc
if err != nil {
return nil, err
}
results[bi] = *result
results[bi] = result
parent = headers[bi]
}
return results, nil
}
func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, gp *core.GasPool, precompiles vm.PrecompiledContracts, timeout time.Duration) (*simBlockResult, error) {
func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, gp *core.GasPool, precompiles vm.PrecompiledContracts, timeout time.Duration) (map[string]interface{}, error) {
// Set header fields that depend only on parent block.
config := sim.b.ChainConfig()
// Parent hash is needed for evm.GetHashFn to work.
@ -272,19 +225,30 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
}
header.Root = sim.state.IntermediateRoot(true)
header.GasUsed = gasUsed
if len(txes) > 0 {
header.TxHash = types.DeriveSha(types.Transactions(txes), trie.NewStackTrie(nil))
}
if len(receipts) > 0 {
header.ReceiptHash = types.DeriveSha(types.Receipts(receipts), trie.NewStackTrie(nil))
header.Bloom = types.CreateBloom(types.Receipts(receipts))
}
if config.IsCancun(header.Number, header.Time) {
header.BlobGasUsed = &blobGasUsed
}
result := simBlockResultFromHeader(header, callResults)
result.repairLogs()
return &result, nil
var withdrawals types.Withdrawals
if config.IsShanghai(header.Number, header.Time) {
withdrawals = make([]*types.Withdrawal, 0)
}
b := types.NewBlockWithWithdrawals(header, txes, nil, receipts, withdrawals, trie.NewStackTrie(nil))
res := RPCMarshalBlock(b, true, false, config)
repairLogs(callResults, res["hash"].(common.Hash))
res["calls"] = callResults
return res, nil
}
// repairLogs updates the block hash in the logs present in the result of
// a simulated block. This is needed as during execution when logs are collected
// the block hash is not known.
func repairLogs(calls []simCallResult, hash common.Hash) {
for i := range calls {
for j := range calls[i].Logs {
calls[i].Logs[j].BlockHash = hash
}
}
}
func (sim *simulator) sanitizeCall(call *TransactionArgs, state *state.StateDB, gasUsed *uint64, blockContext vm.BlockContext) error {