@@ -25,8 +25,10 @@ import (
25
25
"regexp"
26
26
"slices"
27
27
28
+ "github.com/ethereum/go-ethereum/common"
28
29
"github.com/ethereum/go-ethereum/core"
29
30
"github.com/ethereum/go-ethereum/core/rawdb"
31
+ "github.com/ethereum/go-ethereum/log"
30
32
"github.com/ethereum/go-ethereum/tests"
31
33
"github.com/urfave/cli/v2"
32
34
)
@@ -79,6 +81,42 @@ func blockTestCmd(ctx *cli.Context) error {
79
81
return nil
80
82
}
81
83
84
+ // blocktestEndMarker represents the final status of a blocktest execution.
85
+ // It is written as the last line of trace output in JSONL format (single-line JSON).
86
+ type blocktestEndMarker struct {
87
+ TestEnd blocktestEndDetails `json:"testEnd"`
88
+ }
89
+
90
+ type blocktestEndDetails struct {
91
+ Name string `json:"name"`
92
+ Pass bool `json:"pass"`
93
+ Fork string `json:"fork,omitempty"`
94
+ Root string `json:"root,omitempty"`
95
+ Error string `json:"error,omitempty"`
96
+ V int `json:"v"` // Version: 1
97
+ }
98
+
99
+ // writeEndMarker writes the blocktest end marker to stderr in JSONL format.
100
+ // This marker indicates the final outcome of the test as a single-line JSON object.
101
+ func writeEndMarker (result * testResult , fork string , root * common.Hash ) {
102
+ details := blocktestEndDetails {
103
+ Name : result .Name ,
104
+ Pass : result .Pass ,
105
+ Fork : fork ,
106
+ V : 1 ,
107
+ }
108
+ if ! result .Pass && result .Error != "" {
109
+ details .Error = result .Error
110
+ }
111
+ if root != nil {
112
+ details .Root = root .Hex ()
113
+ }
114
+ marker := blocktestEndMarker {TestEnd : details }
115
+ if data , err := json .Marshal (marker ); err == nil {
116
+ fmt .Fprintf (os .Stderr , "%s\n " , data )
117
+ }
118
+ }
119
+
82
120
func runBlockTest (ctx * cli.Context , fname string ) ([]testResult , error ) {
83
121
src , err := os .ReadFile (fname )
84
122
if err != nil {
@@ -94,6 +132,11 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
94
132
}
95
133
tracer := tracerFromFlags (ctx )
96
134
135
+ // Suppress INFO logs when tracing to avoid polluting stderr
136
+ if tracer != nil {
137
+ log .SetDefault (log .NewLogger (log .DiscardHandler ()))
138
+ }
139
+
97
140
// Pull out keys to sort and ensure tests are run in order.
98
141
keys := slices .Sorted (maps .Keys (tests ))
99
142
@@ -103,17 +146,30 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
103
146
if ! re .MatchString (name ) {
104
147
continue
105
148
}
149
+ test := tests [name ]
106
150
result := & testResult {Name : name , Pass : true }
107
- if err := tests [name ].Run (false , rawdb .PathScheme , ctx .Bool (WitnessCrossCheckFlag .Name ), tracer , func (res error , chain * core.BlockChain ) {
151
+ var finalRoot * common.Hash
152
+ if err := test .Run (false , rawdb .PathScheme , ctx .Bool (WitnessCrossCheckFlag .Name ), tracer , func (res error , chain * core.BlockChain ) {
108
153
if ctx .Bool (DumpFlag .Name ) {
109
154
if s , _ := chain .State (); s != nil {
110
155
result .State = dump (s )
111
156
}
112
157
}
158
+ // Capture final state root for end marker
159
+ if chain != nil {
160
+ root := chain .CurrentBlock ().Root
161
+ finalRoot = & root
162
+ }
113
163
}); err != nil {
114
164
result .Pass , result .Error = false , err .Error ()
115
165
}
116
166
results = append (results , * result )
167
+
168
+ // Write end marker when tracing is enabled
169
+ if tracer != nil {
170
+ fork := test .Network ()
171
+ writeEndMarker (result , fork , finalRoot )
172
+ }
117
173
}
118
174
return results , nil
119
175
}
0 commit comments