Skip to content

Commit

Permalink
feat(katana): include settlement info in ChainSpec (#2870)
Browse files Browse the repository at this point in the history
Make the flow more coherent by including information of the settlement layer stuff in the ChainSpec. For example, the messaging component has its own config struct to specify the core contract and RPC url of the underlying layer. These informations are also required by other component (mainly gas oracle) so we want to centralize where we put these information. Having it in the ChainSpec struct make sense because these information define the rollup chain itself.
  • Loading branch information
kariy committed Jan 19, 2025
1 parent 2dd3ead commit ff6b0b2
Show file tree
Hide file tree
Showing 30 changed files with 334 additions and 198 deletions.
25 changes: 23 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"crates/dojo/utils",
"crates/dojo/world",
"crates/dojo/world/abigen",
"crates/katana/chain-spec",
"crates/katana/cli",
"crates/katana/controller",
"crates/katana/core",
Expand Down Expand Up @@ -93,6 +94,7 @@ topological-sort = "0.2"

# katana
katana-cairo = { path = "crates/katana/cairo" }
katana-chain-spec = { path = "crates/katana/chain-spec" }
katana-cli = { path = "crates/katana/cli" }
katana-codecs = { path = "crates/katana/storage/codecs" }
katana-codecs-derive = { path = "crates/katana/storage/codecs/derive" }
Expand Down
4 changes: 2 additions & 2 deletions bin/katana/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repository.workspace = true
version.workspace = true

[dependencies]
katana-chain-spec.workspace = true
katana-cli.workspace = true
katana-db.workspace = true
katana-node.workspace = true
Expand All @@ -23,15 +24,14 @@ comfy-table = "7.1.1"
dirs = "5.0.1"
dojo-utils.workspace = true
inquire = "0.7.5"
lazy_static.workspace = true
rand.workspace = true
serde.workspace = true
shellexpand = "3.1.0"
spinoff.workspace = true
starknet.workspace = true
strum_macros.workspace = true
thiserror.workspace = true
tokio.workspace = true
toml.workspace = true
tracing.workspace = true

[dev-dependencies]
Expand Down
113 changes: 47 additions & 66 deletions bin/katana/src/cli/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ use std::sync::Arc;

use anyhow::{Context, Result};
use clap::Args;
use inquire::{Confirm, CustomType, Select, Text};
use inquire::{Confirm, CustomType, Select};
use katana_chain_spec::{DEV_UNALLOCATED, SettlementLayer};
use katana_primitives::chain::ChainId;
use katana_primitives::genesis::Genesis;
use katana_primitives::genesis::allocation::DevAllocationsGenerator;
use katana_primitives::{ContractAddress, Felt};
use serde::{Deserialize, Serialize};
use lazy_static::lazy_static;
use starknet::accounts::{ExecutionEncoding, SingleOwnerAccount};
use starknet::core::types::{BlockId, BlockTag};
use starknet::core::utils::{cairo_short_string_to_felt, parse_cairo_short_string};
Expand All @@ -36,55 +40,15 @@ struct InitInput {
// the rpc url for the settlement layer.
rpc_url: Url,

fee_token: ContractAddress,

settlement_contract: ContractAddress,

// path at which the config file will be written at.
output_path: PathBuf,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct SettlementLayer {
// the account address that was used to initialized the l1 deployments
pub account: ContractAddress,

// The id of the settlement chain.
pub id: String,

pub rpc_url: Url,

// - The token that will be used to pay for tx fee in the appchain.
// - For now, this must be the native token that is used to pay for tx fee in the settlement
// chain.
pub fee_token: ContractAddress,

// - The bridge contract for bridging the fee token from L1 to the appchain
// - This will be part of the initialization process.
pub bridge_contract: ContractAddress,

// - The core appchain contract used to settlement
// - This is deployed on the L1
pub settlement_contract: ContractAddress,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct InitConfiguration {
// the initialized chain id
pub id: String,

// the fee token contract
//
// this corresponds to the l1 token contract
pub fee_token: ContractAddress,

pub settlement: SettlementLayer,
}

#[derive(Debug, Args)]
pub struct InitArgs {
/// The path to where the config file will be written at.
#[arg(value_name = "PATH")]
pub output_path: Option<PathBuf>,
}
Expand All @@ -97,27 +61,34 @@ impl InitArgs {
let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
let input = self.prompt(&rt)?;

let output = InitConfiguration {
id: input.id,
fee_token: ContractAddress::default(),
settlement: SettlementLayer {
account: input.account,
id: input.settlement_id,
rpc_url: input.rpc_url,
fee_token: input.fee_token,
bridge_contract: ContractAddress::default(),
settlement_contract: input.settlement_contract,
},
let settlement = SettlementLayer::Starknet {
account: input.account,
rpc_url: input.rpc_url,
id: ChainId::parse(&input.settlement_id)?,
core_contract: input.settlement_contract,
};

let content = toml::to_string_pretty(&output)?;
fs::write(input.output_path, content)?;
let mut chain_spec = DEV_UNALLOCATED.clone();
chain_spec.genesis = GENESIS.clone();
chain_spec.id = ChainId::parse(&input.id)?;
chain_spec.settlement = Some(settlement);

Ok(())
chain_spec.store(input.output_path)
}

fn prompt(&self, rt: &Runtime) -> Result<InitInput> {
let chain_id = Text::new("Id").prompt()?;
let chain_id = CustomType::<String>::new("Id")
.with_help_message("This will be the id of your rollup chain.")
// checks that the input is a valid ascii string.
.with_parser(&|input| {
if input.is_ascii() {
Ok(input.to_string())
} else {
Err(())
}
})
.with_error_message("Must be valid ASCII characters")
.prompt()?;

#[derive(Debug, strum_macros::Display)]
enum SettlementChainOpt {
Expand Down Expand Up @@ -180,11 +151,12 @@ impl InitArgs {
ExecutionEncoding::New,
);

// The L1 fee token. Must be an existing token.
let fee_token = CustomType::<ContractAddress>::new("Fee token")
.with_parser(contract_exist_parser)
.with_error_message("Please enter a valid fee token (the token must exist on L1)")
.prompt()?;
// TODO: uncomment once we actually using the fee token.
// // The L1 fee token. Must be an existing token.
// let fee_token = CustomType::<ContractAddress>::new("Fee token")
// .with_parser(contract_exist_parser)
// .with_error_message("Please enter a valid fee token (the token must exist on L1)")
// .prompt()?;

// The core settlement contract on L1c.
// Prompt the user whether to deploy the settlement contract or not.
Expand Down Expand Up @@ -218,16 +190,15 @@ impl InitArgs {
settlement_contract,
settlement_id: parse_cairo_short_string(&l1_chain_id)?,
id: chain_id,
fee_token,
rpc_url: settlement_url,
output_path,
})
}
}

// > CONFIG_DIR/$chain_id/config.toml
// > CONFIG_DIR/$chain_id/config.json
fn config_path(id: &str) -> Result<PathBuf> {
Ok(config_dir(id)?.join("config").with_extension("toml"))
Ok(config_dir(id)?.join("config").with_extension("json"))
}

fn config_dir(id: &str) -> Result<PathBuf> {
Expand Down Expand Up @@ -258,3 +229,13 @@ impl Display for Path {
write!(f, "{}", self.0.display())
}
}

lazy_static! {
static ref GENESIS: Genesis = {
// master account
let accounts = DevAllocationsGenerator::new(1).generate();
let mut genesis = Genesis::default();
genesis.extend_allocations(accounts.into_iter().map(|(k, v)| (k, v.into())));
genesis
};
}
10 changes: 6 additions & 4 deletions crates/dojo/test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ repository.workspace = true
version.workspace = true

[dependencies]
anyhow.workspace = true
assert_fs.workspace = true
async-trait.workspace = true
camino.workspace = true
katana-chain-spec.workspace = true
katana-core = { workspace = true }
katana-executor = { workspace = true, features = [ "blockifier" ] }
katana-node.workspace = true
katana-primitives = { workspace = true }
katana-rpc.workspace = true

anyhow.workspace = true
assert_fs.workspace = true
async-trait.workspace = true
camino.workspace = true
scarb.workspace = true
scarb-ui.workspace = true
serde.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo/test-utils/src/sequencer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use katana_chain_spec::ChainSpec;
use katana_core::backend::Backend;
use katana_core::constants::DEFAULT_SEQUENCER_ADDRESS;
use katana_executor::implementation::blockifier::BlockifierFactory;
Expand All @@ -8,7 +9,6 @@ use katana_node::config::rpc::{RpcConfig, DEFAULT_RPC_ADDR, DEFAULT_RPC_MAX_CONN
pub use katana_node::config::*;
use katana_node::LaunchedNode;
use katana_primitives::chain::ChainId;
use katana_primitives::chain_spec::ChainSpec;
use katana_rpc::Error;
use rpc::RpcModulesList;
use starknet::accounts::{ExecutionEncoding, SingleOwnerAccount};
Expand Down
20 changes: 20 additions & 0 deletions crates/katana/chain-spec/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
edition.workspace = true
license.workspace = true
name = "katana-chain-spec"
repository.workspace = true
version.workspace = true

[dependencies]
katana-primitives.workspace = true

alloy-primitives.workspace = true
anyhow.workspace = true
lazy_static.workspace = true
serde.workspace = true
serde_json.workspace = true
starknet.workspace = true
url.workspace = true

[features]
controller = [ "katana-primitives/controller" ]
Loading

0 comments on commit ff6b0b2

Please sign in to comment.