-
Notifications
You must be signed in to change notification settings - Fork 47
feat: add F3 proofs cache #1457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
6f22fee to
023528d
Compare
818edfb to
ce61c1d
Compare
fbaa095 to
b34142d
Compare
b34142d to
31feb85
Compare
39e59d6 to
bfdc6f7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this AI-generated? In many places it mentions exact identifiers and full data structures from the current code base. Do we really want to keep such detailed readme in sync with future code changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is AI generated, so updating is quite easy (as we could also have it re-generated on CI?). But I can remove some of the details from it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's up to you, I just shared my opinion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's already out of sync with the actual source code 🙃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there was no need to re-generate it give that there was no final implementation approved.
sergefdrv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did my first round of review and left some comments/questions. I would do another round after getting your answers.
One general suggestion: maybe we should consider removing the persistent storage functionality from this PR and make it simpler and easier to review? We can add it later, in a separate PR. WDYT?
I honestly think that the storage is NOT a big part of the PR so it should be fine with it. |
Then I should review the interplay between the in-memory cache, the persistent storage, and the on-chain state more closely. |
93a1066 to
1747f78
Compare
| StorageProofSpec { | ||
| actor_id: self.gateway_actor_id, | ||
| slot: calculate_storage_slot("", NEXT_CONFIG_NUMBER_STORAGE_SLOT), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Storage slot calculation uses empty string for global config
The second StorageProofSpec for NEXT_CONFIG_NUMBER_STORAGE_SLOT uses an empty string "" for calculate_storage_slot, while the first spec uses self.subnet_id. If nextConfigurationNumber is a global field (not per-subnet), passing an empty string may be intentional, but if it's per-subnet like the first spec, this would generate an incorrect storage slot. The inconsistency between the two specs suggests a potential copy-paste error or misunderstanding of the storage layout.
| "calibrationnet", | ||
| initial_instance, | ||
| ) | ||
| .await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Hardcoded F3 network name in development testing tool
The development tool accepts arbitrary RPC URLs via --rpc-url but hardcodes "calibrationnet" as the F3 network name. The F3 light client uses this network name as part of the BLS signing domain, so if a user points the tool at a mainnet or other network RPC endpoint, certificate validation will silently fail with cryptographic errors rather than a clear message about the network mismatch. The network name parameter is missing from the CLI arguments despite the tool being designed to work with arbitrary RPC endpoints.
sergefdrv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job! Now this PR looks good. I don't have any serious concern, just some small minor suggestions. Feel free to merge at your discretion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's already out of sync with the actual source code 🙃
| "calibrationnet", | ||
| initial_instance, | ||
| ) | ||
| .await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Hardcoded network name prevents multi-network usage
The F3 network name is hardcoded to "calibrationnet" when creating the F3Client, but the binary accepts --rpc-url as a user-configurable parameter implying multi-network support. If a user provides a mainnet or other network RPC URL, the F3 client would be initialized with the wrong network name, causing certificate validation failures or incorrect behavior. The network name parameter is missing from the CLI arguments.
| } else { | ||
| println!("No proof found for instance {}", instance_id); | ||
| println!(); | ||
| println!("Available instances: {:?}", entries.len()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Misleading CLI output shows count instead of instance IDs
In the get_proof function, when a proof is not found, the error message displays "Available instances: X" where X is entries.len() (the count of entries). This is misleading because the label "Available instances" suggests the user will see a list of instance IDs they can query, but instead they only see a number. Compare this to show_stats which correctly labels the count as "Count" and shows actual instance IDs separately. Users who see "Available instances: 5" would reasonably expect to see something like [100, 101, 102, 103, 104] so they know which specific instances to query.
| /// This captures validator power changes that need to be reflected in the subnet | ||
| pub const NEW_POWER_CHANGE_REQUEST_SIGNATURE: &str = | ||
| "NewPowerChangeRequest(PowerOperation,address,bytes,uint64)"; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Event signatures use non-canonical Solidity types
NEW_TOPDOWN_MESSAGE_SIGNATURE and NEW_POWER_CHANGE_REQUEST_SIGNATURE use IpcEnvelope and PowerOperation type names, but Ethereum event topics are derived from canonical ABI types (structs as tuples, enums as uint8). This likely makes EventProofSpec.event_signature hash to the wrong topic0, so event proofs won’t match logs and generated bundles can be incomplete/invalid.
| /// This captures validator power changes that need to be reflected in the subnet | ||
| pub const NEW_POWER_CHANGE_REQUEST_SIGNATURE: &str = | ||
| "NewPowerChangeRequest(PowerOperation,address,bytes,uint64)"; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Incorrect Solidity event signatures in proofs
NEW_TOPDOWN_MESSAGE_SIGNATURE and NEW_POWER_CHANGE_REQUEST_SIGNATURE use custom type names (IpcEnvelope, PowerOperation) instead of ABI canonical types (tuple(...) for structs and uint8 for enums). Any filtering/proof generation keyed off these signatures will not match actual event topics, leading to missing/invalid event proofs.
| /// Bindings: contract_bindings::lib_power_change_log::NewPowerChangeRequestFilter | ||
| /// This captures validator power changes that need to be reflected in the subnet | ||
| pub const NEW_POWER_CHANGE_REQUEST_SIGNATURE: &str = | ||
| "NewPowerChangeRequest(PowerOperation,address,bytes,uint64)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Incorrect event signature strings for proofs
The constants NEW_TOPDOWN_MESSAGE_SIGNATURE and NEW_POWER_CHANGE_REQUEST_SIGNATURE use non-canonical Solidity types (IpcEnvelope, PowerOperation) instead of ABI-canonical types (tuples/underlying integer). This likely produces mismatched topic hashes during proof generation, causing event proofs to miss real NewTopDownMessage/NewPowerChangeRequest logs.
| slot: calculate_storage_slot("", NEXT_CONFIG_NUMBER_STORAGE_SLOT), | ||
| }, | ||
| ] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Wrong storage slot computation for config number
build_storage_specs computes the nextConfigurationNumber slot via calculate_storage_slot(\"\", NEXT_CONFIG_NUMBER_STORAGE_SLOT). If nextConfigurationNumber is a plain storage slot (not a mapping keyed by a string), hashing with an empty key will target a different slot and generate invalid storage proofs.
| }, | ||
| StorageProofSpec { | ||
| actor_id: self.gateway_actor_id, | ||
| slot: calculate_storage_slot("", NEXT_CONFIG_NUMBER_STORAGE_SLOT), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Incorrect storage slot calculation for nextConfigurationNumber
The NEXT_CONFIG_NUMBER_STORAGE_SLOT constant is set to 20, but according to the contract storage layout JSON files, PowerChangeLog (containing nextConfigurationNumber) is stored at slot 9 within ParentValidatorsTracker. The comment claims "nextConfigurationNumber is at slot 20" but this doesn't match the actual storage layout. Additionally, calculate_storage_slot("", NEXT_CONFIG_NUMBER_STORAGE_SLOT) passes an empty string for the key, which may produce incorrect results if the function expects a mapping key for slot calculation. This could cause storage proofs to reference the wrong slot, leading to proof verification failures.
Close #1440
Note
Introduce an F3 proof generation and caching service (with RocksDB, metrics, and verifier), wire it into Fendermint and add CLI tools to inspect/manage the cache; also sync contract event/signature markers and minor CI/test tweaks.
fendermint/vm/topdown/proof-servicecrate for F3 certificate validation, proof bundle assembly, two-level cache (in-memory + RocksDB), persistence, metrics, and verification (assembler.rs,cache.rs,persistence.rs,service.rs,verifier.rs).launch_service(...)API and a dev binaryproof-cache-test.fendermint_vm_topdown_proof_serviceand include it in workspace.fendermint proof-cache {inspect|stats|get|clear}for cache management.LibGateway.sol,LibGatewayActorStorage.sol,LibPowerChangeLog.sol, andSubnet.solto stay in sync with proof-service.npm install -g @cyfrin/aderyn.parking_lot,humantime-serde; bumpbls-signaturesto0.15; updateCargo.tomlmembers.Written by Cursor Bugbot for commit b0213ec. This will update automatically on new commits. Configure here.