Skip to content

Commit 82d5f04

Browse files
committed
feat: finish implementing e2e
1 parent 0514cd9 commit 82d5f04

File tree

18 files changed

+643
-280
lines changed

18 files changed

+643
-280
lines changed

Cargo.lock

Lines changed: 12 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fendermint/app/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ tracing-appender = { workspace = true }
4545
tracing-subscriber = { workspace = true }
4646
literally = { workspace = true }
4747
url = { workspace = true }
48+
ethers = { workspace = true }
4849

4950
fendermint_abci = { path = "../abci" }
51+
ipc_actors_abis = { path = "../../contract-bindings" }
5052
actors-custom-api = { path = "../actors/api" }
5153
fendermint_actor_f3_light_client = { path = "../actors/f3-light-client" }
5254
fendermint_app_options = { path = "./options" }

fendermint/app/config/default.toml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,51 @@ vote_interval = 1
273273
# pausing the syncer, preventing new events to trigger votes.
274274
vote_timeout = 60
275275

276+
# # Top-down checkpoint configuration (uncomment to enable parent syncing)
277+
# [ipc.topdown]
278+
# # Number of blocks to delay before considering a parent block final
279+
# chain_head_delay = 10
280+
# # Additional delay on top of chain_head_delay before proposing finality
281+
# proposal_delay = 5
282+
# # Maximum number of blocks to propose in a single checkpoint
283+
# max_proposal_range = 100
284+
# # Maximum number of blocks to cache (optional)
285+
# # max_cache_blocks = 1000
286+
# # Parent syncing cron period, in seconds
287+
# polling_interval = 30
288+
# # Exponential backoff retry base, in seconds
289+
# exponential_back_off = 5
290+
# # Maximum number of retries before giving up
291+
# exponential_retry_limit = 5
292+
# # Parent HTTP RPC endpoint
293+
# parent_http_endpoint = "http://api.calibration.node.glif.io/rpc/v1"
294+
# # Parent HTTP timeout (optional), in seconds
295+
# # parent_http_timeout = 60
296+
# # Bearer token for Authorization header (optional)
297+
# # parent_http_auth_token = "your-token-here"
298+
# # Parent registry address
299+
# parent_registry = "0x74539671a1d2f1c8f200826baba665179f53a1b7"
300+
# # Parent gateway address
301+
# parent_gateway = "0x77aa40b105843728088c0132e43fc44348881da8"
302+
#
303+
# # F3 proof service configuration (optional - for proof-based parent finality)
304+
# # Requires genesis to have F3 parameters configured
305+
# [ipc.topdown.proof_service]
306+
# # Enable F3 proof-based parent finality (default: false)
307+
# enabled = false
308+
# # F3 network name - must match parent chain ("calibrationnet", "mainnet")
309+
# f3_network_name = "calibrationnet"
310+
# # How often to poll parent chain for new F3 certificates, in seconds
311+
# polling_interval = 30
312+
# # How many F3 instances ahead to pre-generate proofs (lookahead window)
313+
# lookahead_instances = 5
314+
# # How many old instances to keep after commitment (retention window)
315+
# retention_instances = 2
316+
# # Gateway actor ID on parent chain (optional - derived from genesis if not set)
317+
# # gateway_actor_id = 176609
318+
# # Or use Ethereum address (will be resolved to actor ID)
319+
# # gateway_eth_address = "0xE4c61299c16323C4B58376b60A77F68Aa59afC8b"
320+
276321
# # Setting which are only allowed if the `--network` CLI parameter is `testnet`.
277322
# [testing]
278323

fendermint/app/settings/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ ipc-observability = { path = "../../../ipc/observability" }
3232

3333
fendermint_vm_encoding = { path = "../../vm/encoding" }
3434
fendermint_vm_topdown = { path = "../../vm/topdown" }
35+
fendermint_vm_topdown_proof_service = { path = "../../vm/topdown/proof-service" }

fendermint/app/settings/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,59 @@ pub struct TopDownSettings {
226226
/// The parent gateway address
227227
#[serde(deserialize_with = "deserialize_eth_address_from_str")]
228228
pub parent_gateway: Address,
229+
/// F3 proof service configuration (optional - for proof-based finality)
230+
#[serde(default)]
231+
pub proof_service: Option<ProofServiceSettings>,
232+
}
233+
234+
/// F3 proof service settings for proof-based parent finality
235+
#[serde_as]
236+
#[derive(Debug, Deserialize, Serialize, Clone)]
237+
pub struct ProofServiceSettings {
238+
/// Enable F3 proof-based finality
239+
pub enabled: bool,
240+
241+
/// F3 network name ("calibrationnet", "mainnet")
242+
pub f3_network_name: String,
243+
244+
/// Polling interval for checking parent F3 certificates
245+
#[serde_as(as = "DurationSeconds<u64>")]
246+
pub polling_interval: Duration,
247+
248+
/// Instances to generate ahead (lookahead)
249+
pub lookahead_instances: u64,
250+
251+
/// Instances to retain after commitment
252+
pub retention_instances: u64,
253+
254+
/// Gateway actor ID on parent (optional - can derive from genesis)
255+
pub gateway_actor_id: Option<u64>,
256+
257+
/// Gateway Ethereum address (alternative to actor ID)
258+
pub gateway_eth_address: Option<String>,
259+
}
260+
261+
impl ProofServiceSettings {
262+
/// Convert to proof service crate's config type
263+
pub fn to_proof_service_config(
264+
&self,
265+
parent_subnet_id: &str,
266+
) -> fendermint_vm_topdown_proof_service::ProofServiceConfig {
267+
fendermint_vm_topdown_proof_service::ProofServiceConfig {
268+
enabled: self.enabled,
269+
polling_interval: self.polling_interval,
270+
lookahead_instances: self.lookahead_instances,
271+
retention_instances: self.retention_instances,
272+
parent_rpc_url: String::new(), // Will be filled from topdown settings
273+
parent_subnet_id: parent_subnet_id.to_string(),
274+
f3_network_name: self.f3_network_name.clone(),
275+
fallback_rpc_urls: vec![],
276+
max_cache_size_bytes: 0,
277+
gateway_actor_id: self.gateway_actor_id,
278+
gateway_eth_address: self.gateway_eth_address.clone(),
279+
subnet_id: None, // Will be filled from IPC settings
280+
}
281+
}
229282
}
230283

231284
#[serde_as]

fendermint/app/src/app.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use fendermint_storage::{
2323
};
2424
use fendermint_vm_core::Timestamp;
2525
use fendermint_vm_interpreter::fvm::state::{
26-
empty_state_tree, CheckStateRef, FvmExecState, FvmQueryState, FvmStateParams,
27-
FvmUpdatableParams,
26+
empty_state_tree, ipc::F3LightClientCaller, CheckStateRef, FvmExecState, FvmQueryState,
27+
FvmStateParams, FvmUpdatableParams,
2828
};
2929
use fendermint_vm_interpreter::fvm::store::ReadOnlyBlockstore;
3030
use fendermint_vm_interpreter::genesis::{read_genesis_car, GenesisAppState};
@@ -36,6 +36,7 @@ use fendermint_vm_interpreter::types::{
3636
use fendermint_vm_interpreter::MessagesInterpreter;
3737

3838
use crate::ipc::derive_subnet_app_hash;
39+
use fendermint_vm_actor_interface::f3_light_client;
3940
use fendermint_vm_interpreter::fvm::end_block_hook::LightClientCommitments;
4041
use fendermint_vm_interpreter::fvm::state::snapshot::SnapshotPayload;
4142
use fendermint_vm_message::query::FvmQueryHeight;
@@ -481,6 +482,61 @@ where
481482
.context("Validator cache is not available")?
482483
.get_validator(id)
483484
}
485+
486+
/// Query the F3 Light Client Actor state after genesis
487+
/// Returns (instance_id, power_table) if F3 is initialized, None otherwise
488+
pub async fn query_f3_state(
489+
&self,
490+
) -> Result<Option<(u64, fendermint_vm_topdown_proof_service::PowerEntries)>> {
491+
// Get committed state to check if genesis has been initialized
492+
let state = self.committed_state()?;
493+
494+
// Don't try to query if state hasn't been initialized by genesis
495+
if !Self::can_query_state(state.app_state.block_height, &state.app_state.state_params) {
496+
return Ok(None);
497+
}
498+
499+
// Create a read-only view of the state
500+
let mut query_state = FvmQueryState::new(
501+
self.state_store_clone(),
502+
self.multi_engine.clone(),
503+
state.app_state.block_height.try_into()?,
504+
state.app_state.state_params.clone(),
505+
self.check_state.clone(),
506+
false, // not pending
507+
)
508+
.context("error creating query state")?;
509+
510+
// Create a temporary exec state to query the actor
511+
let (_, result) = query_state
512+
.with_exec_state(|exec_state| {
513+
let f3_caller = F3LightClientCaller::new();
514+
match f3_caller.get_state(exec_state) {
515+
Ok(state) => {
516+
// For now, we just return the instance ID and an empty power table
517+
// The proof service will fetch the actual power table from the parent chain
518+
Ok(Some((
519+
state.instance_id,
520+
fendermint_vm_topdown_proof_service::PowerEntries(vec![]),
521+
)))
522+
}
523+
Err(e) => {
524+
// F3 actor might not be deployed (non-Filecoin parent)
525+
tracing::debug!("F3 Light Client Actor not found or not accessible: {}", e);
526+
Ok(None)
527+
}
528+
}
529+
})
530+
.await?;
531+
532+
Ok(result)
533+
}
534+
535+
/// Get access to the messages interpreter
536+
/// Used to access the TopDownManager for updating the proof cache
537+
pub fn interpreter(&self) -> &Arc<MI> {
538+
&self.messages_interpreter
539+
}
484540
}
485541

486542
// NOTE: The `Application` interface doesn't allow failures at the moment. The protobuf

0 commit comments

Comments
 (0)