10
10
from abc import abstractmethod
11
11
from dataclasses import dataclass
12
12
from pathlib import Path
13
- from typing import Any , Dict , List , Mapping , Optional , Type
13
+ from typing import Any , Dict , List , LiteralString , Mapping , Optional , Type
14
14
from urllib .parse import urlencode
15
15
16
16
from requests import Response
20
20
from ethereum_test_base_types import BlobSchedule
21
21
from ethereum_test_exceptions import ExceptionMapper
22
22
from ethereum_test_forks import Fork
23
+ from ethereum_test_forks .helpers import get_development_forks , get_forks
23
24
from ethereum_test_types import Alloc , Environment , Transaction
24
25
25
26
from .ethereum_cli import EthereumCLI
38
39
SLOW_REQUEST_TIMEOUT = 180
39
40
40
41
42
+ def get_valid_transition_tool_names () -> set [str ]:
43
+ """Get all valid transition tool names from deployed and development forks."""
44
+ all_available_forks = get_forks () + get_development_forks ()
45
+ return {fork .transition_tool_name () for fork in all_available_forks }
46
+
47
+
41
48
class TransitionTool (EthereumCLI ):
42
49
"""
43
50
Transition tool abstract base class which should be inherited by all transition tool
@@ -424,6 +431,49 @@ def _evaluate_stream(
424
431
425
432
return output
426
433
434
+ def safe_t8n_args (
435
+ self , fork_name : str , chain_id : int , reward : int , temp_dir = None
436
+ ) -> List [str ]:
437
+ """Safely construct t8n arguments with validated inputs."""
438
+ # Validate fork name against actual transition tool names from all available forks
439
+ valid_forks = get_valid_transition_tool_names ()
440
+ if fork_name not in valid_forks :
441
+ raise ValueError (f"Invalid fork name: { fork_name } " )
442
+
443
+ # Validate chain ID (should be positive integer)
444
+ if not isinstance (chain_id , int ) or chain_id <= 0 :
445
+ raise ValueError (f"Invalid chain ID: { chain_id } " )
446
+
447
+ # Validate reward (should be non-negative integer)
448
+ if not isinstance (reward , int ) or reward < 0 :
449
+ raise ValueError (f"Invalid reward: { reward } " )
450
+
451
+ # Use literal strings for command flags
452
+ input_alloc : LiteralString = "--input.alloc=stdin"
453
+ input_txs : LiteralString = "--input.txs=stdin"
454
+ input_env : LiteralString = "--input.env=stdin"
455
+ output_result : LiteralString = "--output.result=stdout"
456
+ output_alloc : LiteralString = "--output.alloc=stdout"
457
+ output_body : LiteralString = "--output.body=stdout"
458
+ trace_flag : LiteralString = "--trace"
459
+
460
+ args = [
461
+ input_alloc ,
462
+ input_txs ,
463
+ input_env ,
464
+ output_result ,
465
+ output_alloc ,
466
+ output_body ,
467
+ f"--state.fork={ fork_name } " ,
468
+ f"--state.chainid={ chain_id } " ,
469
+ f"--state.reward={ reward } " ,
470
+ ]
471
+
472
+ if self .trace and temp_dir :
473
+ args .extend ([trace_flag , f"--output.basedir={ temp_dir .name } " ])
474
+
475
+ return args
476
+
427
477
def construct_args_stream (
428
478
self , t8n_data : TransitionToolData , temp_dir : tempfile .TemporaryDirectory
429
479
) -> List [str ]:
@@ -432,22 +482,10 @@ def construct_args_stream(
432
482
if self .subcommand :
433
483
command .append (self .subcommand )
434
484
435
- args = command + [
436
- "--input.alloc=stdin" ,
437
- "--input.txs=stdin" ,
438
- "--input.env=stdin" ,
439
- "--output.result=stdout" ,
440
- "--output.alloc=stdout" ,
441
- "--output.body=stdout" ,
442
- f"--state.fork={ t8n_data .fork_name } " ,
443
- f"--state.chainid={ t8n_data .chain_id } " ,
444
- f"--state.reward={ t8n_data .reward } " ,
445
- ]
446
-
447
- if self .trace :
448
- args .append ("--trace" )
449
- args .append (f"--output.basedir={ temp_dir .name } " )
450
- return args
485
+ safe_args = self .safe_t8n_args (
486
+ t8n_data .fork_name , t8n_data .chain_id , t8n_data .reward , temp_dir
487
+ )
488
+ return command + safe_args
451
489
452
490
def dump_debug_stream (
453
491
self ,
0 commit comments