Skip to content

Commit

Permalink
imt tests
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejka committed Dec 19, 2024
1 parent 01c9d5b commit 2b33000
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 219 deletions.
140 changes: 107 additions & 33 deletions l2/src/bridge_poc.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use core::starknet::ContractAddress;
type L1Address = u256;

#[starknet::interface]
trait IBridgePOC<TContractState> {
pub trait IBridgePOC<TContractState> {
fn deposit(ref self: TContractState, recipient: ContractAddress, amount: u256) {}
fn withdraw(ref self: TContractState, recipient: L1Address, amount: u256) {}
}


#[starknet::contract]
mod BridgePOC {
pub mod BridgePOC {
use core::num::traits::zero::Zero;
use starknet::storage::VecTrait;
use core::starknet::ContractAddress;
use crate::hash::{Digest, DigestTrait};
Expand All @@ -20,10 +20,9 @@ mod BridgePOC {
StoragePointerReadAccess, StoragePointerWriteAccess, Vec, MutableVecTrait,
};
use crate::double_sha256::double_sha256_digests;
use core::num::traits::Bounded;

// TODO: this should be declared in InternalImpl
pub const TREE_HEIGHT: u8 = 16;
pub const TREE_HEIGHT: u8 = 10;

// Branch of a merkle tree of withdrawal requests. Uses algo described here:
// https://github.com/ethereum/research/blob/a4a600f2869feed5bfaab24b13ca1692069ef312/beacon_chain_impl/progressive_merkle_tree.py
Expand All @@ -47,10 +46,11 @@ mod BridgePOC {
}

#[generate_trait]
impl InternalImpl of InternalTrait {
pub impl InternalImpl of InternalTrait {
// TODO: how to enforce ZERO_HASHES.len() == TREE_HEIGHT?
// calculated with print_zero_hashes below
#[cairofmt::skip]
const ZERO_HASHES: [[u32; 8]; 16] = [
const ZERO_HASHES: [[u32; 8]; 10] = [
[0, 0, 0, 0, 0, 0, 0, 0],
[3807779903, 1909579517, 1068079583, 2741588853, 1550386825, 2040095412, 2347489334, 2538507513],
[2099567403, 4198582091, 4214196093, 1754246239, 2858291362, 2156722654, 812871865, 861070664],
Expand All @@ -61,52 +61,48 @@ mod BridgePOC {
[1723082150, 3777628280, 2788800972, 2132291431, 4168203796, 2521771669, 2723785127, 1542325057],
[1829197597, 3996005857, 931906618, 2383644882, 4277580546, 482972235, 2287817650, 3459845800],
[2257188826, 1732868934, 4244326882, 39139633, 3210730636, 2509762326, 1485744241, 392942686],
[2184653188, 4257042108, 677354460, 2465790105, 2048605806, 2745285032, 3104182931, 15402110],
[2860792224, 1687116504, 4231068254, 1935089599, 3765226240, 2947536533, 2517980564, 218435369],
[1926580722, 2072212521, 1018304954, 168205711, 57131430, 3740386295, 3329007170, 530668389],
[2270689968, 3288476717, 2865565625, 3616230225, 4127251747, 557907537, 780565330, 718131277],
[738994716, 1806310578, 2743103358, 3990199691, 371481172, 913060570, 163698502, 1078340806],
[770758798, 2266110520, 184798668, 311383229, 734089413, 4172582247, 2839721722, 4005778739]
];

fn get_element(self: @ContractState, i: u64) -> Digest {
match self.withdrawals.elements.get(i) {
Option::Some(element) => element.read(),
Option::None => { panic!("should not happen!"); Zero::zero() },
}
}

fn append(ref self: ContractState, withdrawal: Digest) {
//TODO: make sure it is not full
let mut value = withdrawal;
let original_size = self.withdrawals.size.read();

// TODO: close the queue when it's full?
if original_size == Bounded::<u16>::MAX {
panic!("BridgePoc::withdrawals queue is full");
}

let mut size = original_size;
let mut i = 0;

while size % 2 == 1 {
let element = self.withdrawals.elements.at(i).read();
value = double_sha256_digests(@element, @value);
value = double_sha256_digests(@self.get_element(i), @value);
size = size / 2;
i += 1;
};

self.withdrawals.elements.at(i).write(value);
if i >= self.withdrawals.elements.len() {
self.withdrawals.elements.append().write(value);
} else {
self.withdrawals.elements.at(i).write(value);
}
self.withdrawals.size.write(original_size + 1);
}

fn root(self: @ContractState) -> Digest {
let zero_hashes = Self::ZERO_HASHES.span();

let mut root = DigestTrait::new(*zero_hashes.at(0));

let mut height = 0;
let mut size = self.withdrawals.size.read();

while height < super::BridgePOC::TREE_HEIGHT.into() {
while height < TREE_HEIGHT.into() {
if size % 2 == 1 {
let element = self.withdrawals.elements.at(height.into()).read();
root = double_sha256_digests(@element, @root);
root = double_sha256_digests(@self.get_element(height.into()), @root);
} else {
let zero_hash = DigestTrait::new(*zero_hashes.at(height));
root = double_sha256_digests(@root, @zero_hash);
root = double_sha256_digests(@root, @DigestTrait::new(*zero_hashes.at(height)));
}
size = size / 2;
height += 1;
Expand All @@ -118,19 +114,97 @@ mod BridgePOC {
}

#[cfg(test)]
mod tests {
use crate::hash::Digest;
mod merkle_tree_tests {
use crate::hash::{Digest, DigestTrait};
use crate::double_sha256::double_sha256_digests;
use super::BridgePOC;
use super::{BridgePOC};
use super::BridgePOC::InternalTrait;
use crate::bit_shifts::pow2;

fn merkle_root(hashes: Span<Digest>) -> Digest {
let zero_hash = DigestTrait::new([0; 8]);
let mut hashes: Array<Digest> = hashes.into();

let expected_size = pow2(BridgePOC::TREE_HEIGHT.into());
for _ in 0..(expected_size - hashes.len().into()) {
hashes.append(zero_hash);
};

let mut hashes = hashes.span();

for _ in 0..BridgePOC::TREE_HEIGHT {
let mut next_hashes: Array<Digest> = array![];
while let Option::Some(v) = hashes.multi_pop_front::<2>() {
let [a, b] = (*v).unbox();
next_hashes.append(double_sha256_digests(@a, @b));
};
hashes = next_hashes.span();
};

*hashes.at(0)
}

// use this to fill the ZERO_HASHES array
#[test]
#[ignore]
fn print_zero_hashes() {
let mut previous: Digest = 0_u256.into();
for i in 0..BridgePOC::TREE_HEIGHT {
println!("zero_hashes[{}] = {:?}", i, previous);
for _ in 0..BridgePOC::TREE_HEIGHT {
previous = double_sha256_digests(@previous, @previous);
}
}

fn data(size: u256) -> Array<Digest> {
let x = 0x8000000000000000000000000000000000000000000000000000000000000000;
let mut r = array![];
for i in 1..size + 1 {
r.append((x + i).into());
};
r
}

fn test_data(size: u256) {

let data = data(size).span();

let mut bridge = BridgePOC::contract_state_for_testing();

for d in data {
bridge.append(*d);
};

assert_eq!(bridge.root(), merkle_root(data), "merkle root mismatch");
}

#[test]
fn test_merkle_root1() {
test_data(1);
}

#[test]
fn test_merkle_root2() {
test_data(2);
}

#[test]
fn test_merkle_root3() {
test_data(3);
}

#[test]
fn test_merkle_root256() {
test_data(256);
}

fn test_merkle_root1023() {
test_data(1023);
}
}

#[cfg(test)]
mod bridge_tests {
fn test_deposit() {// let bridge_class = declare("BridgePOC").unwrap().contract_class();
// let bridge_address = bridge_class.deploy(@array![]).unwrap();
// let bridge = IBridgePOCDispather(contract_address);
}
}
1 change: 0 additions & 1 deletion l2/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ mod bit_shifts;
mod bridge_poc;
mod double_sha256;
mod hash;
mod merkle_tree;
mod word_array;

#[cfg(target: 'test')]
Expand Down
Loading

0 comments on commit 2b33000

Please sign in to comment.