1- use alloy_primitives:: { Bytes , keccak256} ;
1+ use alloy_primitives:: { B256 , Bytes , keccak256} ;
22use reth_node_builder:: BuilderContext ;
33use reth_provider:: StateProvider ;
44use reth_revm:: State ;
55use revm:: Database ;
6- use std:: fmt:: Debug ;
6+ use std:: {
7+ fmt:: Debug ,
8+ fs:: { self , OpenOptions } ,
9+ io:: Write ,
10+ os:: unix:: fs:: OpenOptionsExt ,
11+ path:: Path ,
12+ } ;
713use tracing:: { info, warn} ;
814
915use crate :: {
@@ -12,7 +18,7 @@ use crate::{
1218 } ,
1319 primitives:: reth:: ExecutionInfo ,
1420 traits:: NodeBounds ,
15- tx_signer:: { Signer , generate_ethereum_keypair , generate_key_from_seed } ,
21+ tx_signer:: { Signer , generate_key_from_seed , generate_signer } ,
1622} ;
1723
1824use super :: {
@@ -28,21 +34,16 @@ pub async fn bootstrap_flashtestations<Node>(
2834where
2935 Node : NodeBounds ,
3036{
31- let ( private_key, public_key, address) = if args. debug {
32- info ! ( "Flashtestations debug mode enabled, generating debug key" ) ;
33- // Generate deterministic key for debugging purposes
34- generate_key_from_seed ( & args. debug_tee_key_seed )
35- } else {
36- generate_ethereum_keypair ( )
37- } ;
37+ let tee_service_signer = load_or_generate_tee_key (
38+ & args. flashtestations_key_path ,
39+ args. debug ,
40+ & args. debug_tee_key_seed ,
41+ ) ?;
3842
39- info ! ( "Flashtestations key generated: {}" , address) ;
40-
41- let tee_service_signer = Signer {
42- address,
43- pubkey : public_key,
44- secret : private_key,
45- } ;
43+ info ! (
44+ "Flashtestations TEE address: {}" ,
45+ tee_service_signer. address
46+ ) ;
4647
4748 let funding_key = args
4849 . funding_key
@@ -135,6 +136,64 @@ where
135136 Ok ( flashtestations_builder_tx)
136137}
137138
139+ /// Load ephemeral TEE key from file, or generate and save a new one
140+ fn load_or_generate_tee_key ( key_path : & str , debug : bool , debug_seed : & str ) -> eyre:: Result < Signer > {
141+ if debug {
142+ info ! ( "Flashtestations debug mode enabled, generating debug key from seed" ) ;
143+ return Ok ( generate_key_from_seed ( debug_seed) ) ;
144+ }
145+
146+ let path = Path :: new ( key_path) ;
147+
148+ if let Some ( signer) = load_tee_key ( path) {
149+ return Ok ( signer) ;
150+ }
151+
152+ // Generate new key
153+ info ! ( "Generating new ephemeral TEE key" ) ;
154+ let signer = generate_signer ( ) ;
155+
156+ let key_hex = hex:: encode ( signer. secret . secret_bytes ( ) ) ;
157+
158+ // Create file with 0600 permissions atomically
159+ OpenOptions :: new ( )
160+ . write ( true )
161+ . create ( true )
162+ . truncate ( true )
163+ . mode ( 0o600 )
164+ . open ( path)
165+ . and_then ( |mut file| file. write_all ( key_hex. as_bytes ( ) ) )
166+ . inspect_err ( |e| warn ! ( "Failed to write key to {}: {:?}" , key_path, e) )
167+ . ok ( ) ;
168+
169+ Ok ( signer)
170+ }
171+
172+ fn load_tee_key ( path : & Path ) -> Option < Signer > {
173+ // Try to load existing key
174+ if !path. exists ( ) {
175+ return None ;
176+ }
177+
178+ info ! ( "Loading TEE key from {:?}" , path) ;
179+ let key_hex = fs:: read_to_string ( path)
180+ . inspect_err ( |e| warn ! ( "failed to read key file: {:?}" , e) )
181+ . ok ( ) ?;
182+
183+ let secret_bytes = B256 :: try_from (
184+ hex:: decode ( key_hex. trim ( ) )
185+ . inspect_err ( |e| warn ! ( "failed to decode hex from file {:?}" , e) )
186+ . ok ( ) ?
187+ . as_slice ( ) ,
188+ )
189+ . inspect_err ( |e| warn ! ( "failed to parse key from file: {:?}" , e) )
190+ . ok ( ) ?;
191+
192+ Signer :: try_from_secret ( secret_bytes)
193+ . inspect_err ( |e| warn ! ( "failed to create signer from key: {:?}" , e) )
194+ . ok ( )
195+ }
196+
138197#[ derive( Debug , Clone ) ]
139198pub struct FlashtestationsBuilderTx { }
140199
0 commit comments