Skip to content

fix: constrain proposed block header#13693

Merged
LeilaWang merged 13 commits into
masterfrom
lw/constrain_proposed_block
Apr 27, 2025
Merged

fix: constrain proposed block header#13693
LeilaWang merged 13 commits into
masterfrom
lw/constrain_proposed_block

Conversation

@LeilaWang

@LeilaWang LeilaWang commented Apr 20, 2025

Copy link
Copy Markdown
Contributor

@LeilaWang LeilaWang linked an issue Apr 22, 2025 that may be closed by this pull request
@LeilaWang LeilaWang force-pushed the lw/constrain_proposed_block branch from 8d76e49 to ece49b0 Compare April 22, 2025 14:49
bytes calldata _blobPublicInputs
) internal view returns (bytes32[] memory) {
RollupStore storage rollupStore = STFLib.getStorage();
// Args are defined as an array because Solidity complains with "stack too deep" otherwise

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removing the comment as it's not an array anymore.

uint256 pendingBlockNumber = STFLib.getEffectivePendingBlockNumber(_args.currentTime);

require(
_args.header.globalVariables.blockNumber == pendingBlockNumber + 1,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We don't need to check the block number here because in the block merge rollup circuit we ensure that consecutive block numbers are incrementing by 1. And when proving an epoch, we check that the first block number is correct, by checking previousArchive.nextAvailableLeafIndex. So the block numbers after the first block are also guaranteed to be correct.

// @note: not view as sampling validators uses tstore
function validateHeader(ValidateHeaderArgs memory _args) internal {
require(
block.chainid == _args.header.globalVariables.chainId,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

chainId and version are propagated to root and checked once per epoch.

@MirandaWood MirandaWood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thought I'd have more to say considering the number of files, but all looks great and very clean! LGTM

+ 1 /* protocol_contract_tree_root */
+ 1 /* prover_id */
+ AZTEC_MAX_EPOCH_DURATION * BLOB_PUBLIC_INPUTS * BLOBS_PER_BLOCK;
// + 6 for end_timestamp, end_block_number, out_hash, vk_tree_root, protocol_contract_tree_root, prover_id

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this referred to ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH which you've nicely broken up below so can be removed!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this!

Comment on lines +79 to +89
function updateHeaderArchive(bytes memory _header, bytes32 _archive)
internal
pure
returns (bytes memory)
{
assembly {
mstore(add(_header, 0x20), _archive)
}
return _header;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for adding these, I always hated editing the assembly for these use cases!!

@LeilaWang LeilaWang added this pull request to the merge queue Apr 27, 2025
Merged via the queue into master with commit a1f94c3 Apr 27, 2025
@LeilaWang LeilaWang deleted the lw/constrain_proposed_block branch April 27, 2025 10:51
};

retrievedBlocks.push({ ...block, l1 });
const chainId = new Fr(await publicClient.getChainId());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should be called outside the loop

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That makes way more sense! Will change this.

private sender: EthAddress | undefined;

constructor(
/** The block number of the attestation. */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Having block number outside the consensus payload here means that attesting nodes are not directly checking it, which means it will only be caught at proving time. Im not sure we want this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't know if I miss anything, but this block number is only used in debug logs so I thought it should be fine throwing it in via constructor?

retrievedBlocks.push({ ...block, l1 });
const chainId = new Fr(await publicClient.getChainId());

const version = new Fr(await rollup.read.getVersion({ blockNumber: log.blockNumber }));

@LHerskind LHerskind Apr 28, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When this is passing along blockNumber as this, it will likely try to run at that point in time, which could make it explode as historical execution. You can remove the blockNumber part, for the same contract the value will not change. Also as @Maddiaa0 said above, can be done outside the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: block header not being verified on L1

4 participants