Skip to content

Commit

Permalink
feat: make address deterministic
Browse files Browse the repository at this point in the history
  • Loading branch information
Th0rgal committed Nov 4, 2024
1 parent a37b41a commit 8e25a38
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 11 deletions.
17 changes: 16 additions & 1 deletion src/interfaces.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{bitcoin::block::BlockHeader, utils::digest::DigestStore};
use starknet::get_block_timestamp;
use starknet::{ContractAddress, get_block_timestamp};
use utils::hash::Digest;


Expand Down Expand Up @@ -33,6 +33,21 @@ pub impl BlockStatusImpl of BlockStatusTrait {

#[starknet::interface]
pub trait IUtuRelay<TContractState> {
/// Initializes the contract with an owner.
///
/// This function is used instead of a constructor to ensure the contract address is fully
/// deterministic. When using a constructor, the constructor arguments become part of the
/// contract's address calculation. By moving initialization to a separate function that can
/// only be called once, we keep the address calculation dependent only on the contract's code
/// and class hash.
///
/// # Arguments
/// * `owner` - The address that will be set as the contract owner
///
/// # Reverts
/// * If the contract has already been initialized
fn initialize(ref self: TContractState, owner: ContractAddress);

/// Registers new blocks with the relay.
///
/// This function allows anyone to register blocks (they don't have to be contiguous or in
Expand Down
14 changes: 8 additions & 6 deletions src/tests/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ pub impl DigestIntoSpan of Into<Digest, Span<felt252>> {

pub fn deploy_utu() -> IUtuRelayDispatcher {
let contract = declare("UtuRelay").unwrap().contract_class();
let _owner: ContractAddress = contract_address_const::<'owner'>();

let mut constructor_calldata = array![];
let (contract_address, _constructor_returned_data) = contract
.deploy(@constructor_calldata)
.unwrap();
// Deploy with empty constructor
let (contract_address, _) = contract.deploy(@ArrayTrait::new()).unwrap();
let dispatcher = IUtuRelayDispatcher { contract_address };

IUtuRelayDispatcher { contract_address }
// Initialize the contract with owner
let owner: ContractAddress = contract_address_const::<'owner'>();
dispatcher.initialize(owner);

dispatcher
}
20 changes: 16 additions & 4 deletions src/utu_relay.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub mod UtuRelay {
blocks: Map<Digest, BlockStatus>,
// This is a mapping of each chain height to a block from the strongest chain registered
chain: Map<u64, Digest>,
// This allows to keep a clean constructor and thus make address deterministic
initialized: bool,
// Components
#[substorage(v0)]
ownable: OwnableComponent::Storage,
Expand All @@ -56,9 +58,7 @@ pub mod UtuRelay {
}

#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}
fn constructor(ref self: ContractState) {}

#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
Expand All @@ -73,6 +73,19 @@ pub mod UtuRelay {

#[abi(embed_v0)]
impl UtuRelayImpl of IUtuRelay<ContractState> {
fn initialize(ref self: ContractState, owner: ContractAddress) {
// Check if already initialized
if self.initialized.read() {
panic!("Contract is already initialized");
}

// Set initialized flag
self.initialized.write(true);

// Initialize ownership
self.ownable.initializer(owner);
}

fn register_blocks(ref self: ContractState, mut blocks: Span<BlockHeader>) {
loop {
match blocks.pop_front() {
Expand All @@ -94,7 +107,6 @@ pub mod UtuRelay {
};
}


fn update_canonical_chain(
ref self: ContractState,
begin_height: u64,
Expand Down

0 comments on commit 8e25a38

Please sign in to comment.