Skip to content
Merged
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
80 changes: 62 additions & 18 deletions noir-projects/aztec-nr/aztec/src/oracle/header.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use dep::protocol_types::{constants::HEADER_LENGTH, header::Header};

use crate::{context::PrivateContext, oracle::get_membership_witness::get_archive_membership_witness};

use crate::test::helpers::test_environment::TestEnvironment;

#[oracle(getHeader)]
unconstrained fn get_header_at_oracle(_block_number: u32) -> [Field; HEADER_LENGTH] {}

Expand All @@ -12,16 +14,17 @@ unconstrained pub fn get_header_at_internal(block_number: u32) -> Header {
}

pub fn get_header_at(block_number: u32, context: PrivateContext) -> Header {
let historical_header_block_number = context.historical_header.global_variables.block_number as u32;
let header = context.historical_header;
let current_block_number = header.global_variables.block_number as u32;

if (block_number == historical_header_block_number) {
if (block_number == current_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
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;
let last_archive_block_number = current_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"
Expand All @@ -30,22 +33,63 @@ pub fn get_header_at(block_number: u32, context: PrivateContext) -> Header {
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.hash();
// 3) Get the header hint of a given block from an oracle
let historical = get_header_at_internal(block_number);

// 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
== root_from_sibling_path(block_hash, witness.index, witness.path), "Proving membership of a block in archive failed"
// 4) We make sure that the header hint we received from the oracle exists in the state tree and is the actual header
// at the desired block number
constrain_get_header_at_internal(
historical,
block_number,
last_archive_block_number,
header.last_archive.root
);

// 7) Return the block header
header
// 5) Return the block header
historical
}
}

fn constrain_get_header_at_internal(
header_hint: Header,
block_number: u32,
last_archive_block_number: u32,
last_archive_root: Field
) {
// 1) Compute the block hash from the block header
let block_hash = header_hint.hash();
Comment on lines +59 to +60
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 was referring to comments of this kind, which are rather useless. This is the famous let x = 5; // set x to 5.


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

// 3) Check that the block is in the archive (i.e. the witness is valid)
assert(
last_archive_root == root_from_sibling_path(block_hash, witness.index, witness.path), "Proving membership of a block in archive failed"
);

// 4) Check that the header hint has the same block number as the block number we are looking for, ensuring we are actually grabbing the header we specify
assert(
header_hint.global_variables.block_number as u32 == block_number, "Block number provided is not the same as the block number from the header hint"
);
}

#[test(should_fail_with = "Block number provided is not the same as the block number from the header hint")]
fn fetching_a_valid_but_different_header_should_fail() {
let mut env = TestEnvironment::new();

env.advance_block_to(3);

// We get our current header for the last archive values.
let current_header = env.private().historical_header;

let target_block_number = 2;
let bad_header = get_header_at_internal(target_block_number - 1);

// We pass in a different block number than the header received
constrain_get_header_at_internal(
bad_header,
2,
current_header.global_variables.block_number as u32 - 1,
current_header.last_archive.root
);
}