Skip to content

Commit

Permalink
feat(katana): always include Controller class by default (#2107)
Browse files Browse the repository at this point in the history
* define and declare controller account by default

* update genesis test

* separate slot and controller feature

* update comment

* fix typo
  • Loading branch information
kariy authored Jun 26, 2024
1 parent badeeba commit 7da96db
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 91 deletions.
2 changes: 1 addition & 1 deletion bin/katana/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ blockifier = [ "katana-executor/blockifier" ]

jemalloc = [ "dojo-metrics/jemalloc" ]
messaging = [ "katana-core/messaging" ]
slot = [ "dep:katana-slot-controller" ]
slot = [ "dep:katana-slot-controller", "katana-primitives/slot" ]
starknet-messaging = [ "katana-core/starknet-messaging", "messaging" ]
50 changes: 6 additions & 44 deletions crates/katana/controller/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::sync::Arc;

use account_sdk::abigen::controller::{Signer, SignerType};
use account_sdk::signers::webauthn::{DeviceSigner, WebauthnAccountSigner};
Expand All @@ -8,11 +7,10 @@ use account_sdk::wasm_webauthn::CredentialID;
use alloy_primitives::U256;
use anyhow::Result;
use coset::CoseKey;
use katana_primitives::class::{ClassHash, CompiledClass, SierraCompiledClass};
use katana_primitives::contract::{ContractAddress, StorageKey, StorageValue};
use katana_primitives::genesis::allocation::{GenesisAllocation, GenesisContractAlloc};
use katana_primitives::genesis::{Genesis, GenesisClass};
use katana_primitives::utils::class::{parse_compiled_class_v1, parse_sierra_class};
use katana_primitives::genesis::constant::CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH;
use katana_primitives::genesis::Genesis;
use katana_primitives::FieldElement;
use slot::credential::Credentials;
use starknet::core::utils::get_storage_var_address;
Expand All @@ -22,9 +20,6 @@ mod webauthn;

const LOG_TARGET: &str = "katana::controller";

const CONTROLLER_SIERRA_ARTIFACT: &str =
include_str!("../../contracts/compiled/controller_CartridgeAccount.contract_class.json");

const WEBAUTHN_RP_ID: &str = "cartridge.gg";
const WEBAUTHN_ORIGIN: &str = "https://x.cartridge.gg";

Expand All @@ -34,33 +29,6 @@ pub fn add_controller_account(genesis: &mut Genesis) -> Result<()> {
add_controller_account_inner(genesis, credentials.account)
}

fn add_controller_class(genesis: &mut Genesis) -> Result<ClassHash> {
let sierra = parse_sierra_class(CONTROLLER_SIERRA_ARTIFACT)?;
let casm = read_compiled_class_artifact(CONTROLLER_SIERRA_ARTIFACT)?;

let class_hash = sierra.class_hash()?;
let flattened_sierra = sierra.flatten()?;
let casm_hash = FieldElement::from_bytes_be(&casm.casm.compiled_class_hash().to_be_bytes())?;

trace!(
target: LOG_TARGET,
class_hash = format!("{class_hash:#x}"),
casm_hash = format!("{casm_hash:#x}"),
"Adding Cartridge Controller account class to genesis."
);

genesis.classes.insert(
class_hash,
GenesisClass {
sierra: Some(Arc::new(flattened_sierra)),
compiled_class_hash: casm_hash,
casm: Arc::new(CompiledClass::Class(casm)),
},
);

Ok(class_hash)
}

fn add_controller_account_inner(genesis: &mut Genesis, user: slot::account::Account) -> Result<()> {
let cred = user.credentials.webauthn.first().unwrap();

Expand All @@ -71,16 +39,14 @@ fn add_controller_account_inner(genesis: &mut Genesis, user: slot::account::Acco
"Adding Cartridge Controller account to genesis."
);

let class_hash = add_controller_class(genesis)?;

let credential_id = webauthn::credential::from_base64(&cred.id)?;
let public_key = webauthn::cose_key::from_base64(&cred.public_key)?;

let (address, contract) = {
let account = GenesisContractAlloc {
nonce: None,
class_hash: Some(class_hash),
balance: Some(U256::from(0xfffffffffffffffu128)),
class_hash: Some(CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH),
storage: Some(get_contract_storage(credential_id, public_key, SignerType::Webauthn)?),
};

Expand Down Expand Up @@ -108,6 +74,8 @@ pub mod json {

use super::*;

const CONTROLLER_SIERRA_ARTIFACT: &str =
include_str!("../../contracts/compiled/controller_CartridgeAccount.contract_class.json");
const CONTROLLER_CLASS_NAME: &str = "controller";

// TODO(kariy): should accept the whole account struct instead of individual fields
Expand Down Expand Up @@ -188,11 +156,6 @@ fn get_contract_storage(
Ok(HashMap::from([(storage, guid)]))
}

fn read_compiled_class_artifact(artifact: &str) -> Result<SierraCompiledClass> {
let value = serde_json::from_str(artifact)?;
parse_compiled_class_v1(value)
}

#[cfg(test)]
mod tests {
use slot::account::WebAuthnCredential;
Expand Down Expand Up @@ -230,15 +193,14 @@ mod tests {
},
};

let controller_class_hash = add_controller_class(&mut Genesis::default()).unwrap();
add_controller_account_inner(&mut genesis, account.clone()).unwrap();

let address = ContractAddress::from(account.contract_address);
let allocation = genesis.allocations.get(&address).unwrap();

assert!(genesis.allocations.contains_key(&address));
assert_eq!(allocation.class_hash(), Some(controller_class_hash));
assert_eq!(allocation.balance(), Some(U256::from(0xfffffffffffffffu128)));
assert_eq!(allocation.class_hash(), Some(CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH));
}

#[test]
Expand Down
3 changes: 3 additions & 0 deletions crates/katana/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ similar-asserts.workspace = true

[features]
default = [ "serde" ]

controller = [ ]
rpc = [ ]
serde = [ "alloy-primitives/serde" ]
slot = [ "controller" ]
9 changes: 9 additions & 0 deletions crates/katana/primitives/src/genesis/constant.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use lazy_static::lazy_static;
use starknet::core::utils::get_storage_var_address;
use starknet::macros::felt;

use crate::class::{ClassHash, CompiledClass, CompiledClassHash, SierraClass};
use crate::contract::{ContractAddress, StorageKey};
Expand Down Expand Up @@ -121,6 +122,8 @@ pub const DEFAULT_OZ_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH: CompiledClassHash =
190499602541245794,
]);

pub const CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH: ClassHash = felt!("0xCC");

// Pre-compiled contract classes
lazy_static! {

Expand All @@ -134,7 +137,13 @@ lazy_static! {
// Default account contract
pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT: SierraClass = parse_sierra_class(include_str!("../../../contracts/compiled/oz_account_080.json")).unwrap();
pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../../contracts/compiled/oz_account_080.json"));
}

#[cfg(feature = "controller")]
lazy_static! {
// Cartridge Controller account
pub static ref CONTROLLER_ACCOUNT_CONTRACT: SierraClass = parse_sierra_class(include_str!("../../../contracts/compiled/controller_CartridgeAccount.contract_class.json")).unwrap();
pub static ref CONTROLLER_ACCOUNT_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../../contracts/compiled/oz_account_080.json"));
}

/// A helper function to get the base storage address for the fee token balance of a given account.
Expand Down
67 changes: 38 additions & 29 deletions crates/katana/primitives/src/genesis/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ use starknet::core::types::FromByteArrayError;
use super::allocation::{
DevGenesisAccount, GenesisAccount, GenesisAccountAlloc, GenesisContractAlloc,
};
#[cfg(feature = "slot")]
use super::constant::{
CONTROLLER_ACCOUNT_CONTRACT, CONTROLLER_ACCOUNT_CONTRACT_CASM,
CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
};
use super::constant::{
DEFAULT_FEE_TOKEN_ADDRESS, DEFAULT_LEGACY_ERC20_CONTRACT_CASM,
DEFAULT_LEGACY_ERC20_CONTRACT_CLASS_HASH, DEFAULT_LEGACY_ERC20_CONTRACT_COMPILED_CLASS_HASH,
Expand Down Expand Up @@ -320,6 +325,19 @@ impl TryFrom<GenesisJson> for Genesis {
let mut class_names: HashMap<String, FieldElement> = HashMap::new();
let mut classes: HashMap<ClassHash, GenesisClass> = HashMap::new();

#[cfg(feature = "slot")]
// Merely a band aid fix for now.
// Adding this by default so that we can support mounting the genesis file from k8s
// ConfigMap when we embed the Controller class, and its capacity is only limited to 1MiB.
classes.insert(
CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
GenesisClass {
casm: Arc::new(CONTROLLER_ACCOUNT_CONTRACT_CASM.clone()),
compiled_class_hash: CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
sierra: Some(Arc::new(CONTROLLER_ACCOUNT_CONTRACT.clone().flatten()?)),
},
);

for entry in value.classes {
let GenesisClassJson { class, class_hash, name } = entry;

Expand Down Expand Up @@ -513,9 +531,7 @@ impl TryFrom<GenesisJson> for Genesis {
// insert default account class to the classes map
e.insert(GenesisClass {
casm: Arc::new(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone()),
sierra: Some(Arc::new(
DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(),
)),
sierra: Some(Arc::new(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten()?)),
compiled_class_hash: DEFAULT_OZ_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH,
});
}
Expand Down Expand Up @@ -662,34 +678,9 @@ fn class_artifact_at_path(

#[cfg(test)]
mod tests {
use std::collections::{BTreeMap, HashMap};
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::str::FromStr;

use alloy_primitives::U256;
use starknet::macros::felt;

use super::{from_base64, GenesisAccountJson, GenesisClassJson, GenesisJson};
use crate::block::GasPrices;
use crate::genesis::allocation::{
DevGenesisAccount, GenesisAccount, GenesisAccountAlloc, GenesisContractAlloc,
};
use crate::genesis::constant::{
DEFAULT_FEE_TOKEN_ADDRESS, DEFAULT_LEGACY_ERC20_CONTRACT_CASM,
DEFAULT_LEGACY_ERC20_CONTRACT_CLASS_HASH,
DEFAULT_LEGACY_ERC20_CONTRACT_COMPILED_CLASS_HASH, DEFAULT_LEGACY_UDC_CASM,
DEFAULT_LEGACY_UDC_CLASS_HASH, DEFAULT_LEGACY_UDC_COMPILED_CLASS_HASH,
DEFAULT_OZ_ACCOUNT_CONTRACT, DEFAULT_OZ_ACCOUNT_CONTRACT_CASM,
DEFAULT_OZ_ACCOUNT_CONTRACT_CLASS_HASH, DEFAULT_OZ_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH,
DEFAULT_UDC_ADDRESS,
};
use crate::genesis::json::{to_base64, ClassNameOrHash};
use crate::genesis::{
ContractAddress, FeeTokenConfig, Genesis, GenesisAllocation, GenesisClass,
UniversalDeployerConfig,
};
use super::*;

#[test]
fn deserialize_from_json() {
Expand Down Expand Up @@ -925,6 +916,15 @@ mod tests {
sierra: Some(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap().into()),
},
),
#[cfg(feature = "slot")]
(
CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
GenesisClass {
casm: Arc::new(CONTROLLER_ACCOUNT_CONTRACT_CASM.clone()),
compiled_class_hash: CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
sierra: Some(Arc::new(CONTROLLER_ACCOUNT_CONTRACT.clone().flatten().unwrap())),
},
),
]);

let expected_fee_token = FeeTokenConfig {
Expand Down Expand Up @@ -1145,6 +1145,15 @@ mod tests {
sierra: Some(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap().into()),
},
),
#[cfg(feature = "slot")]
(
CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
GenesisClass {
casm: Arc::new(CONTROLLER_ACCOUNT_CONTRACT_CASM.clone()),
compiled_class_hash: CONTROLLER_ACCOUNT_CONTRACT_CLASS_HASH,
sierra: Some(Arc::new(CONTROLLER_ACCOUNT_CONTRACT.clone().flatten().unwrap())),
},
),
]);

let fee_token = FeeTokenConfig {
Expand Down
Loading

0 comments on commit 7da96db

Please sign in to comment.