Skip to content

Commit

Permalink
World deployments with determinsitic addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrencev committed Oct 3, 2023
1 parent 8360af8 commit 4bcbb25
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 8 deletions.
3 changes: 3 additions & 0 deletions crates/dojo-core/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ mod packing_test;
mod world;
#[cfg(test)]
mod world_test;
mod upgradable;
#[cfg(test)]
mod upgradable_test;

#[cfg(test)]
mod test_utils;
4 changes: 2 additions & 2 deletions crates/dojo-core/src/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ use dojo::world::{world, IWorldDispatcher, IWorldDispatcherTrait};
/// # Returns
/// * address of contract deployed
fn deploy_contract(class_hash: felt252, calldata: Span<felt252>) -> ContractAddress {
let (system_contract, _) = starknet::deploy_syscall(
let (contract, _) = starknet::deploy_syscall(
class_hash.try_into().unwrap(), 0, calldata, false
)
.unwrap();
system_contract
contract
}

/// Deploy classhash and passes in world address to constructor
Expand Down
48 changes: 48 additions & 0 deletions crates/dojo-core/src/upgradable.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use starknet::{ClassHash, SyscallResult, SyscallResultTrait};
use zeroable::Zeroable;
use result::ResultTrait;
use serde::Serde;
use clone::Clone;
use traits::PartialEq;

#[starknet::interface]
trait IUpgradeable<T> {
fn upgrade(ref self: T, new_class_hash: ClassHash);
}

#[derive(Clone, Drop, Serde, PartialEq, starknet::Event)]
struct Upgraded {
class_hash: ClassHash,
}

trait UpgradeableTrait {
fn upgrade(new_class_hash: ClassHash);
}

impl UpgradeableTraitImpl of UpgradeableTrait {
fn upgrade(new_class_hash: ClassHash) {
assert(new_class_hash.is_non_zero(), 'class_hash cannot be zero');
starknet::replace_class_syscall(new_class_hash).unwrap_syscall();
}
}

#[starknet::contract]
mod placeholder {
use starknet::{ClassHash};
use dojo::upgradable::{IUpgradeable, UpgradeableTrait};

#[storage]
struct Storage {}

#[external(v0)]
impl Upgradeable of IUpgradeable<ContractState> {
/// Upgrade contract implementation to new_class_hash
///
/// # Arguments
///
/// * `new_class_hash` - The new implementation class hahs.
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
UpgradeableTrait::upgrade(new_class_hash);
}
}
}
42 changes: 42 additions & 0 deletions crates/dojo-core/src/upgradable_test.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use option::OptionTrait;
use starknet::ClassHash;
use traits::TryInto;

use dojo::upgradable::{placeholder, IUpgradeableDispatcher, IUpgradeableDispatcherTrait};
use dojo::test_utils::deploy_contract;

#[starknet::contract]
mod contract_upgrade {
#[storage]
struct Storage {}

#[starknet::interface]
trait IQuantumLeap<TState> {
fn plz_more_tps(self: @TState) -> felt252;
}

#[constructor]
fn constructor(ref self: ContractState) {}

#[external(v0)]
impl QuantumLeap of IQuantumLeap<ContractState> {
fn plz_more_tps(self: @ContractState) -> felt252 {
'daddy'
}
}
}

use contract_upgrade::{IQuantumLeapDispatcher, IQuantumLeapDispatcherTrait};

#[test]
#[available_gas(6000000)]
fn test_upgrade() {
let placeholder_address = deploy_contract(placeholder::TEST_CLASS_HASH, array![].span());
let upgradable_dispatcher = IUpgradeableDispatcher { contract_address: placeholder_address };

let new_class_hash: ClassHash = contract_upgrade::TEST_CLASS_HASH.try_into().unwrap();
upgradable_dispatcher.upgrade(new_class_hash);

let quantum_dispatcher = IQuantumLeapDispatcher { contract_address: placeholder_address };
assert(quantum_dispatcher.plz_more_tps() == 'daddy', 'quantum leap failed');
}
21 changes: 15 additions & 6 deletions crates/dojo-core/src/world.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use option::OptionTrait;
trait IWorld<T> {
fn model(self: @T, name: felt252) -> ClassHash;
fn register_model(ref self: T, class_hash: ClassHash);
fn deploy_contract(self: @T, name: felt252, class_hash: ClassHash, calldata: Span<felt252>) -> SyscallResult<(ContractAddress, Span<felt252>)>;
fn uuid(ref self: T) -> usize;
fn emit(self: @T, keys: Array<felt252>, values: Span<felt252>);
fn entity(
Expand All @@ -29,6 +30,7 @@ trait IWorld<T> {
) -> (Span<felt252>, Span<Span<felt252>>);
fn set_executor(ref self: T, contract_address: ContractAddress);
fn executor(self: @T) -> ContractAddress;
fn deployment_placeholder(self: @T) -> ClassHash;
fn delete_entity(ref self: T, model: felt252, keys: Span<felt252>);
fn is_owner(self: @T, address: ContractAddress, target: felt252) -> bool;
fn grant_owner(ref self: T, address: ContractAddress, target: felt252);
Expand All @@ -49,12 +51,13 @@ mod world {
use starknet::{
get_caller_address, get_contract_address, get_tx_info,
contract_address::ContractAddressIntoFelt252, ClassHash, Zeroable, ContractAddress,
syscalls::emit_event_syscall, SyscallResultTrait, SyscallResultTraitImpl
syscalls::{deploy_syscall, emit_event_syscall}, SyscallResult, SyscallResultTrait, SyscallResultTraitImpl
};

use dojo::database;
use dojo::database::index::WhereCondition;
use dojo::executor::{IExecutorDispatcher, IExecutorDispatcherTrait};
use dojo::upgradable::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait};
use dojo::world::{IWorldDispatcher, IWorld};


Expand Down Expand Up @@ -101,18 +104,18 @@ mod world {
#[storage]
struct Storage {
executor_dispatcher: IExecutorDispatcher,
models: LegacyMap::<felt252, ClassHash>,
deployment_placeholder: ClassHash,
nonce: usize,
models: LegacyMap::<felt252, ClassHash>,
owners: LegacyMap::<(felt252, ContractAddress), bool>,
writers: LegacyMap::<(felt252, ContractAddress), bool>,
// Tracks the calling systems name for auth purposes.
call_stack_len: felt252,
call_stack: LegacyMap::<felt252, felt252>,
}

#[constructor]
fn constructor(ref self: ContractState, executor: ContractAddress) {
fn constructor(ref self: ContractState, executor: ContractAddress, deployment_placeholder: ClassHash) {
self.executor_dispatcher.write(IExecutorDispatcher { contract_address: executor });
self.deployment_placeholder.write(deployment_placeholder);

self
.owners
.write(
Expand Down Expand Up @@ -273,6 +276,12 @@ mod world {
self.models.read(name)
}

fn deploy_contract(self: @ContractState, name: felt252, class_hash: ClassHash) -> (ContractAddress, Span<felt252>) {
let (contract_address, _) = deploy_syscall(self.deployment_placeholder.read(), name, vec![].span(), false).unwrap_syscall();
let upgradable_dispatcher = IUpgradeableDispatcher { contract_address };
upgradable_dispatcher.upgrade(class_hash);
}

/// Issues an autoincremented id to the caller.
///
/// # Returns
Expand Down

0 comments on commit 4bcbb25

Please sign in to comment.