mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
This commit is contained in:
parent
1b561493fb
commit
900b333241
4 changed files with 108 additions and 32 deletions
|
|
@ -83,6 +83,11 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash
|
|||
var cache []common.Hash
|
||||
|
||||
return func(n uint64) common.Hash {
|
||||
if ref.Number.Uint64() <= n {
|
||||
// This situation can happen if we're doing tracing and using
|
||||
// block overrides.
|
||||
return common.Hash{}
|
||||
}
|
||||
// If there's no hash cache yet, make one
|
||||
if len(cache) == 0 {
|
||||
cache = append(cache, ref.ParentHash)
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ type TraceConfig struct {
|
|||
type TraceCallConfig struct {
|
||||
TraceConfig
|
||||
StateOverrides *ethapi.StateOverride
|
||||
BlockOverrides *ethapi.BlockOverrides
|
||||
}
|
||||
|
||||
// txTraceResult is the result of a single transaction trace.
|
||||
|
|
@ -665,7 +666,6 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||
// created during the execution of EVM if the given transaction was added on
|
||||
// top of the provided block and returns them as a JSON object.
|
||||
// You can provide -2 as a block number to trace on top of the pending block.
|
||||
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
||||
// Try to retrieve the specified block
|
||||
var (
|
||||
|
|
@ -699,11 +699,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Apply the customized state rules if required.
|
||||
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
// Apply the customization rules if required.
|
||||
if config != nil {
|
||||
if err := config.StateOverrides.Apply(statedb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.BlockOverrides.Apply(&vmctx)
|
||||
}
|
||||
// Execute the trace
|
||||
// TODO(daniel): replace block.BaseFee() with vmctx.BaseFee
|
||||
|
|
@ -712,7 +714,6 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
var traceConfig *TraceConfig
|
||||
if config != nil {
|
||||
traceConfig = &config.TraceConfig
|
||||
|
|
|
|||
|
|
@ -207,13 +207,12 @@ func TestTraceCall(t *testing.T) {
|
|||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
||||
b.AddTx(tx)
|
||||
}))
|
||||
|
||||
var testSuite = []struct {
|
||||
blockNumber rpc.BlockNumber
|
||||
call ethapi.TransactionArgs
|
||||
config *TraceCallConfig
|
||||
expectErr error
|
||||
expect interface{}
|
||||
expect string
|
||||
}{
|
||||
// Standard JSON trace upon the genesis, plain transfer.
|
||||
{
|
||||
|
|
@ -225,12 +224,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: &logger.ExecutionResult{
|
||||
Gas: params.TxGas,
|
||||
Failed: false,
|
||||
ReturnValue: "",
|
||||
StructLogs: []logger.StructLogRes{},
|
||||
},
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the head, plain transfer.
|
||||
{
|
||||
|
|
@ -242,12 +236,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: &logger.ExecutionResult{
|
||||
Gas: params.TxGas,
|
||||
Failed: false,
|
||||
ReturnValue: "",
|
||||
StructLogs: []logger.StructLogRes{},
|
||||
},
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the non-existent block, error expects
|
||||
{
|
||||
|
|
@ -259,7 +248,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
|
||||
expect: nil,
|
||||
// expect: nil,
|
||||
},
|
||||
// Standard JSON trace upon the latest block
|
||||
{
|
||||
|
|
@ -271,12 +260,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: &logger.ExecutionResult{
|
||||
Gas: params.TxGas,
|
||||
Failed: false,
|
||||
ReturnValue: "",
|
||||
StructLogs: []logger.StructLogRes{},
|
||||
},
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Tracing on 'pending' should fail
|
||||
{
|
||||
|
|
@ -289,28 +273,46 @@ func TestTraceCall(t *testing.T) {
|
|||
config: nil,
|
||||
expectErr: errors.New("tracing on top of pending is not supported"),
|
||||
},
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: ethapi.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
Input: &hexutil.Bytes{0x43}, // blocknumber
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
expectErr: nil,
|
||||
expect: ` {"gas":53072,"failed":false,"returnValue":"","structLogs":[
|
||||
{"pc":0,"op":"NUMBER","gas":24946930,"gasCost":2,"depth":1,"stack":[]},
|
||||
{"pc":1,"op":"STOP","gas":24946928,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`,
|
||||
},
|
||||
}
|
||||
for _, testspec := range testSuite {
|
||||
for i, testspec := range testSuite {
|
||||
result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
|
||||
if testspec.expectErr != nil {
|
||||
if err == nil {
|
||||
t.Errorf("Expect error %v, get nothing", testspec.expectErr)
|
||||
t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(err.Error(), testspec.expectErr.Error()) {
|
||||
t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err)
|
||||
if !reflect.DeepEqual(err, testspec.expectErr) {
|
||||
t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Expect no error, get %v", err)
|
||||
t.Errorf("test %d: expect no error, got %v", i, err)
|
||||
continue
|
||||
}
|
||||
var have *logger.ExecutionResult
|
||||
if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil {
|
||||
t.Errorf("failed to unmarshal result %v", err)
|
||||
t.Errorf("test %d: failed to unmarshal result %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(have, testspec.expect) {
|
||||
t.Errorf("Result mismatch, want %v, get %v", testspec.expect, have)
|
||||
var want *logger.ExecutionResult
|
||||
if err := json.Unmarshal([]byte(testspec.expect), &want); err != nil {
|
||||
t.Errorf("test %d: failed to unmarshal result %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Errorf("test %d: result mismatch, want %v, got %v", i, testspec.expect, string(result.(json.RawMessage)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -540,6 +542,39 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
want: `{"gas":23555,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`,
|
||||
},
|
||||
{ // Override blocknumber
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: ethapi.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
// BLOCKNUMBER PUSH1 MSTORE
|
||||
Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
|
||||
//&hexutil.Bytes{0x43}, // blocknumber
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":59903,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`,
|
||||
},
|
||||
{ // Override blocknumber, and query a blockhash
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: ethapi.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
Input: &hexutil.Bytes{
|
||||
0x60, 0x00, 0x40, // BLOCKHASH(0)
|
||||
0x60, 0x00, 0x52, // STORE memory offset 0
|
||||
0x61, 0x13, 0x36, 0x40, // BLOCKHASH(0x1336)
|
||||
0x60, 0x20, 0x52, // STORE memory offset 32
|
||||
0x61, 0x13, 0x37, 0x40, // BLOCKHASH(0x1337)
|
||||
0x60, 0x40, 0x52, // STORE memory offset 64
|
||||
0x60, 0x60, 0x60, 0x00, 0xf3, // RETURN (0-96)
|
||||
|
||||
}, // blocknumber
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":73812,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
|
||||
},
|
||||
}
|
||||
for i, tc := range testSuite {
|
||||
result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)
|
||||
|
|
|
|||
|
|
@ -580,6 +580,41 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// BlockOverrides is a set of header fields to override.
|
||||
type BlockOverrides struct {
|
||||
Number *hexutil.Big
|
||||
Difficulty *hexutil.Big
|
||||
Time *hexutil.Big
|
||||
GasLimit *hexutil.Uint64
|
||||
Coinbase *common.Address
|
||||
Random *common.Hash
|
||||
}
|
||||
|
||||
// Apply overrides the given header fields into the given block context.
|
||||
func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
||||
if diff == nil {
|
||||
return
|
||||
}
|
||||
if diff.Number != nil {
|
||||
blockCtx.BlockNumber = diff.Number.ToInt()
|
||||
}
|
||||
if diff.Difficulty != nil {
|
||||
blockCtx.Difficulty = diff.Difficulty.ToInt()
|
||||
}
|
||||
if diff.Time != nil {
|
||||
blockCtx.Time = diff.Time.ToInt()
|
||||
}
|
||||
if diff.GasLimit != nil {
|
||||
blockCtx.GasLimit = uint64(*diff.GasLimit)
|
||||
}
|
||||
if diff.Coinbase != nil {
|
||||
blockCtx.Coinbase = *diff.Coinbase
|
||||
}
|
||||
if diff.Random != nil {
|
||||
blockCtx.Random = diff.Random
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BlockChainAPI) GetBlockSignersByHash(ctx context.Context, blockHash common.Hash) ([]common.Address, error) {
|
||||
block, err := s.b.GetBlock(ctx, blockHash)
|
||||
if err != nil || block == nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue