4
4
5
5
import argparse
6
6
import fnmatch
7
+ import json
7
8
import os
8
9
from functools import partial
9
- from typing import Any , TextIO
10
+ from typing import Any , Optional , TextIO , Union
10
11
11
12
from ethereum_rlp import rlp
12
13
from ethereum_types .numeric import U64 , U256 , Uint
23
24
from ..utils import (
24
25
FatalException ,
25
26
get_module_name ,
27
+ get_module_name_json_input ,
26
28
get_stream_logger ,
27
29
parse_hex_or_int ,
28
30
)
@@ -82,19 +84,73 @@ class T8N(Load):
82
84
"""The class that carries out the transition"""
83
85
84
86
def __init__ (
85
- self , options : Any , out_file : TextIO , in_file : TransitionToolRequest
87
+ self ,
88
+ options : Any ,
89
+ in_file : Union [TransitionToolRequest , TextIO ],
90
+ out_file : Optional [TextIO ] = None
86
91
) -> None :
87
92
self .out_file = out_file
88
93
self .in_file = in_file
89
94
self .options = options
90
95
self .forks = Hardfork .discover ()
91
96
97
+ if isinstance (in_file , TransitionToolRequest ):
98
+ self ._init_from_pydantic (options , in_file )
99
+ else :
100
+ if out_file is None :
101
+ raise ValueError ("out_file is required for JSON file input" )
102
+ self ._init_from_json (options , in_file , out_file )
103
+
104
+ def _init_from_pydantic (self , options : Any , in_file : TransitionToolRequest ) -> None :
92
105
fork_module , self .fork_block = get_module_name (
93
- self .forks , self . options , in_file .input .env
106
+ self .forks , options , in_file .input .env
94
107
)
95
108
self .fork = ForkLoad (fork_module )
96
109
self .exception_mapper = ExecutionSpecsExceptionMapper ()
97
110
111
+ if options .trace :
112
+ trace_memory = getattr (options , "trace.memory" , False )
113
+ trace_stack = not getattr (options , "trace.nostack" , False )
114
+ trace_return_data = getattr (options , "trace.returndata" )
115
+ trace .set_evm_trace (
116
+ partial (
117
+ evm_trace ,
118
+ trace_memory = trace_memory ,
119
+ trace_stack = trace_stack ,
120
+ trace_return_data = trace_return_data ,
121
+ output_basedir = options .output_basedir ,
122
+ )
123
+ )
124
+ self .logger = get_stream_logger ("T8N" )
125
+
126
+ super ().__init__ (
127
+ options .state_fork ,
128
+ fork_module ,
129
+ )
130
+
131
+ self .chain_id = parse_hex_or_int (options .state_chainid , U64 )
132
+ self .alloc = Alloc (self , in_file .input .alloc )
133
+ self .env = Env (self , in_file .input .env )
134
+ self .txs = Txs (self , in_file .input .txs )
135
+ self .result = Result (
136
+ self .env .block_difficulty , self .env .base_fee_per_gas
137
+ )
138
+
139
+ def _init_from_json (self , options : Any , in_file : TextIO , out_file : TextIO ) -> None :
140
+ if "stdin" in (
141
+ options .input_env ,
142
+ options .input_alloc ,
143
+ options .input_txs ,
144
+ ):
145
+ stdin = json .load (in_file )
146
+ else :
147
+ stdin = None
148
+
149
+ fork_module , self .fork_block = get_module_name_json_input (
150
+ self .forks , self .options , stdin
151
+ )
152
+ self .fork = ForkLoad (fork_module )
153
+
98
154
if self .options .trace :
99
155
trace_memory = getattr (self .options , "trace.memory" , False )
100
156
trace_stack = not getattr (self .options , "trace.nostack" , False )
@@ -116,9 +172,9 @@ def __init__(
116
172
)
117
173
118
174
self .chain_id = parse_hex_or_int (self .options .state_chainid , U64 )
119
- self .alloc = Alloc (self , in_file . input . alloc )
120
- self .env = Env (self , in_file . input . env )
121
- self .txs = Txs (self , in_file . input . txs )
175
+ self .alloc = Alloc (self , stdin )
176
+ self .env = Env (self , stdin )
177
+ self .txs = Txs (self , stdin )
122
178
self .result = Result (
123
179
self .env .block_difficulty , self .env .base_fee_per_gas
124
180
)
@@ -305,13 +361,59 @@ def run(self) -> int:
305
361
306
362
json_state = self .alloc .to_json ()
307
363
json_result = self .result .to_json ()
364
+ if isinstance (self .in_file , TransitionToolRequest ):
365
+ json_output = {}
366
+
367
+ txs_rlp = "0x" + rlp .encode (self .txs .all_txs ).hex ()
368
+ json_output ["body" ] = txs_rlp
369
+ json_output ["alloc" ] = json_state
370
+ json_output ["result" ] = json_result
371
+ output : TransitionToolOutput = TransitionToolOutput .model_validate (
372
+ json_output , context = {"exception_mapper" : self .exception_mapper }
373
+ )
374
+ return output
375
+ else :
376
+ return self ._write_json_output (json_state , json_result )
377
+
378
+ def _write_json_output (self , json_state : Any , json_result : Any ) -> int :
308
379
json_output = {}
309
380
310
- txs_rlp = "0x" + rlp .encode (self .txs .all_txs ).hex ()
311
- json_output ["body" ] = txs_rlp
312
- json_output ["alloc" ] = json_state
313
- json_output ["result" ] = json_result
314
- output : TransitionToolOutput = TransitionToolOutput .model_validate (
315
- json_output , context = {"exception_mapper" : self .exception_mapper }
316
- )
317
- return output
381
+ if self .options .output_body == "stdout" :
382
+ txs_rlp = "0x" + rlp .encode (self .txs .all_txs ).hex ()
383
+ json_output ["body" ] = txs_rlp
384
+ elif self .options .output_body is not None :
385
+ txs_rlp_path = os .path .join (
386
+ self .options .output_basedir ,
387
+ self .options .output_body ,
388
+ )
389
+ txs_rlp = "0x" + rlp .encode (self .txs .all_txs ).hex ()
390
+ with open (txs_rlp_path , "w" ) as f :
391
+ json .dump (txs_rlp , f )
392
+ self .logger .info (f"Wrote transaction rlp to { txs_rlp_path } " )
393
+
394
+ if self .options .output_alloc == "stdout" :
395
+ json_output ["alloc" ] = json_state
396
+ else :
397
+ alloc_output_path = os .path .join (
398
+ self .options .output_basedir ,
399
+ self .options .output_alloc ,
400
+ )
401
+ with open (alloc_output_path , "w" ) as f :
402
+ json .dump (json_state , f , indent = 4 )
403
+ self .logger .info (f"Wrote alloc to { alloc_output_path } " )
404
+
405
+ if self .options .output_result == "stdout" :
406
+ json_output ["result" ] = json_result
407
+ else :
408
+ result_output_path = os .path .join (
409
+ self .options .output_basedir ,
410
+ self .options .output_result ,
411
+ )
412
+ with open (result_output_path , "w" ) as f :
413
+ json .dump (json_result , f , indent = 4 )
414
+ self .logger .info (f"Wrote result to { result_output_path } " )
415
+
416
+ if json_output :
417
+ json .dump (json_output , self .out_file , indent = 4 )
418
+
419
+ return 0
0 commit comments