Skip to content

Conversation

@bkchr
Copy link
Member

@bkchr bkchr commented Apr 7, 2025

This pull requests implements support for ignoring trie nodes while recording a proof. It directly includes the feature into basic-authorship to later make use of it in Cumulus for multi-block PoVs.

The idea behind this is when you have multiple blocks per PoV that trie nodes accessed or produced by a block before (in the same PoV), are not required to be added to the storage proof again. So, all the blocks in one PoV basically share the same storage proof. This also impacts things like storage weight reclaim, because ignored trie node do not contribute a to the storage proof size (similar to when this would happen in the same block).

Example

Let's say block A access key X and block B accesses key X again. As A already has read it, we know that it is part of the storage proof and thus, don't need to add it again to the storage proof when building B. The same applies for storage values produced by an earlier block (in the same PoV). These storage values are an output of the execution and thus, don't need to be added to the storage proof :)

Depends on #6137. Base branch will be changed when this got merged.

Part of: #6495

bkchr and others added 30 commits October 16, 2024 22:41
…om:paritytech/polkadot-sdk into bkchr-parachain-block-data-multiple-blocks
@bkchr
Copy link
Member Author

bkchr commented Jun 9, 2025

The one which will re-use the proof-recorder between consecutive blocks built on the same collator?

Yeah exactly. This pull request is just preparing this work. All of this is not yet used.

/// Trie nodes that should not be recorded.
///
/// Only applies when proof recording is enabled.
pub ignored_nodes_by_proof_recording: Option<IgnoredNodes<Block::Hash>>,
Copy link
Contributor

@michalkucharczyk michalkucharczyk Jun 10, 2025

Choose a reason for hiding this comment

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

Had a second thought here.

Maybe instead of providing some specific proof recorder parameters here, it would be better to provide some callback which would allow caller of Proposer API to customize the proof recorder instantiated by proposer internals? This could be more flexible for future extensions.

Something like:

		let maybe_proposal = self
			.proposer
			.propose(
				&parent_header,
				&inherent_data.0,
				inherent_data.1,
				Digest { logs: digest },
				proposal_duration,
				|proof_recorder| { proof_recorder.with_ignored_nodes(ignored_node) },
			)
			.await
			.map_err(|e| Box::new(e) as Box<dyn Error + Send>)?;

Copy link
Contributor

@skunert skunert left a comment

Choose a reason for hiding this comment

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

Overall logic LGTM

fn select_next_core() -> (CoreSelector, ClaimQueueOffset) {
let blocks_per_pov = BlocksPerPoV::get();

if blocks_per_pov == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will break elastic scaling zombienet tests, because they have blocks_per_pov not set, but still require the correct core selector logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

All this code there is quite hacky right now :D blocks_per_pov is 1 by default.

changes.transaction.drain().into_iter().for_each(|(_, (value, count))| {
// We only care about inserts and not deletes.
if count > 0 {
db.insert(EMPTY_PREFIX, &value);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is up with this EMPTY_PREFIX here? I see that internally, the value is hashed for the key. Makes sense, but when would we need the prefix here?

Copy link
Member Author

Choose a reason for hiding this comment

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

We are using a HashKey, that ignores the prefix. The prefix would be important if we use a PrefixKey (this is used by changes.transaction).

In the end what is happening here is that we use the hash of value as key and EMPTY_PREFIX is ignored.

@bkchr
Copy link
Member Author

bkchr commented Jun 18, 2025

/cmd prdoc --audience node_dev

@skunert skunert self-requested a review July 14, 2025 17:44
@paritytech-workflow-stopper
Copy link

All GitHub workflows were cancelled due to failure one of the required jobs.
Failed workflow url: https://github.com/paritytech/polkadot-sdk/actions/runs/16632483207
Failed job name: fmt

@bkchr
Copy link
Member Author

bkchr commented Jul 30, 2025

/cmd fmt

@bkchr bkchr added this pull request to the merge queue Jul 31, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 31, 2025
@alvicsam alvicsam added this pull request to the merge queue Jul 31, 2025
Merged via the queue into master with commit 5633cf5 Jul 31, 2025
242 of 245 checks passed
@alvicsam alvicsam deleted the bkchr-ignore-trie-nodes branch July 31, 2025 10:41
alvicsam pushed a commit that referenced this pull request Oct 17, 2025
This pull requests implements support for ignoring trie nodes while
recording a proof. It directly includes the feature into
`basic-authorship` to later make use of it in Cumulus for multi-block
PoVs.

The idea behind this is when you have multiple blocks per PoV that trie
nodes accessed or produced by a block before (in the same `PoV`), are
not required to be added to the storage proof again. So, all the blocks
in one `PoV` basically share the same storage proof. This also impacts
things like storage weight reclaim, because ignored trie node do not
contribute a to the storage proof size (similar to when this would
happen in the same block).

# Example 

Let's say block `A` access key `X` and block `B` accesses key `X` again.
As `A` already has read it, we know that it is part of the storage proof
and thus, don't need to add it again to the storage proof when building
`B`. The same applies for storage values produced by an earlier block
(in the same PoV). These storage values are an output of the execution
and thus, don't need to be added to the storage proof :)


Depends on #6137. Base
branch will be changed when this got merged.

Part of: #6495

---------

Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T0-node This PR/Issue is related to the topic “node”. T18-zombienet_tests Trigger zombienet CI tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants