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
|
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 {
|
type callResult struct {
|
||||||
ReturnValue hexutil.Bytes `json:"return"`
|
ReturnValue hexutil.Bytes `json:"return"`
|
||||||
Logs []*types.Log `json:"logs"`
|
Logs []*types.Log `json:"logs"`
|
||||||
|
|
@ -1120,14 +1131,14 @@ func (r *callResult) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal((*callResultAlias)(r))
|
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
|
// The transactions are packed into blocks. For each block, block header
|
||||||
// fields can be overridden. The state can also be overridden prior to
|
// fields can be overridden. The state can also be overridden prior to
|
||||||
// execution of each block.
|
// execution of each block.
|
||||||
//
|
//
|
||||||
// Note, this function doesn't make any changes in the state/blockchain and is
|
// Note, this function doesn't make any changes in the state/blockchain and is
|
||||||
// useful to execute and retrieve values.
|
// 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)
|
state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1147,7 +1158,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
|
||||||
// this makes sure resources are cleaned up.
|
// this makes sure resources are cleaned up.
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var (
|
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
|
// Each tx and all the series of txes shouldn't consume more gas than cap
|
||||||
globalGasCap = s.b.RPCGasCap()
|
globalGasCap = s.b.RPCGasCap()
|
||||||
gp = new(core.GasPool).AddGas(globalGasCap)
|
gp = new(core.GasPool).AddGas(globalGasCap)
|
||||||
|
|
@ -1171,7 +1182,16 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, blocks []CallBatch, blo
|
||||||
if block.ECRecoverOverride != nil {
|
if block.ECRecoverOverride != nil {
|
||||||
state.SetCode(common.BytesToAddress([]byte{1}), *block.ECRecoverOverride)
|
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 {
|
for i, call := range block.Calls {
|
||||||
// Hack to get logs from statedb which stores logs by txhash.
|
// Hack to get logs from statedb which stores logs by txhash.
|
||||||
txhash := common.BigToHash(big.NewInt(int64(i)))
|
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)
|
result, err := doCall(ctx, s.b, call, state, header, timeout, gp, &blockContext, vmConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
results[bi][i] = callResult{Error: err.Error()}
|
results[bi].Calls[i] = callResult{Error: err.Error()}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If the result contains a revert reason, try to unpack it.
|
// 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 {
|
if result.Err != nil {
|
||||||
callRes.Error = result.Err.Error()
|
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
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -633,19 +633,29 @@ func TestMulticallV1(t *testing.T) {
|
||||||
latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
includeTransfers = true
|
includeTransfers = true
|
||||||
)
|
)
|
||||||
type res struct {
|
type callRes struct {
|
||||||
ReturnValue string `json:"return"`
|
ReturnValue string `json:"return"`
|
||||||
Error string
|
Error string
|
||||||
Logs []types.Log
|
Logs []types.Log
|
||||||
GasUsed string
|
GasUsed string
|
||||||
Transfers []transfer
|
Transfers []transfer
|
||||||
}
|
}
|
||||||
|
type blockRes struct {
|
||||||
|
Number string
|
||||||
|
Hash string
|
||||||
|
// Ignore timestamp
|
||||||
|
GasLimit string
|
||||||
|
GasUsed string
|
||||||
|
FeeRecipient string
|
||||||
|
BaseFee string
|
||||||
|
Calls []callRes
|
||||||
|
}
|
||||||
var testSuite = []struct {
|
var testSuite = []struct {
|
||||||
blocks []CallBatch
|
blocks []CallBatch
|
||||||
tag rpc.BlockNumberOrHash
|
tag rpc.BlockNumberOrHash
|
||||||
includeTransfers *bool
|
includeTransfers *bool
|
||||||
expectErr error
|
expectErr error
|
||||||
want [][]res
|
want []blockRes
|
||||||
}{
|
}{
|
||||||
// State build-up over calls:
|
// State build-up over calls:
|
||||||
// First value transfer OK after state override.
|
// First value transfer OK after state override.
|
||||||
|
|
@ -666,17 +676,21 @@ func TestMulticallV1(t *testing.T) {
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
want: [][]res{{
|
want: []blockRes{{
|
||||||
res{
|
Number: "0xa",
|
||||||
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
GasLimit: "0x47e7c4",
|
||||||
|
GasUsed: "0xa410",
|
||||||
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
|
Calls: []callRes{{
|
||||||
ReturnValue: "0x",
|
ReturnValue: "0x",
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0x5208",
|
||||||
Logs: []types.Log{},
|
Logs: []types.Log{},
|
||||||
},
|
}, {
|
||||||
res{
|
|
||||||
ReturnValue: "0x",
|
ReturnValue: "0x",
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0x5208",
|
||||||
Logs: []types.Log{},
|
Logs: []types.Log{},
|
||||||
},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
// State build-up over blocks.
|
// State build-up over blocks.
|
||||||
|
|
@ -712,32 +726,38 @@ func TestMulticallV1(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
want: [][]res{
|
want: []blockRes{{
|
||||||
{
|
Number: "0xa",
|
||||||
res{
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
ReturnValue: "0x",
|
GasLimit: "0x47e7c4",
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0xa410",
|
||||||
Logs: []types.Log{},
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
},
|
Calls: []callRes{{
|
||||||
res{
|
ReturnValue: "0x",
|
||||||
ReturnValue: "0x",
|
GasUsed: "0x5208",
|
||||||
GasUsed: "0x5208",
|
Logs: []types.Log{},
|
||||||
Logs: []types.Log{},
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
res{
|
ReturnValue: "0x",
|
||||||
ReturnValue: "0x",
|
GasUsed: "0x5208",
|
||||||
GasUsed: "0x5208",
|
Logs: []types.Log{},
|
||||||
Logs: []types.Log{},
|
}},
|
||||||
},
|
}, {
|
||||||
res{
|
Number: "0xa",
|
||||||
ReturnValue: "0x",
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
GasUsed: "0x0",
|
GasLimit: "0x47e7c4",
|
||||||
Logs: []types.Log{},
|
GasUsed: "0x5208",
|
||||||
Error: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 9937000)", randomAccounts[3].addr.String()),
|
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
|
// Block overrides should work, each call is simulated on a different block number
|
||||||
tag: latest,
|
tag: latest,
|
||||||
|
|
@ -768,18 +788,28 @@ func TestMulticallV1(t *testing.T) {
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
want: [][]res{{
|
want: []blockRes{{
|
||||||
res{
|
Number: "0xb",
|
||||||
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
GasLimit: "0x47e7c4",
|
||||||
|
GasUsed: "0xe891",
|
||||||
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
|
Calls: []callRes{{
|
||||||
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b",
|
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b",
|
||||||
GasUsed: "0xe891",
|
GasUsed: "0xe891",
|
||||||
Logs: []types.Log{},
|
Logs: []types.Log{},
|
||||||
},
|
}},
|
||||||
}, {
|
}, {
|
||||||
res{
|
Number: "0xc",
|
||||||
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
GasLimit: "0x47e7c4",
|
||||||
|
GasUsed: "0xe891",
|
||||||
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
|
Calls: []callRes{{
|
||||||
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
|
ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
|
||||||
GasUsed: "0xe891",
|
GasUsed: "0xe891",
|
||||||
Logs: []types.Log{},
|
Logs: []types.Log{},
|
||||||
},
|
}},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
// Block numbers must be in order.
|
// 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"),
|
expectErr: errors.New("block numbers must be in order"),
|
||||||
},
|
},
|
||||||
// Test on solidity storage example. Set value in one call, read in next.
|
// Test on solidity storage example. Set value in one call, read in next.
|
||||||
|
|
@ -835,15 +865,22 @@ func TestMulticallV1(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
want: [][]res{{{
|
want: []blockRes{{
|
||||||
ReturnValue: "0x",
|
Number: "0xa",
|
||||||
GasUsed: "0xaacc",
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
Logs: []types.Log{},
|
GasLimit: "0x47e7c4",
|
||||||
}, {
|
GasUsed: "0x10683",
|
||||||
ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005",
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
GasUsed: "0x5bb7",
|
Calls: []callRes{{
|
||||||
Logs: []types.Log{},
|
ReturnValue: "0x",
|
||||||
}}},
|
GasUsed: "0xaacc",
|
||||||
|
Logs: []types.Log{},
|
||||||
|
}, {
|
||||||
|
ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005",
|
||||||
|
GasUsed: "0x5bb7",
|
||||||
|
Logs: []types.Log{},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
// Test logs output.
|
// Test logs output.
|
||||||
{
|
{
|
||||||
|
|
@ -867,16 +904,23 @@ func TestMulticallV1(t *testing.T) {
|
||||||
To: &randomAccounts[2].addr,
|
To: &randomAccounts[2].addr,
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
want: [][]res{{{
|
want: []blockRes{{
|
||||||
ReturnValue: "0x",
|
Number: "0xa",
|
||||||
Logs: []types.Log{{
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
Address: randomAccounts[2].addr,
|
GasLimit: "0x47e7c4",
|
||||||
Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")},
|
GasUsed: "0x5508",
|
||||||
BlockNumber: 10,
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
Data: []byte{},
|
Calls: []callRes{{
|
||||||
|
ReturnValue: "0x",
|
||||||
|
Logs: []types.Log{{
|
||||||
|
Address: randomAccounts[2].addr,
|
||||||
|
Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")},
|
||||||
|
BlockNumber: 10,
|
||||||
|
Data: []byte{},
|
||||||
|
}},
|
||||||
|
GasUsed: "0x5508",
|
||||||
}},
|
}},
|
||||||
GasUsed: "0x5508",
|
}},
|
||||||
}}},
|
|
||||||
},
|
},
|
||||||
// Test ecrecover override
|
// Test ecrecover override
|
||||||
{
|
{
|
||||||
|
|
@ -926,12 +970,19 @@ func TestMulticallV1(t *testing.T) {
|
||||||
To: &randomAccounts[2].addr,
|
To: &randomAccounts[2].addr,
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
want: [][]res{{{
|
want: []blockRes{{
|
||||||
// Caller is in this case the contract that invokes ecrecover.
|
Number: "0xa",
|
||||||
ReturnValue: strings.ToLower(randomAccounts[2].addr.String()),
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
GasUsed: "0x52f6",
|
GasLimit: "0x47e7c4",
|
||||||
Logs: []types.Log{},
|
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.
|
// Test ether transfers.
|
||||||
{
|
{
|
||||||
|
|
@ -962,22 +1013,29 @@ func TestMulticallV1(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
includeTransfers: &includeTransfers,
|
includeTransfers: &includeTransfers,
|
||||||
want: [][]res{{{
|
want: []blockRes{{
|
||||||
ReturnValue: "0x",
|
Number: "0xa",
|
||||||
GasUsed: "0xd984",
|
Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
Transfers: []transfer{
|
GasLimit: "0x47e7c4",
|
||||||
{
|
GasUsed: "0xd984",
|
||||||
From: accounts[0].addr,
|
FeeRecipient: "0x0000000000000000000000000000000000000000",
|
||||||
To: randomAccounts[0].addr,
|
Calls: []callRes{{
|
||||||
Value: big.NewInt(50),
|
ReturnValue: "0x",
|
||||||
}, {
|
GasUsed: "0xd984",
|
||||||
From: randomAccounts[0].addr,
|
Transfers: []transfer{
|
||||||
To: randomAccounts[1].addr,
|
{
|
||||||
Value: big.NewInt(100),
|
From: accounts[0].addr,
|
||||||
|
To: randomAccounts[0].addr,
|
||||||
|
Value: big.NewInt(50),
|
||||||
|
}, {
|
||||||
|
From: randomAccounts[0].addr,
|
||||||
|
To: randomAccounts[1].addr,
|
||||||
|
Value: big.NewInt(100),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
Logs: []types.Log{},
|
||||||
Logs: []types.Log{},
|
}},
|
||||||
}}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1001,7 +1059,7 @@ func TestMulticallV1(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Turn result into res-struct
|
// Turn result into res-struct
|
||||||
var have [][]res
|
var have []blockRes
|
||||||
resBytes, _ := json.Marshal(result)
|
resBytes, _ := json.Marshal(result)
|
||||||
if err := json.Unmarshal(resBytes, &have); err != nil {
|
if err := json.Unmarshal(resBytes, &have); err != nil {
|
||||||
t.Fatalf("failed to unmarshal result: %v", err)
|
t.Fatalf("failed to unmarshal result: %v", err)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue