Skip to content

Commit

Permalink
feat: allow using of current block in inclusion proofs (#4285)
Browse files Browse the repository at this point in the history
Fixes #4274
  • Loading branch information
benesjan authored Jan 30, 2024
1 parent 018177b commit 728c5ac
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 64 deletions.
64 changes: 36 additions & 28 deletions yarn-project/aztec-nr/aztec/src/oracle/header.nr
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,40 @@ unconstrained pub fn get_header_at_internal(block_number: u32) -> Header {
}

pub fn get_header_at(block_number: u32, context: PrivateContext) -> Header {
// 1) Get block number corresponding to the last_archive root in the header
// Note: We subtract 1 because the last_archive root is the root of the archive after applying the previous block
let last_archive_block_number = (context.historical_header.global_variables.block_number - 1) as u32;

// 2) Check that the last archive block number is more than or equal to the block number we want to prove against
// We could not perform the proof otherwise because the last archive root from the header would not "contain"
// the header we want to prove against
assert(
last_archive_block_number >= block_number, "Last archive block number is smaller than the block number we want to prove against"
);

// 3) Get the header of a given block from oracle
let header = get_header_at_internal(block_number);

// 4) Compute the block hash from the block header
let block_hash = header.block_hash();

// 5) Get the membership witness of the block in the archive
let witness = get_archive_membership_witness(last_archive_block_number, block_hash);

// 6) Check that the block is in the archive (i.e. the witness is valid)
assert(
context.historical_header.last_archive.root
== compute_merkle_root(block_hash, witness.index, witness.path), "Proving membership of a block in archive failed"
);

// 7) Return the block header
header
let historical_header_block_number = context.historical_header.global_variables.block_number as u32;

if (block_number == historical_header_block_number) {
// If the block number we want to prove against is the same as the block number in the historical header we
// skip the inclusion proofs and just return the historical header from context.
context.historical_header
} else {
// 1) Get block number corresponding to the last_archive root in the header
// Note: We subtract 1 because the last_archive root is the root of the archive after applying the previous block
let last_archive_block_number = historical_header_block_number - 1;

// 2) Check that the last archive block number is more than or equal to the block number we want to prove against
// We could not perform the proof otherwise because the last archive root from the header would not "contain"
// the header we want to prove against
assert(
last_archive_block_number >= block_number, "Last archive block number is smaller than the block number we want to prove against"
);

// 3) Get the header of a given block from oracle
let header = get_header_at_internal(block_number);

// 4) Compute the block hash from the block header
let block_hash = header.block_hash();

// 5) Get the membership witness of the block in the archive
let witness = get_archive_membership_witness(last_archive_block_number, block_hash);

// 6) Check that the block is in the archive (i.e. the witness is valid)
assert(
context.historical_header.last_archive.root
== compute_merkle_root(block_hash, witness.index, witness.path), "Proving membership of a block in archive failed"
);

// 7) Return the block header
header
}
}
37 changes: 4 additions & 33 deletions yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ describe('e2e_inclusion_proofs_contract', () => {
expect(receivedOwner).toEqual(owner.toField());
}

// We advance block to be able to prove against block with `noteCreationBlockNumber` --> we have to do this
// because `last_archive` root in the `Header` of aztec-nr contexts is the root of the archive after applying
// the previous block and not the current one.
await advanceBlock();

{
// Prove note inclusion in a given block.
const ignoredCommitment = 0; // Not ignored only when the note doesn't exist
Expand All @@ -88,7 +83,7 @@ describe('e2e_inclusion_proofs_contract', () => {
// Prove that the note has not been nullified
// TODO(#3535): Prove the nullifier non-inclusion at older block to test archival node. This is currently not
// possible because of issue https://github.com/AztecProtocol/aztec-packages/issues/3535
const blockNumber = await getLatestUsableBlockNumber();
const blockNumber = await pxe.getBlockNumber();
const ignoredNullifier = 0; // Not ignored only when the note doesn't exist
await contract.methods.test_nullifier_non_inclusion_proof(owner, blockNumber, ignoredNullifier).send().wait();
}
Expand All @@ -99,10 +94,7 @@ describe('e2e_inclusion_proofs_contract', () => {
const { newNullifiers } = receipt.debugInfo!;
expect(newNullifiers.length).toBe(2);

// Once again we advance the block to be able to access the correct archive root,
await advanceBlock();

const blockNumber = await getLatestUsableBlockNumber();
const blockNumber = await pxe.getBlockNumber();
const nullifier = newNullifiers[1];
// Note: getLowNullifierMembershipWitness returns the membership witness of the nullifier itself and not
// the low nullifier when the nullifier already exists in the tree and for this reason the execution fails
Expand Down Expand Up @@ -134,11 +126,6 @@ describe('e2e_inclusion_proofs_contract', () => {
expect(receivedOwner).toEqual(owner.toField());
}

// We advance block to be able to prove against block with `noteCreationBlockNumber` --> we have to do this
// because `last_archive` root in the `Header` of aztec-nr contexts is the root of the archive after applying
// the previous block and not the current one.
await advanceBlock();

{
// Prove note validity
await contract.methods.test_note_validity_proof(owner, noteCreationBlockNumber).send().wait();
Expand Down Expand Up @@ -264,26 +251,10 @@ describe('e2e_inclusion_proofs_contract', () => {
});

const getRandomBlockNumberSinceDeployment = async () => {
return (
deploymentBlockNumber + Math.floor(Math.random() * ((await getLatestUsableBlockNumber()) - deploymentBlockNumber))
);
return deploymentBlockNumber + Math.floor(Math.random() * ((await pxe.getBlockNumber()) - deploymentBlockNumber));
};

const getRandomBlockNumber = async () => {
return (
deploymentBlockNumber + Math.floor(Math.random() * ((await getLatestUsableBlockNumber()) - INITIAL_L2_BLOCK_NUM))
);
};

const getLatestUsableBlockNumber = async () => {
const currentBlockNumber = await pxe.getBlockNumber();
// Note: We subtract 1 from current because the `last_archive` root in the `Header` of aztec-nr contexts is
// the root of the archive after applying the previous block and not the current one.
return currentBlockNumber - 1;
};

// We advance block by sending a transaction calling empty function on our contract.
const advanceBlock = async () => {
await contract.methods.empty().send().wait();
return deploymentBlockNumber + Math.floor(Math.random() * ((await pxe.getBlockNumber()) - INITIAL_L2_BLOCK_NUM));
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,6 @@ contract InclusionProofs {
// Here typically the factory would add the contract address to its internal map of deployed contracts.
}

#[aztec(private)]
fn empty() {}

// Computes note hash and nullifier.
// Note 1: Needs to be defined by every contract producing logs.
// Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes.
Expand Down

0 comments on commit 728c5ac

Please sign in to comment.