11use alloy:: {
2- consensus:: SignableTransaction ,
3- network:: { EthereumWallet , Network , ReceiptResponse , TxSigner } ,
2+ network:: { EthereumWallet , Network , ReceiptResponse } ,
43 primitives:: { Address , B256 } ,
54 providers:: { Provider , ProviderBuilder } ,
6- signers:: { local:: PrivateKeySigner , Signer } ,
5+ signers:: local:: PrivateKeySigner ,
76 sol,
87 transports:: Transport ,
98} ;
109use anyhow:: Result ;
11- use log:: { error, info} ;
1210use sp1_blobstream_primitives:: get_header_update_verdict;
1311use sp1_blobstream_script:: util:: {
1412 fetch_input_for_blobstream_proof, find_block_to_request, get_latest_block_height,
@@ -22,8 +20,10 @@ use sp1_sdk::{
2220use std:: { env, sync:: Arc } ;
2321use std:: { marker:: PhantomData , time:: Duration } ;
2422use tendermint_light_client_verifier:: Verdict ;
23+ use tracing:: { error, info} ;
24+ use tracing_subscriber:: EnvFilter ;
2525
26- use signer:: MaybeSigner ;
26+ use signer:: MaybeWallet ;
2727
2828sol ! {
2929 #[ allow( missing_docs) ]
@@ -69,7 +69,6 @@ impl<P: Provider<T, N>, T: Transport + Clone, N: Network> SP1BlobstreamOperator<
6969 ///
7070 /// # Panics
7171 /// - If the chain id cannot be retrieved from the provider.
72- /// - If the signer is not provided and were not using the KMS relayer.
7372 pub async fn new (
7473 provider : P ,
7574 contract_address : Address ,
@@ -288,7 +287,7 @@ impl ChainConfig {
288287 ///
289288 /// If neither are set, it will try to use [`Self::from_env`].
290289 fn fetch ( ) -> Result < Vec < Self > > {
291- const DEFAULT_PATH : & str = "../ chains.json" ;
290+ const DEFAULT_PATH : & str = "chains.json" ;
292291
293292 let path = env:: var ( "CHAINS_PATH" ) . unwrap_or ( DEFAULT_PATH . to_string ( ) ) ;
294293
@@ -297,13 +296,16 @@ impl ChainConfig {
297296
298297 /// Tries to read from the `CHAINS` environment variable.
299298 fn from_env ( ) -> Result < Vec < Self > > {
300- let chains = env:: var ( "CHAINS" ) . expect ( "CHAINS not set." ) ;
299+ let chains = env:: var ( "CHAINS" ) ? ;
301300
302301 Ok ( serde_json:: from_str ( & chains) ?)
303302 }
304303
305304 fn from_file ( path : & str ) -> Result < Vec < Self > > {
306- let file = std:: fs:: read_to_string ( path) ?;
305+ tracing:: debug!( "Reading chains from file: {}" , path) ;
306+
307+ let file = std:: fs:: read_to_string ( path)
308+ . inspect_err ( |e| println ! ( "Error reading file: {:?}" , e) ) ?;
307309
308310 Ok ( serde_json:: from_str ( & file) ?)
309311 }
@@ -312,29 +314,35 @@ impl ChainConfig {
312314#[ tokio:: main]
313315async fn main ( ) {
314316 dotenv:: dotenv ( ) . ok ( ) ;
315- env_logger:: init ( ) ;
316317
317- let prover = ProverClient :: builder ( ) . cpu ( ) . build ( ) ;
318- let ( pk, vk) = prover. setup ( TENDERMINT_ELF ) ;
319- let pk = Arc :: new ( pk) ;
318+ // Setup tracing.
319+ tracing_subscriber:: fmt:: fmt ( )
320+ . with_env_filter ( EnvFilter :: from_default_env ( ) )
321+ . init ( ) ;
320322
321323 // Succinct deployments use the `CHAINS` environment variable.
322- let config = ChainConfig :: from_env ( ) . expect ( "Failed to fetch chain config. " ) ;
324+ let config = ChainConfig :: fetch ( ) . expect ( "Failed to fetch chain config" ) ;
323325 let maybe_private_key: Option < PrivateKeySigner > = env:: var ( "PRIVATE_KEY" )
324326 . ok ( )
325327 . map ( |s| s. parse ( ) . expect ( "Failed to parse PRIVATE_KEY" ) ) ;
326328
329+ // Setup the KMS relayer config.
327330 let use_kms_relayer: bool = env:: var ( "USE_KMS_RELAYER" )
328331 . map ( |s| s. parse ( ) . expect ( "USE_KMS_RELAYER failed to parse" ) )
329- . expect ( "USE_KMS_RELAYER not set. " ) ;
332+ . expect ( "USE_KMS_RELAYER not set" ) ;
330333
331334 // Ensure we have a signer if we're not using the KMS relayer.
332335 if !use_kms_relayer && maybe_private_key. is_none ( ) {
333336 panic ! ( "PRIVATE_KEY is not set but USE_KMS_RELAYER is false." ) ;
334337 }
335338
336339 // Setup our signer.
337- let signer = EthereumWallet :: new ( MaybeSigner :: new ( maybe_private_key) ) ;
340+ let signer = MaybeWallet :: new ( maybe_private_key. map ( EthereumWallet :: new) ) ;
341+
342+ // Setup the prover and program keys.
343+ let prover = ProverClient :: builder ( ) . cpu ( ) . build ( ) ;
344+ let ( pk, vk) = prover. setup ( TENDERMINT_ELF ) ;
345+ let pk = Arc :: new ( pk) ;
338346
339347 // Setup all the tasks.
340348 // These futures should never resolve, so we just await them in the main thread.
@@ -357,11 +365,14 @@ async fn main() {
357365 )
358366 . await ;
359367
368+ let span = tracing:: span!( tracing:: Level :: INFO , "operator" , chain = c. name) ;
369+ let _guard = span. enter ( ) ;
370+
360371 loop {
361372 let request_interval_mins = get_loop_interval_mins ( ) ;
362373 tokio:: select! {
363374 _ = tokio:: time:: sleep( tokio:: time:: Duration :: from_secs( 60 * LOOP_TIMEOUT_MINS ) ) => {
364- log :: error!( "Operator took longer than {} minutes to run." , LOOP_TIMEOUT_MINS ) ;
375+ tracing :: error!( "Operator took longer than {} minutes to run." , LOOP_TIMEOUT_MINS ) ;
365376 continue ;
366377 }
367378 e = operator. run( ) => {
@@ -383,49 +394,61 @@ async fn main() {
383394 // Run all the tasks.
384395 futures:: future:: try_join_all ( handles) . await . unwrap ( ) ;
385396
386- error ! ( "All operators finished." ) ;
397+ info ! ( "All operators finished." ) ;
387398}
388399
400+ /// We want our operators to be generic over a single provider (which is generic over a signer).
401+ /// Using this signer, we get one concrete type as a provider, even if we dont have a private key.
389402mod signer {
390- use alloy:: { consensus:: SignableTransaction , network:: TxSigner , primitives:: Address } ;
391- use std:: marker:: PhantomData ;
403+ use alloy:: {
404+ consensus:: { TxEnvelope , TypedTransaction } ,
405+ network:: { Network , NetworkWallet } ,
406+ primitives:: Address ,
407+ } ;
392408
393409 /// A signer than panics if called and not set.
394- pub struct MaybeSigner < Sig , S > {
395- signer : Option < S > ,
396- _phantom : PhantomData < Sig > ,
397- }
410+ #[ derive( Clone , Debug ) ]
411+ pub struct MaybeWallet < W > ( Option < W > ) ;
398412
399- impl < Sig , S > MaybeSigner < Sig , S > {
400- pub fn new ( signer : Option < S > ) -> Self {
401- Self {
402- signer,
403- _phantom : PhantomData ,
404- }
413+ impl < W > MaybeWallet < W > {
414+ pub fn new ( signer : Option < W > ) -> Self {
415+ Self ( signer)
405416 }
406417 }
407418
408- #[ async_trait:: async_trait]
409- impl < Sig , S > TxSigner < Sig > for MaybeSigner < Sig , S >
419+ impl < W , N > NetworkWallet < N > for MaybeWallet < W >
410420 where
411- S : TxSigner < Sig > + Send + Sync ,
412- Sig : Send + Sync ,
421+ W : NetworkWallet < N > ,
422+ N : Network < UnsignedTx = TypedTransaction , TxEnvelope = TxEnvelope > ,
413423 {
414- fn address ( & self ) -> Address {
415- self . signer
424+ fn default_signer_address ( & self ) -> Address {
425+ self . 0
426+ . as_ref ( )
427+ . expect ( "No signer set" )
428+ . default_signer_address ( )
429+ }
430+
431+ fn has_signer_for ( & self , address : & Address ) -> bool {
432+ self . 0
416433 . as_ref ( )
417- . expect ( "Signer should be set" )
418- . address ( )
434+ . expect ( "No signer set" )
435+ . has_signer_for ( address)
436+ }
437+
438+ fn signer_addresses ( & self ) -> impl Iterator < Item = Address > {
439+ self . 0 . as_ref ( ) . expect ( "No signer set" ) . signer_addresses ( )
419440 }
420441
421- async fn sign_transaction (
442+ #[ doc( alias = "sign_tx_from" ) ]
443+ async fn sign_transaction_from (
422444 & self ,
423- tx : & mut dyn SignableTransaction < Sig > ,
424- ) -> alloy:: signers:: Result < Sig > {
425- self . signer
445+ sender : Address ,
446+ tx : TypedTransaction ,
447+ ) -> alloy:: signers:: Result < TxEnvelope > {
448+ self . 0
426449 . as_ref ( )
427- . expect ( "Signer should be set" )
428- . sign_transaction ( tx)
450+ . expect ( "No signer set" )
451+ . sign_transaction_from ( sender , tx)
429452 . await
430453 }
431454 }
0 commit comments