Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testv0.2 #15

Closed
wants to merge 6 commits into from
Closed
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
135 changes: 69 additions & 66 deletions starknet/src/L1_headers_store/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ pub mod L1HeaderStore {
use fossil::library::blockheader_rlp_extractor::{
decode_parent_hash, decode_uncle_hash, decode_beneficiary, decode_state_root,
decode_transactions_root, decode_receipts_root, decode_difficulty, decode_base_fee,
decode_timestamp, decode_gas_used
decode_timestamp, decode_gas_used, decode_block_number
};
use fossil::library::{
keccak256::keccak256, keccak_utils::keccak_words64,
mmr_verifier::{verify_proof, extract_state_root}, words64_utils::words64_to_u256
};
use fossil::library::keccak_utils::keccak_words64;
use fossil::library::words64_utils::words64_to_u256;
use fossil::types::ProcessBlockOptions;
use fossil::types::Words64Sequence;
use fossil::types::{BlockRLP, MMRProof, Words64Sequence};
use openzeppelin::access::ownable::OwnableComponent;
// *************************************************************************
// IMPORTS
Expand Down Expand Up @@ -48,19 +50,11 @@ pub mod L1HeaderStore {
ownable: OwnableComponent::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage,
starknet_handler_address: ContractAddress,
l1_messages_origin: ContractAddress,
latest_l1_block: u64,
block_parent_hash: LegacyMap::<u64, u256>,
latest_l1_block_number: u64,
mmr_root_hash: u256,
latest_l1_block_hash: LegacyMap::<u64, u256>,
block_state_root: LegacyMap::<u64, u256>,
block_transactions_root: LegacyMap::<u64, u256>,
block_receipts_root: LegacyMap::<u64, u256>,
block_uncles_hash: LegacyMap::<u64, u256>,
block_beneficiary: LegacyMap::<u64, EthAddress>,
block_difficulty: LegacyMap::<u64, u64>,
block_base_fee: LegacyMap::<u64, u64>,
block_timestamp: LegacyMap::<u64, u64>,
block_gas_used: LegacyMap::<u64, u64>,
}

// *************************************************************************
Expand All @@ -82,17 +76,15 @@ pub mod L1HeaderStore {
///
/// # Arguments
/// * `l1_messages_origin` - The address of L1 Message Proxy.
/// * `owner` - .
/// * `admin` - .
#[constructor]
fn constructor(
ref self: ContractState,
l1_messages_origin: starknet::ContractAddress,
owner: starknet::ContractAddress,
starknet_handler_address: starknet::ContractAddress
admin: starknet::ContractAddress
) {
self.l1_messages_origin.write(l1_messages_origin);
self.ownable.initializer(owner);
self.starknet_handler_address.write(starknet_handler_address);
self.ownable.initializer(admin);
}

// *************************************************************************
Expand All @@ -115,10 +107,10 @@ pub mod L1HeaderStore {
get_caller_address() == self.l1_messages_origin.read(),
"L1HeaderStore: unauthorized caller"
);
self.block_parent_hash.write(block_number, parent_hash);
self.latest_l1_block_hash.write(block_number, parent_hash);

if self.latest_l1_block.read() <= block_number {
self.latest_l1_block.write(block_number);
if self.latest_l1_block_number.read() <= block_number {
self.latest_l1_block_number.write(block_number);
}
}

Expand All @@ -133,61 +125,79 @@ pub mod L1HeaderStore {
self.l1_messages_origin.write(l1_messages_origin);
}

fn store_state_root(ref self: ContractState, block_number: u64, state_root: u256) {
self.assert_only_starknet_handler();
assert!(
self.block_state_root.read(block_number) == 0,
"L1HeaderStore: state root already exists"
);
self.block_state_root.write(block_number, state_root);
/// Change MMR root hash. (Only Owner)
///
/// # Arguments
/// * `new_root` - The new MMR root hash.
fn set_latest_mmr_root(ref self: ContractState, new_root: u256) {
self.ownable.assert_only_owner();
self.mmr_root_hash.write(new_root);
}

fn store_many_state_roots(
ref self: ContractState, start_block: u64, end_block: u64, state_roots: Array<u256>
) {
self.assert_only_starknet_handler();
assert!(
state_roots.len().into() == (end_block - start_block + 1),
"L1HeaderStore: invalid state roots length"
);

let mut start = start_block;
let mut index = 0;
// Verifies the MMR inclusion proof for the block hash.
// Processes the block header RLP encoded data to extract block state root.
// Hashes the block header RLP encoded data and compare to the block hash provided.
// Save the block state root in the contract storage.
fn verify_mmr_inclusion(
ref self: ContractState,
block_number: u64,
block_hash: u256,
mmr_proof: MMRProof,
encoded_block: BlockRLP
) -> Result<bool, felt252> {
let result = verify_proof(block_hash, mmr_proof);

match result {
Result::Ok(result) => {
let encoded_block_hash = keccak256(encoded_block);
let is_encoded_hash_matched = encoded_block_hash == block_hash;

while start <= end_block {
self.store_state_root(start, *state_roots.at(index));
start += 1;
index += 1;
};
match is_encoded_hash_matched {
true => {},
false => { return Result::Err('block hash mismatch'); }
}

let state_root = extract_state_root(encoded_block);

self.block_state_root.write(block_number, state_root);

Result::Ok(result)
},
Result::Err(e) => Result::Err(e)
}
}

/// Retrieves the parent hash of the specified block number.
///
/// # Arguments
/// * `block_number` - The block number for which to retrieve the parent hash.
/// Retrieves the latest block hash stored in the contract.
///
/// # Returns
/// * `u256` - The parent hash.
fn get_parent_hash(self: @ContractState, block_number: u64) -> u256 {
self.block_parent_hash.read(block_number)
/// * `u256` - The latest block hash.
fn get_latest_block_hash(self: @ContractState) -> u256 {
self.latest_l1_block_hash.read(self.latest_l1_block_number.read())
}

/// Retrieves the latest L1 block number stored in the contract.
///
/// # Returns
/// * `u64` - The latest L1 block number.
fn get_latest_l1_block(self: @ContractState) -> u64 {
self.latest_l1_block.read()
fn get_latest_l1_block_number(self: @ContractState) -> u64 {
self.latest_l1_block_number.read()
}

/// Retrieves the state root of the specified block number.
/// Retrieves the MMR root hash stored in the contract.
///
/// # Arguments
/// * `block_number` - The block number for which to retrieve the state root.
/// # Returns
/// * `u256` - The MMR root hash.
fn get_mmr_root(self: @ContractState) -> u256 {
self.mmr_root_hash.read()
}

/// Retrieves the block state root for specific block number stored in
/// the contract.
///
/// # Returns
/// * `u256` - The state root.
fn get_state_root(self: @ContractState, block_number: u64) -> u256 {
/// * `u256` - The block state root.
fn get_block_state_root(self: @ContractState, block_number: u64) -> u256 {
self.block_state_root.read(block_number)
}
}
Expand Down Expand Up @@ -244,12 +254,5 @@ pub mod L1HeaderStore {

(block_header_rlp, block_header_rlp_bytes_len)
}

fn assert_only_starknet_handler(self: @ContractState) {
let caller = get_caller_address();
assert(
caller == self.starknet_handler_address.read(), 'Caller is not starknet handler'
);
}
}
}
22 changes: 14 additions & 8 deletions starknet/src/L1_headers_store/interface.cairo
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
use fossil::types::ProcessBlockOptions;
use fossil::types::{MMRProof, BlockRLP, Words64Sequence};
use starknet::{EthAddress, ContractAddress};

#[starknet::interface]
pub trait IL1HeadersStore<TState> {
fn receive_from_l1(ref self: TState, parent_hash: u256, block_number: u64);
fn change_l1_messages_origin(ref self: TState, l1_messages_origin: starknet::ContractAddress);
fn store_state_root(ref self: TState, block_number: u64, state_root: u256);
fn store_many_state_roots(
ref self: TState, start_block: u64, end_block: u64, state_roots: Array<u256>
);
fn get_parent_hash(self: @TState, block_number: u64) -> u256;
fn get_latest_l1_block(self: @TState) -> u64;
fn get_state_root(self: @TState, block_number: u64) -> u256;
fn verify_mmr_inclusion(
ref self: TState,
block_number: u64,
block_hash: u256,
mmr_proof: MMRProof,
encoded_block: BlockRLP
) -> Result<bool, felt252>;
fn set_latest_mmr_root(ref self: TState, new_root: u256);

fn get_latest_block_hash(self: @TState) -> u256;
fn get_latest_l1_block_number(self: @TState) -> u64;
fn get_mmr_root(self: @TState) -> u256;
fn get_block_state_root(self: @TState, block_number: u64) -> u256;
}
6 changes: 4 additions & 2 deletions starknet/src/fact_registry/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ pub mod FactRegistry {
proof_sizes_bytes: Array<usize>,
proofs_concat: Array<u64>,
) -> Result<bool, felt252> {
let state_root = self.l1_headers_store.read().get_state_root(block);
let state_root = self.l1_headers_store.read().get_block_state_root(block);
assert!(state_root != 0, "FactRegistry: block state root not found");
let proof = self
.reconstruct_ints_sequence_list(proofs_concat.span(), proof_sizes_bytes.span());
let result = verify_proof(account.to_words64(), state_root.to_words64(), proof.span());

match result {
Result::Err(e) => { Result::Err(e) },
Result::Ok(result) => {
Expand Down Expand Up @@ -205,7 +206,8 @@ pub mod FactRegistry {
);

match result {
Result::Err => Result::Err('Error'),
// Result::Err => Result::Err('Error'),
Result::Err(e) => { Result::Err(e) },
Result::Ok(result) => {
if !result.is_some() {
Result::Err('Result is None')
Expand Down
6 changes: 4 additions & 2 deletions starknet/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ pub mod L1_messages_proxy {

pub mod library {
pub mod array_utils;
mod bitshift;
pub mod bitshift;
pub mod blockheader_rlp_extractor;
mod keccak256;
pub mod keccak256;
pub mod keccak_utils;
mod math_utils;
mod merkle_patricia_utils;
pub mod mmr_verifier;
pub mod rlp_utils;
pub mod trie_proof;
pub mod words64_utils;
Expand All @@ -36,6 +37,7 @@ pub mod testing {
pub mod proofs {
pub mod account;
pub mod blocks;
pub mod mmr;
pub mod storage;
}
}
31 changes: 31 additions & 0 deletions starknet/src/library/keccak256.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// make auditing easier. The original code can be found at https://github.com/keep-starknet-strange/alexandria/blob/main/src/math/src/keccak256.cairo

use core::integer::u128_byte_reverse;
use fossil::library::bitshift::BitShift;
use keccak::cairo_keccak;

#[generate_trait]
Expand Down Expand Up @@ -61,3 +62,33 @@ pub fn keccak256(mut self: Span<u8>) -> u256 {
let (last_word, last_word_bytes) = U64Trait::from_le_bytes(self);
reverse_endianness(cairo_keccak(ref words64, last_word, last_word_bytes))
}

pub fn hash_2(a: u256, b: u256) -> u256 {
let a_array = u256_to_big_endian_bytes(a);
let b_array = u256_to_big_endian_bytes(b);
let mut combined = array![];
let mut i = 0;
while i < a_array.len() {
combined.append(*a_array.at(i));
i += 1;
};
i = 0;
while i < b_array.len() {
combined.append(*b_array.at(i));
i += 1;
};
keccak256(combined.span())
}

fn u256_to_big_endian_bytes(num: u256) -> Array<u8> {
let mut out = array![];

let mut i = 0_u32;
while i < 32 {
let byte: u8 = (BitShift::shr(num, ((31 - i) * 8).into()) & 0xFF).try_into().unwrap();
out.append(byte);
i += 1;
};

out
}
Loading
Loading