Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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