Skip to content
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

Storage Proofs: BlockDigest -> DomainRuntimeUpgrades & merge AllowList #3329

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

teor2345
Copy link
Contributor

@teor2345 teor2345 commented Dec 23, 2024

This PR replaces the block digest storage proof with the existing runtime upgrade records storage proof, and merges the allow list storage proof into the common storage proof.

It also cleans up the associated struct hierarchy, and bumps the runtime version.

Part of ticket #3281.

Code contributor checklist:

@teor2345 teor2345 added execution Subspace execution breaking-runtime This PR introduces breaking changes to the runtime labels Dec 23, 2024
@teor2345 teor2345 self-assigned this Dec 23, 2024
@@ -1048,7 +1048,9 @@ impl FraudProofStorageKeyProvider<NumberFor<Block>> for StorageKeyProvider {
FraudProofStorageKeyRequest::DomainAllowlistUpdates(domain_id) => {
Messenger::domain_allow_list_update_storage_key(domain_id)
}
FraudProofStorageKeyRequest::BlockDigest => sp_domains::system_digest_final_key(),
FraudProofStorageKeyRequest::DomainRuntimeUpgrades => {
pallet_domains::DomainRuntimeUpgrades::<Runtime>::hashed_key().to_vec()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be using DomainRuntimeUpgradeRecords or DomainRuntimeUpgrades for the parent block instead?

(pallet_domains::Hooks::on_initialize() clears the contents of DomainRuntimeUpgrades using take().)

Copy link
Member

@NingLin-P NingLin-P Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is failing with Invalid Domain extrinsic root proof verification failed: StorageProof(DomainRuntimeUpgradesStorageProof(MissingValue)), and yes this is because we clear the contents of DomainRuntimeUpgrades using take() and this value does not exist in the Merkle tree thus we are unable to generate a storage proof (which is a proof of existence).

To fix it we need to instead reset the DomainRuntimeUpgrades to an empty vec so we can generate a proof-of-empty-value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you find this failure in the logs?

All I can see is a test hang (not a test failure):
https://github.com/autonomys/subspace/actions/runs/12459186519/job/34775706616?pr=3329#step:11:1535

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I run the test locally cargo test -p domain-client-operator -- --exact tests::test_invalid_domain_extrinsics_root_proof_creation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix it we need to instead reset the DomainRuntimeUpgrades to an empty vec so we can generate a proof-of-empty-value.

But an empty value doesn't work with the rest of the code, which needs a list of upgraded runtime IDs:
https://github.com/autonomys/subspace/pull/3329/files#diff-4828b750acc5f6c044ce5281811e58a5135ab6b80541bd805a1dde9281159f9fR344-R346

So I think we should be using DomainRuntimeUpgradeRecords instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty list (or a list that doesn't contain the domain's runtime id) means there is no domain runtime upgrade happening, so we don't need to generate the runtime code storage proof. In this way, if a bad ER claims there is a domain runtime upgrade happened, the FP can prove that there is actually not and prune the bad ER and slash the submitter.

The problem with using DomainRuntimeUpgradeRecords is if a domain runtime upgrade happens in #N then the record is added to the state at #N+1 and the record is clear from the state at #N+1+challenge period.

@teor2345 teor2345 enabled auto-merge December 23, 2024 08:00
@teor2345 teor2345 force-pushed the fraud-proof-data-digest branch from f657e5c to 2f3a9b6 Compare December 23, 2024 23:46
@teor2345 teor2345 changed the title Replace BlockDigest with DomainRuntimeUpgrades storage proof Storage Proofs: BlockDigest -> DomainRuntimeUpgrades & merge AllowList Dec 23, 2024
@teor2345 teor2345 force-pushed the fraud-proof-data-digest branch from 2f3a9b6 to a0a7dd3 Compare December 24, 2024 01:41
@teor2345 teor2345 force-pushed the fraud-proof-data-digest branch from a0a7dd3 to 0c39996 Compare December 24, 2024 02:21
Comment on lines +1949 to +1951
let domain_chain_allowlist =
T::DomainAllowlistUpdates::domain_allowlist_updates(domain_id)
.unwrap_or_default();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it because of the allowlist update we need to store the InvalidInherentExtrinsicData for each domain separately?

While most of the data are the same for all the domain I think it makes more sense to store them once and shared by all the domains, for the allowlist update we can store Map<domain_id, AllowlistUpdate> which may bring redundant data in the FP but it should be fine as FP and the allowlist update are rare.

Comment on lines +1871 to +1872
// At genesis, avoid block number underflow, and use the default zero genesis parent hash.
let parent_number = block_number.checked_sub(&One::one());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC there should be no on_initialize/on_finalize for the genesis block, the genesis block is built from the chain spec with genesis_build, also see https://github.com/paritytech/polkadot-sdk/blob/ca7817922148c1e6f6856138998f7135f42f3f4f/substrate/frame/system/src/lib.rs#L1812.

cc @vedhavyas @nazar-pc in case I'm wrong.

#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: Cow::Borrowed("subspace"),
impl_name: Cow::Borrowed("subspace"),
authoring_version: 0,
spec_version: 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consensus runtime version is already bumped in 4ba268a.

As a good practice, I think we should bump the runtime version when we are going to do runtime upgrade instead of when there are runtime code change to avoid bumping the version multiple times by accident.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-runtime This PR introduces breaking changes to the runtime execution Subspace execution
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants