return block info except blockhash

This commit is contained in:
Sina Mahmoodi 2023-07-03 18:07:36 +02:00
parent c78330d32c
commit 8fff7fd101
2 changed files with 164 additions and 84 deletions

View file

@ -1103,6 +1103,17 @@ type CallBatch struct {
Calls []TransactionArgs
}
type blockResult 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"`
Calls []callResult `json:"calls"`
}
type callResult struct {
ReturnValue hexutil.Bytes `json:"return"`
Logs []*types.Log `json:"logs"`
@ -1120,14 +1131,14 @@ func (r *callResult) MarshalJSON() ([]byte, error) {
return json.Marshal((*callResultAlias)(r))
}
// Multicall executes series of transactions on top of a base state.
// MulticallV1 executes series of transactions on top of a base state.
// The transactions are packed into blocks. For each block, block header
// fields can be overridden. The state can also be overridden prior to
// execution of each block.
//
// Note, this function doesn't make any changes in the state/blockchain and is
// useful to execute and retrieve values.
func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blockNrOrHash rpc.BlockNumberOrHash, includeTransfers *bool) ([][]callResult, error) {
func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blockNrOrHash rpc.BlockNumberOrHash, includeTransfers *bool) ([]blockResult, error) {
state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
@ -1147,7 +1158,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
// this makes sure resources are cleaned up.
defer cancel()
var (
results = make([][]callResult, len(blocks))
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)
@ -1171,7 +1182,16 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
if block.ECRecoverOverride != nil {
state.SetCode(common.BytesToAddress([]byte{1}), *block.ECRecoverOverride)
}
results[bi] = make([]callResult, len(block.Calls))
results[bi] = blockResult{
Number: hexutil.Uint64(blockContext.BlockNumber.Uint64()),
Hash: common.Hash{}, // TODO
Time: hexutil.Uint64(blockContext.Time),
GasLimit: hexutil.Uint64(blockContext.GasLimit),
FeeRecipient: blockContext.Coinbase,
BaseFee: (*hexutil.Big)(blockContext.BaseFee),
Calls: make([]callResult, len(block.Calls)),
}
gasUsed := uint64(0)
for i, call := range block.Calls {
// Hack to get logs from statedb which stores logs by txhash.
txhash := common.BigToHash(big.NewInt(int64(i)))
@ -1185,7 +1205,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
}
result, err := doCall(ctx, s.b, call, state, header, timeout, gp, &blockContext, vmConfig)
if err != nil {
results[bi][i] = callResult{Error: err.Error()}
results[bi].Calls[i] = callResult{Error: err.Error()}
continue
}
// If the result contains a revert reason, try to unpack it.
@ -1205,8 +1225,10 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
if result.Err != nil {
callRes.Error = result.Err.Error()
}
results[bi][i] = callRes
results[bi].Calls[i] = callRes
gasUsed += result.UsedGas
}
results[bi].GasUsed = hexutil.Uint64(gasUsed)
}
return results, nil
}

View file

@ -633,19 +633,29 @@ func TestMulticallV1(t *testing.T) {
latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
includeTransfers = true
)
type res struct {
type callRes struct {
ReturnValue string `json:"return"`
Error string
Logs []types.Log
GasUsed string
Transfers []transfer
}
type blockRes struct {
Number string
Hash string
// Ignore timestamp
GasLimit string
GasUsed string
FeeRecipient string
BaseFee string
Calls []callRes
}
var testSuite = []struct {
blocks []CallBatch
tag rpc.BlockNumberOrHash
includeTransfers *bool
expectErr error
want [][]res
want []blockRes
}{
// State build-up over calls:
// First value transfer OK after state override.
@ -666,17 +676,21 @@ func TestMulticallV1(t *testing.T) {
Value: (*hexutil.Big)(big.NewInt(1000)),
}},
}},
want: [][]res{{
res{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0xa410",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
},
res{
}, {
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
},
}},
}},
}, {
// State build-up over blocks.
@ -712,32 +726,38 @@ func TestMulticallV1(t *testing.T) {
},
},
}},
want: [][]res{
{
res{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0xa410",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
},
res{
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
},
}, {
res{
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
},
res{
}},
}, {
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0x5208",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0x5208",
Logs: []types.Log{},
}, {
ReturnValue: "0x",
GasUsed: "0x0",
Logs: []types.Log{},
Error: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 9937000)", randomAccounts[3].addr.String()),
},
},
},
}},
}},
}, {
// Block overrides should work, each call is simulated on a different block number
tag: latest,
@ -768,18 +788,28 @@ func TestMulticallV1(t *testing.T) {
},
}},
}},
want: [][]res{{
res{
want: []blockRes{{
Number: "0xb",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0xe891",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b",
GasUsed: "0xe891",
Logs: []types.Log{},
},
}},
}, {
res{
Number: "0xc",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0xe891",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
GasUsed: "0xe891",
Logs: []types.Log{},
},
}},
}},
},
// Block numbers must be in order.
@ -810,7 +840,7 @@ func TestMulticallV1(t *testing.T) {
},
}},
}},
want: [][]res{},
want: []blockRes{},
expectErr: errors.New("block numbers must be in order"),
},
// Test on solidity storage example. Set value in one call, read in next.
@ -835,7 +865,13 @@ func TestMulticallV1(t *testing.T) {
},
},
}},
want: [][]res{{{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0x10683",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xaacc",
Logs: []types.Log{},
@ -843,7 +879,8 @@ func TestMulticallV1(t *testing.T) {
ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005",
GasUsed: "0x5bb7",
Logs: []types.Log{},
}}},
}},
}},
},
// Test logs output.
{
@ -867,7 +904,13 @@ func TestMulticallV1(t *testing.T) {
To: &randomAccounts[2].addr,
}},
}},
want: [][]res{{{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0x5508",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
Logs: []types.Log{{
Address: randomAccounts[2].addr,
@ -876,7 +919,8 @@ func TestMulticallV1(t *testing.T) {
Data: []byte{},
}},
GasUsed: "0x5508",
}}},
}},
}},
},
// Test ecrecover override
{
@ -926,12 +970,19 @@ func TestMulticallV1(t *testing.T) {
To: &randomAccounts[2].addr,
}},
}},
want: [][]res{{{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0x52f6",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
// Caller is in this case the contract that invokes ecrecover.
ReturnValue: strings.ToLower(randomAccounts[2].addr.String()),
GasUsed: "0x52f6",
Logs: []types.Log{},
}}},
}},
}},
},
// Test ether transfers.
{
@ -962,7 +1013,13 @@ func TestMulticallV1(t *testing.T) {
}},
}},
includeTransfers: &includeTransfers,
want: [][]res{{{
want: []blockRes{{
Number: "0xa",
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
GasLimit: "0x47e7c4",
GasUsed: "0xd984",
FeeRecipient: "0x0000000000000000000000000000000000000000",
Calls: []callRes{{
ReturnValue: "0x",
GasUsed: "0xd984",
Transfers: []transfer{
@ -977,7 +1034,8 @@ func TestMulticallV1(t *testing.T) {
},
},
Logs: []types.Log{},
}}},
}},
}},
},
}
@ -1001,7 +1059,7 @@ func TestMulticallV1(t *testing.T) {
continue
}
// Turn result into res-struct
var have [][]res
var have []blockRes
resBytes, _ := json.Marshal(result)
if err := json.Unmarshal(resBytes, &have); err != nil {
t.Fatalf("failed to unmarshal result: %v", err)