mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
return block info except blockhash
This commit is contained in:
parent
c78330d32c
commit
8fff7fd101
2 changed files with 164 additions and 84 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue