@@ -12,13 +12,15 @@ use fendermint_crypto::{PublicKey, SecretKey};
1212use fendermint_vm_actor_interface:: ipc;
1313use fendermint_vm_actor_interface:: {
1414 eam:: EthAddress ,
15+ f3_light_client,
1516 init:: builtin_actor_eth_addr,
1617 ipc:: { AbiHash , ValidatorMerkleTree , GATEWAY_ACTOR_ID } ,
1718} ;
1819use fendermint_vm_genesis:: { Collateral , Power , PowerScale , Validator , ValidatorKey } ;
1920use fendermint_vm_message:: conv:: { from_eth, from_fvm} ;
2021use fendermint_vm_message:: signed:: sign_secp256k1;
2122use fendermint_vm_topdown:: IPCParentFinality ;
23+ use fvm_ipld_encoding:: RawBytes ;
2224
2325use ipc_actors_abis:: checkpointing_facet:: CheckpointingFacet ;
2426use ipc_actors_abis:: gateway_getter_facet:: GatewayGetterFacet ;
@@ -385,3 +387,110 @@ fn membership_to_power_table(
385387
386388 pt
387389}
390+
391+ /// Caller for F3 Light Client actor operations.
392+ ///
393+ /// The F3 Light Client actor maintains F3 light client state including:
394+ /// - Current F3 instance ID
395+ /// - Finalized epochs chain
396+ /// - Validator power table
397+ #[ derive( Clone ) ]
398+ pub struct F3LightClientCaller {
399+ actor_id : ActorID ,
400+ }
401+
402+ impl Default for F3LightClientCaller {
403+ fn default ( ) -> Self {
404+ Self :: new ( f3_light_client:: F3_LIGHT_CLIENT_ACTOR_ID )
405+ }
406+ }
407+
408+ impl F3LightClientCaller {
409+ pub fn new ( actor_id : ActorID ) -> Self {
410+ Self { actor_id }
411+ }
412+ }
413+
414+ impl < DB : Blockstore + Clone > F3LightClientCaller {
415+ /// Get the current F3 light client state.
416+ ///
417+ /// Returns the instance ID, finalized epochs, and power table.
418+ pub fn get_state (
419+ & self ,
420+ state : & mut FvmExecState < DB > ,
421+ ) -> anyhow:: Result < f3_light_client:: GetStateResponse > {
422+ let method_num = f3_light_client:: Method :: GetState as u64 ;
423+ let params = RawBytes :: default ( ) ; // No params needed for GetState
424+
425+ let msg = fvm_shared:: message:: Message {
426+ from : fvm_shared:: address:: Address :: new_id ( fvm_shared:: SYSTEM_ACTOR_ID ) ,
427+ to : fvm_shared:: address:: Address :: new_id ( self . actor_id ) ,
428+ sequence : 0 ,
429+ gas_limit : 10_000_000_000 ,
430+ method_num,
431+ params,
432+ value : TokenAmount :: zero ( ) ,
433+ version : 0 ,
434+ gas_fee_cap : TokenAmount :: zero ( ) ,
435+ gas_premium : TokenAmount :: zero ( ) ,
436+ } ;
437+
438+ let ret = state
439+ . execute_implicit ( msg)
440+ . context ( "failed to call F3LightClientActor GetState" ) ?;
441+
442+ if !ret. msg_receipt . exit_code . is_success ( ) {
443+ bail ! (
444+ "F3LightClientActor GetState returned exit code: {:?}" ,
445+ ret. msg_receipt. exit_code
446+ ) ;
447+ }
448+
449+ let response: f3_light_client:: GetStateResponse =
450+ fvm_ipld_encoding:: from_slice ( & ret. msg_receipt . return_data )
451+ . context ( "failed to decode GetStateResponse" ) ?;
452+
453+ Ok ( response)
454+ }
455+
456+ /// Update the F3 light client state with a new certificate.
457+ ///
458+ /// This should be called after successfully executing a proof-based topdown finality message.
459+ pub fn update_state (
460+ & self ,
461+ state : & mut FvmExecState < DB > ,
462+ new_state : f3_light_client:: LightClientState ,
463+ ) -> anyhow:: Result < ( ) > {
464+ let method_num = f3_light_client:: Method :: UpdateState as u64 ;
465+
466+ let params = f3_light_client:: UpdateStateParams { state : new_state } ;
467+ let params = fvm_ipld_encoding:: RawBytes :: serialize ( params)
468+ . context ( "failed to serialize UpdateStateParams" ) ?;
469+
470+ let msg = fvm_shared:: message:: Message {
471+ from : fvm_shared:: address:: Address :: new_id ( fvm_shared:: SYSTEM_ACTOR_ID ) ,
472+ to : fvm_shared:: address:: Address :: new_id ( self . actor_id ) ,
473+ sequence : 0 ,
474+ gas_limit : 10_000_000_000 ,
475+ method_num,
476+ params,
477+ value : TokenAmount :: zero ( ) ,
478+ version : 0 ,
479+ gas_fee_cap : TokenAmount :: zero ( ) ,
480+ gas_premium : TokenAmount :: zero ( ) ,
481+ } ;
482+
483+ let ret = state
484+ . execute_implicit ( msg)
485+ . context ( "failed to call F3LightClientActor UpdateState" ) ?;
486+
487+ if !ret. msg_receipt . exit_code . is_success ( ) {
488+ bail ! (
489+ "F3LightClientActor UpdateState returned exit code: {:?}" ,
490+ ret. msg_receipt. exit_code
491+ ) ;
492+ }
493+
494+ Ok ( ( ) )
495+ }
496+ }
0 commit comments