mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
eth/tracers: hex-encode returnValue (#31216)
This is a **breaking change** to the opcode tracer. The top-level `returnValue` field of a trace will be now hex-encoded. If the return data is empty, this field will contain "0x". Fixes #31196
This commit is contained in:
parent
c5db2c6a80
commit
46ccc25831
2 changed files with 42 additions and 25 deletions
|
|
@ -356,7 +356,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the head, plain transfer.
|
||||
{
|
||||
|
|
@ -368,7 +368,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`,
|
||||
},
|
||||
// Upon the last state, default to the post block's state
|
||||
{
|
||||
|
|
@ -379,7 +379,7 @@ func TestTraceCall(t *testing.T) {
|
|||
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
|
||||
},
|
||||
config: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`,
|
||||
},
|
||||
// Before the first transaction, should be failed
|
||||
{
|
||||
|
|
@ -413,7 +413,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: &TraceCallConfig{TxIndex: uintPtr(2)},
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the non-existent block, error expects
|
||||
{
|
||||
|
|
@ -437,7 +437,7 @@ func TestTraceCall(t *testing.T) {
|
|||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`,
|
||||
},
|
||||
// Tracing on 'pending' should fail:
|
||||
{
|
||||
|
|
@ -460,7 +460,7 @@ func TestTraceCall(t *testing.T) {
|
|||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
expectErr: nil,
|
||||
expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[
|
||||
expect: ` {"gas":53018,"failed":false,"returnValue":"0x","structLogs":[
|
||||
{"pc":0,"op":"NUMBER","gas":24946984,"gasCost":2,"depth":1,"stack":[]},
|
||||
{"pc":1,"op":"STOP","gas":24946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`,
|
||||
},
|
||||
|
|
@ -537,7 +537,7 @@ func TestTraceTransaction(t *testing.T) {
|
|||
if !reflect.DeepEqual(have, &logger.ExecutionResult{
|
||||
Gas: params.TxGas,
|
||||
Failed: false,
|
||||
ReturnValue: "",
|
||||
ReturnValue: []byte{},
|
||||
StructLogs: []json.RawMessage{},
|
||||
}) {
|
||||
t.Error("Transaction tracing result is different")
|
||||
|
|
@ -598,7 +598,7 @@ func TestTraceBlock(t *testing.T) {
|
|||
// Trace head block
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks),
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
// Trace non-existent block
|
||||
{
|
||||
|
|
@ -608,12 +608,12 @@ func TestTraceBlock(t *testing.T) {
|
|||
// Trace latest block
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
// Trace pending block
|
||||
{
|
||||
blockNumber: rpc.PendingBlockNumber,
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
}
|
||||
for i, tc := range testSuite {
|
||||
|
|
@ -706,7 +706,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
},
|
||||
},
|
||||
want: `{"gas":21000,"failed":false,"returnValue":""}`,
|
||||
want: `{"gas":21000,"failed":false,"returnValue":"0x"}`,
|
||||
},
|
||||
// Invalid call without state overriding
|
||||
{
|
||||
|
|
@ -717,7 +717,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: &TraceCallConfig{},
|
||||
expectErr: core.ErrInsufficientFunds,
|
||||
expectErr: fmt.Errorf("tracing failed: %w: address %v have 0 want 1000", core.ErrInsufficientFunds, randomAccounts[0].addr.Hex()),
|
||||
},
|
||||
// Successful simple contract call
|
||||
//
|
||||
|
|
@ -751,7 +751,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`,
|
||||
want: `{"gas":23347,"failed":false,"returnValue":"0x000000000000000000000000000000000000000000000000000000000000007b"}`,
|
||||
},
|
||||
{ // Override blocknumber
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
|
|
@ -763,7 +763,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
config: &TraceCallConfig{
|
||||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`,
|
||||
want: `{"gas":59537,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000001337"}`,
|
||||
},
|
||||
{ // Override blocknumber, and query a blockhash
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
|
|
@ -783,7 +783,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
config: &TraceCallConfig{
|
||||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
|
||||
want: `{"gas":72666,"failed":false,"returnValue":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
|
||||
},
|
||||
/*
|
||||
pragma solidity =0.8.12;
|
||||
|
|
@ -817,7 +817,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
|
||||
want: `{"gas":44100,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000001"}`,
|
||||
},
|
||||
{ // Same again, this time with storage override
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
|
|
@ -829,6 +829,24 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
config: &TraceCallConfig{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
||||
State: newStates([]common.Hash{{}}, []common.Hash{{}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
//want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
|
||||
want: `{"gas":44100,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000001"}`,
|
||||
},
|
||||
{ // No state override
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: ethapi.TransactionArgs{
|
||||
From: &randomAccounts[0].addr,
|
||||
To: &storageAccount,
|
||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: &override.StateOverride{
|
||||
storageAccount: override.OverrideAccount{
|
||||
Code: newRPCBytes([]byte{
|
||||
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
|
||||
byte(vm.PUSH1), 0x04,
|
||||
|
|
@ -847,7 +865,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000077"}`,
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000077"}`,
|
||||
},
|
||||
{ // Full state override
|
||||
// The original storage is
|
||||
|
|
@ -885,7 +903,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000011"}`,
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000011"}`,
|
||||
},
|
||||
{ // Partial state override
|
||||
// The original storage is
|
||||
|
|
@ -923,7 +941,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
|
||||
want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000055"}`,
|
||||
},
|
||||
{ // Call to precompile ECREC (0x01), but code was modified to add 1 to input
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
|
|
@ -1068,7 +1086,7 @@ func TestTraceChain(t *testing.T) {
|
|||
backend.relHook = func() { rel.Add(1) }
|
||||
api := NewAPI(backend)
|
||||
|
||||
single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
|
||||
single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}`
|
||||
var cases = []struct {
|
||||
start uint64
|
||||
end uint64
|
||||
|
|
@ -1182,7 +1200,7 @@ func TestTraceBlockWithBasefee(t *testing.T) {
|
|||
// Trace head block
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks),
|
||||
want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee),
|
||||
want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"0x","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee),
|
||||
},
|
||||
}
|
||||
for i, tc := range testSuite {
|
||||
|
|
|
|||
|
|
@ -350,14 +350,13 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) {
|
|||
failed := l.err != nil
|
||||
returnData := common.CopyBytes(l.output)
|
||||
// Return data when successful and revert reason when reverted, otherwise empty.
|
||||
returnVal := fmt.Sprintf("%x", returnData)
|
||||
if failed && !errors.Is(l.err, vm.ErrExecutionReverted) {
|
||||
returnVal = ""
|
||||
returnData = []byte{}
|
||||
}
|
||||
return json.Marshal(&ExecutionResult{
|
||||
Gas: l.usedGas,
|
||||
Failed: failed,
|
||||
ReturnValue: returnVal,
|
||||
ReturnValue: returnData,
|
||||
StructLogs: l.logs,
|
||||
})
|
||||
}
|
||||
|
|
@ -527,6 +526,6 @@ func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O
|
|||
type ExecutionResult struct {
|
||||
Gas uint64 `json:"gas"`
|
||||
Failed bool `json:"failed"`
|
||||
ReturnValue string `json:"returnValue"`
|
||||
ReturnValue hexutil.Bytes `json:"returnValue"`
|
||||
StructLogs []json.RawMessage `json:"structLogs"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue