Unverified Commit 5f70f9fd authored by Martin Holst Swende's avatar Martin Holst Swende Committed by GitHub

eth/tracers: simplify test framework (#25973)

Co-authored-by: 's avatarSina Mahmoodi <itz.s1na@gmail.com>
parent a404195c
...@@ -48,17 +48,18 @@ type callContext struct { ...@@ -48,17 +48,18 @@ type callContext struct {
// callTrace is the result of a callTracer run. // callTrace is the result of a callTracer run.
type callTrace struct { type callTrace struct {
Type string `json:"type"`
From common.Address `json:"from"` From common.Address `json:"from"`
To common.Address `json:"to"` Gas *hexutil.Uint64 `json:"gas"`
GasUsed *hexutil.Uint64 `json:"gasUsed"`
To common.Address `json:"to,omitempty"`
Input hexutil.Bytes `json:"input"` Input hexutil.Bytes `json:"input"`
Output hexutil.Bytes `json:"output"` Output hexutil.Bytes `json:"output,omitempty"`
Gas *hexutil.Uint64 `json:"gas,omitempty"`
GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"`
Value *hexutil.Big `json:"value,omitempty"`
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
Revertal string `json:"revertReason,omitempty"` Revertal string `json:"revertReason,omitempty"`
Calls []callTrace `json:"calls,omitempty"` Calls []callTrace `json:"calls,omitempty"`
Value *hexutil.Big `json:"value,omitempty"`
// Gencodec adds overridden fields at the end
Type string `json:"type"`
} }
// callTracerTest defines a single test to check the call tracer against. // callTracerTest defines a single test to check the call tracer against.
...@@ -144,17 +145,21 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { ...@@ -144,17 +145,21 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err) t.Fatalf("failed to retrieve trace result: %v", err)
} }
ret := new(callTrace) // The legacy javascript calltracer marshals json in js, which
if err := json.Unmarshal(res, ret); err != nil { // is not deterministic (as opposed to the golang json encoder).
t.Fatalf("failed to unmarshal trace result: %v", err) if strings.HasSuffix(dirPath, "_legacy") {
// This is a tweak to make it deterministic. Can be removed when
// we remove the legacy tracer.
var x callTrace
json.Unmarshal(res, &x)
res, _ = json.Marshal(x)
} }
want, err := json.Marshal(test.Result)
if !jsonEqual(ret, test.Result, new(callTrace), new(callTrace)) { if err != nil {
// uncomment this for easier debugging t.Fatalf("failed to marshal test: %v", err)
//have, _ := json.MarshalIndent(ret, "", " ") }
//want, _ := json.MarshalIndent(test.Result, "", " ") if string(want) != string(res) {
//t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want))
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result)
} }
}) })
} }
...@@ -298,14 +303,8 @@ func TestZeroValueToNotExitCall(t *testing.T) { ...@@ -298,14 +303,8 @@ func TestZeroValueToNotExitCall(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err) t.Fatalf("failed to retrieve trace result: %v", err)
} }
have := new(callTrace) wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x2d0","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`
if err := json.Unmarshal(res, have); err != nil { if string(res) != wantStr {
t.Fatalf("failed to unmarshal trace result: %v", err) t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr)
}
wantStr := `{"type":"CALL","from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}`
want := new(callTrace)
json.Unmarshal([]byte(wantStr), want)
if !jsonEqual(have, want, new(callTrace), new(callTrace)) {
t.Error("have != want")
} }
} }
...@@ -35,19 +35,16 @@ import ( ...@@ -35,19 +35,16 @@ import (
// prestateTrace is the result of a prestateTrace run. // prestateTrace is the result of a prestateTrace run.
type prestateTrace = map[common.Address]*account type prestateTrace = map[common.Address]*account
type account struct { type account struct {
Balance string `json:"balance,omitempty"` Balance string `json:"balance"`
Nonce uint64 `json:"nonce,omitempty"` Code string `json:"code"`
Code string `json:"code,omitempty"` Nonce uint64 `json:"nonce"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"` Storage map[common.Hash]common.Hash `json:"storage"`
}
type prePostStateTrace struct {
Pre prestateTrace `json:"pre"`
Post prestateTrace `json:"post"`
} }
// prestateTraceTest defines a single test to check the stateDiff tracer against. // testcase defines a single test to check the stateDiff tracer against.
type prestateTraceTest struct { type testcase struct {
Genesis *core.Genesis `json:"genesis"` Genesis *core.Genesis `json:"genesis"`
Context *callContext `json:"context"` Context *callContext `json:"context"`
Input string `json:"input"` Input string `json:"input"`
...@@ -55,15 +52,19 @@ type prestateTraceTest struct { ...@@ -55,15 +52,19 @@ type prestateTraceTest struct {
Result interface{} `json:"result"` Result interface{} `json:"result"`
} }
func TestPrestateTracerLegacy(t *testing.T) {
testPrestateDiffTracer("prestateTracerLegacy", "prestate_tracer_legacy", t)
}
func TestPrestateTracer(t *testing.T) { func TestPrestateTracer(t *testing.T) {
testPrestateDiffTracer("prestateTracer", "prestate_tracer", t, func() interface{} { return new(prestateTrace) }) testPrestateDiffTracer("prestateTracer", "prestate_tracer", t)
} }
func TestPrestateWithDiffModeTracer(t *testing.T) { func TestPrestateWithDiffModeTracer(t *testing.T) {
testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t, func() interface{} { return new(prePostStateTrace) }) testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t)
} }
func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typeBuilder func() interface{}) { func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
files, err := os.ReadDir(filepath.Join("testdata", dirPath)) files, err := os.ReadDir(filepath.Join("testdata", dirPath))
if err != nil { if err != nil {
t.Fatalf("failed to retrieve tracer test suite: %v", err) t.Fatalf("failed to retrieve tracer test suite: %v", err)
...@@ -77,7 +78,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ ...@@ -77,7 +78,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ
t.Parallel() t.Parallel()
var ( var (
test = new(prestateTraceTest) test = new(testcase)
tx = new(types.Transaction) tx = new(types.Transaction)
) )
// Call tracer test found, read if from disk // Call tracer test found, read if from disk
...@@ -127,17 +128,21 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ ...@@ -127,17 +128,21 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ
if err != nil { if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err) t.Fatalf("failed to retrieve trace result: %v", err)
} }
ret := typeBuilder() // The legacy javascript calltracer marshals json in js, which
if err := json.Unmarshal(res, ret); err != nil { // is not deterministic (as opposed to the golang json encoder).
t.Fatalf("failed to unmarshal trace result: %v", err) if strings.HasSuffix(dirPath, "_legacy") {
// This is a tweak to make it deterministic. Can be removed when
// we remove the legacy tracer.
var x prestateTrace
json.Unmarshal(res, &x)
res, _ = json.Marshal(x)
} }
want, err := json.Marshal(test.Result)
if !jsonEqual(ret, test.Result, typeBuilder(), typeBuilder()) { if err != nil {
// uncomment this for easier debugging t.Fatalf("failed to marshal test: %v", err)
// have, _ := json.MarshalIndent(ret, "", " ") }
// want, _ := json.MarshalIndent(test.Result, "", " ") if string(want) != string(res) {
// t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want))
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result)
} }
}) })
} }
......
...@@ -77,8 +77,7 @@ ...@@ -77,8 +77,7 @@
"nonce": 29072 "nonce": 29072
}, },
"0x1585936b53834b021f68cc13eeefdec2efc8e724": { "0x1585936b53834b021f68cc13eeefdec2efc8e724": {
"balance": "0x0", "balance": "0x0"
"nonce": 0
} }
} }
} }
package tracetest package tracetest
import ( import (
"encoding/json"
"reflect"
"strings" "strings"
"unicode" "unicode"
...@@ -64,22 +62,6 @@ var makeTest = function(tx, rewind) { ...@@ -64,22 +62,6 @@ var makeTest = function(tx, rewind) {
} }
*/ */
// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to
// comparison
func jsonEqual(xi, yi, xt, yt interface{}) bool {
if xj, err := json.Marshal(xi); err == nil {
json.Unmarshal(xj, xt)
} else {
return false
}
if yj, err := json.Marshal(yi); err == nil {
json.Unmarshal(yj, yt)
} else {
return false
}
return reflect.DeepEqual(xt, yt)
}
// camel converts a snake cased input string into a camel cased output. // camel converts a snake cased input string into a camel cased output.
func camel(str string) string { func camel(str string) string {
pieces := strings.Split(str, "_") pieces := strings.Split(str, "_")
......
...@@ -204,7 +204,6 @@ ...@@ -204,7 +204,6 @@
gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16), gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16),
input: toHex(ctx.input), input: toHex(ctx.input),
output: toHex(ctx.output), output: toHex(ctx.output),
time: ctx.time,
}; };
if (this.callstack[0].calls !== undefined) { if (this.callstack[0].calls !== undefined) {
result.calls = this.callstack[0].calls; result.calls = this.callstack[0].calls;
......
...@@ -16,14 +16,14 @@ var _ = (*accountMarshaling)(nil) ...@@ -16,14 +16,14 @@ var _ = (*accountMarshaling)(nil)
func (a account) MarshalJSON() ([]byte, error) { func (a account) MarshalJSON() ([]byte, error) {
type account struct { type account struct {
Balance *hexutil.Big `json:"balance,omitempty"` Balance *hexutil.Big `json:"balance,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Code hexutil.Bytes `json:"code,omitempty"` Code hexutil.Bytes `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
} }
var enc account var enc account
enc.Balance = (*hexutil.Big)(a.Balance) enc.Balance = (*hexutil.Big)(a.Balance)
enc.Nonce = a.Nonce
enc.Code = a.Code enc.Code = a.Code
enc.Nonce = a.Nonce
enc.Storage = a.Storage enc.Storage = a.Storage
return json.Marshal(&enc) return json.Marshal(&enc)
} }
...@@ -31,10 +31,10 @@ func (a account) MarshalJSON() ([]byte, error) { ...@@ -31,10 +31,10 @@ func (a account) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (a *account) UnmarshalJSON(input []byte) error { func (a *account) UnmarshalJSON(input []byte) error {
type account struct { type account struct {
Balance *hexutil.Big `json:"balance"` Balance *hexutil.Big `json:"balance,omitempty"`
Nonce *uint64 `json:"nonce"` Code *hexutil.Bytes `json:"code,omitempty"`
Code *hexutil.Bytes `json:"code"` Nonce *uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
} }
var dec account var dec account
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
...@@ -43,12 +43,12 @@ func (a *account) UnmarshalJSON(input []byte) error { ...@@ -43,12 +43,12 @@ func (a *account) UnmarshalJSON(input []byte) error {
if dec.Balance != nil { if dec.Balance != nil {
a.Balance = (*big.Int)(dec.Balance) a.Balance = (*big.Int)(dec.Balance)
} }
if dec.Nonce != nil {
a.Nonce = *dec.Nonce
}
if dec.Code != nil { if dec.Code != nil {
a.Code = *dec.Code a.Code = *dec.Code
} }
if dec.Nonce != nil {
a.Nonce = *dec.Nonce
}
if dec.Storage != nil { if dec.Storage != nil {
a.Storage = dec.Storage a.Storage = dec.Storage
} }
......
...@@ -40,8 +40,8 @@ type state = map[common.Address]*account ...@@ -40,8 +40,8 @@ type state = map[common.Address]*account
type account struct { type account struct {
Balance *big.Int `json:"balance,omitempty"` Balance *big.Int `json:"balance,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Code []byte `json:"code,omitempty"` Code []byte `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
} }
...@@ -253,9 +253,9 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) { ...@@ -253,9 +253,9 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) {
var err error var err error
if t.config.DiffMode { if t.config.DiffMode {
res, err = json.Marshal(struct { res, err = json.Marshal(struct {
Pre state `json:"pre"`
Post state `json:"post"` Post state `json:"post"`
}{t.pre, t.post}) Pre state `json:"pre"`
}{t.post, t.pre})
} else { } else {
res, err = json.Marshal(t.pre) res, err = json.Marshal(t.pre)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment