mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
add transfers
This commit is contained in:
parent
4478f20135
commit
2ae2fe50d0
3 changed files with 72 additions and 13 deletions
|
|
@ -1105,6 +1105,7 @@ type CallBatch struct {
|
||||||
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"`
|
||||||
|
Transfers []transfer `json:"transfers,omitempty"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
@ -1116,12 +1117,11 @@ type callResult struct {
|
||||||
//
|
//
|
||||||
// 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) Multicall(ctx context.Context, blocks []CallBatch, blockNrOrHash rpc.BlockNumberOrHash) ([][]callResult, error) {
|
func (s *BlockChainAPI) Multicall(ctx context.Context, blocks []CallBatch, blockNrOrHash rpc.BlockNumberOrHash, includeTransfers *bool) ([][]callResult, 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup context so it may be cancelled before the calls completed
|
// Setup context so it may be cancelled before the calls completed
|
||||||
// or, in case of unmetered gas, setup a context with a timeout.
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
var (
|
var (
|
||||||
|
|
@ -1166,7 +1166,14 @@ func (s *BlockChainAPI) Multicall(ctx context.Context, blocks []CallBatch, block
|
||||||
// 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)))
|
||||||
state.SetTxContext(txhash, i)
|
state.SetTxContext(txhash, i)
|
||||||
result, err := doCall(ctx, s.b, call, state, header, timeout, gp, &blockContext, &vm.Config{NoBaseFee: true, DisableECRecover: true})
|
vmConfig := &vm.Config{NoBaseFee: true}
|
||||||
|
if block.ECRecoverOverride != nil {
|
||||||
|
vmConfig.DisableECRecover = true
|
||||||
|
}
|
||||||
|
if includeTransfers != nil && *includeTransfers {
|
||||||
|
vmConfig.Tracer = newTracer()
|
||||||
|
}
|
||||||
|
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][i] = callResult{Error: err.Error()}
|
||||||
continue
|
continue
|
||||||
|
|
@ -1180,7 +1187,11 @@ func (s *BlockChainAPI) Multicall(ctx context.Context, blocks []CallBatch, block
|
||||||
for _, l := range logs {
|
for _, l := range logs {
|
||||||
l.TxHash = common.Hash{}
|
l.TxHash = common.Hash{}
|
||||||
}
|
}
|
||||||
callRes := callResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)}
|
var transfers []transfer
|
||||||
|
if includeTransfers != nil && *includeTransfers {
|
||||||
|
transfers = vmConfig.Tracer.(*tracer).Transfers()
|
||||||
|
}
|
||||||
|
callRes := callResult{ReturnValue: result.Return(), Logs: logs, Transfers: transfers, GasUsed: hexutil.Uint64(result.UsedGas)}
|
||||||
if result.Err != nil {
|
if result.Err != nil {
|
||||||
callRes.Error = result.Err.Error()
|
callRes.Error = result.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -629,20 +629,23 @@ func TestMulticall(t *testing.T) {
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
}))
|
}))
|
||||||
var (
|
var (
|
||||||
randomAccounts = newAccounts(4)
|
randomAccounts = newAccounts(4)
|
||||||
latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
|
includeTransfers = true
|
||||||
)
|
)
|
||||||
type res struct {
|
type res 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
|
||||||
}
|
}
|
||||||
var testSuite = []struct {
|
var testSuite = []struct {
|
||||||
blocks []CallBatch
|
blocks []CallBatch
|
||||||
tag rpc.BlockNumberOrHash
|
tag rpc.BlockNumberOrHash
|
||||||
expectErr error
|
includeTransfers *bool
|
||||||
want [][]res
|
expectErr error
|
||||||
|
want [][]res
|
||||||
}{
|
}{
|
||||||
// State build-up over calls:
|
// State build-up over calls:
|
||||||
// First value transfer OK after state override.
|
// First value transfer OK after state override.
|
||||||
|
|
@ -919,10 +922,55 @@ func TestMulticall(t *testing.T) {
|
||||||
GasUsed: "0x52f6",
|
GasUsed: "0x52f6",
|
||||||
}}},
|
}}},
|
||||||
},
|
},
|
||||||
|
// Test ether transfers.
|
||||||
|
{
|
||||||
|
tag: latest,
|
||||||
|
blocks: []CallBatch{{
|
||||||
|
StateOverrides: &StateOverride{
|
||||||
|
randomAccounts[0].addr: OverrideAccount{
|
||||||
|
Balance: newRPCBalance(big.NewInt(100)),
|
||||||
|
// Yul code that transfers 100 wei to address passed in calldata:
|
||||||
|
// object "Test" {
|
||||||
|
// code {
|
||||||
|
// let recipient := shr(96, calldataload(0))
|
||||||
|
// let value := 100
|
||||||
|
// let success := call(gas(), recipient, value, 0, 0, 0, 0)
|
||||||
|
// if eq(success, 0) {
|
||||||
|
// revert(0, 0)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Code: hex2Bytes("60003560601c606460008060008084865af160008103601d57600080fd5b505050"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Calls: []TransactionArgs{{
|
||||||
|
From: &accounts[0].addr,
|
||||||
|
To: &randomAccounts[0].addr,
|
||||||
|
Value: (*hexutil.Big)(big.NewInt(50)),
|
||||||
|
Input: hex2Bytes(strings.TrimPrefix(randomAccounts[1].addr.String(), "0x")),
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
includeTransfers: &includeTransfers,
|
||||||
|
want: [][]res{{{
|
||||||
|
ReturnValue: "0x",
|
||||||
|
GasUsed: "0xd984",
|
||||||
|
Transfers: []transfer{
|
||||||
|
{
|
||||||
|
From: accounts[0].addr,
|
||||||
|
To: randomAccounts[0].addr,
|
||||||
|
Value: big.NewInt(50),
|
||||||
|
}, {
|
||||||
|
From: randomAccounts[0].addr,
|
||||||
|
To: randomAccounts[1].addr,
|
||||||
|
Value: big.NewInt(100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range testSuite {
|
for i, tc := range testSuite {
|
||||||
result, err := api.Multicall(context.Background(), tc.blocks, tc.tag)
|
result, err := api.Multicall(context.Background(), tc.blocks, tc.tag, tc.includeTransfers)
|
||||||
if tc.expectErr != nil {
|
if tc.expectErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
||||||
|
|
|
||||||
|
|
@ -614,8 +614,8 @@ web3._extend({
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'multicall',
|
name: 'multicall',
|
||||||
call: 'eth_multicall',
|
call: 'eth_multicall',
|
||||||
params: 2,
|
params: 3,
|
||||||
inputFormatter: [null, web3._extend.formatters.inputDefaultBlockNumberFormatter],
|
inputFormatter: [null, web3._extend.formatters.inputDefaultBlockNumberFormatter, null],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
properties: [
|
properties: [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue