Skip to content

Commit

Permalink
fix(katana-contracts): update piltover (#2980)
Browse files Browse the repository at this point in the history
* update piltover on PR cartridge-gg/piltover#5

* update piltover submodule

* update piltover to latest version

* update to latest piltover changes

* ensure katana rpc server can return big responses

* update SNOS program hash

* wip

* update piltover rev

* bump piltover with block-0 correctly handled

* point piltover to main

* feat(rpc): add `max_request_body_size` and `max_response_body_size`

* doc: update comment

* update

* add comments for the two programs hashes

* comments

* fmt

* add bootloader program hash

* add bootloader support for correct piltover configuration

* change piltover rev to main

---------

Co-authored-by: Ammar Arif <[email protected]>
  • Loading branch information
glihm and kariy authored Feb 10, 2025
1 parent d9227db commit 6ee7082
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 108 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
url = https://github.com/foundry-rs/forge-std
[submodule "crates/katana/contracts/piltover"]
path = crates/katana/contracts/piltover
url = https://github.com/cartridge-gg/piltover.git
url = https://github.com/keep-starknet-strange/piltover.git
12 changes: 11 additions & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ inherits = "release"

[workspace.dependencies]
cainome = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.12", features = [ "abigen-rs" ] }
cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.11" }
cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.12" }
dojo-utils = { path = "crates/dojo/utils" }

# metrics
Expand Down
1 change: 1 addition & 0 deletions bin/katana/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ comfy-table = "7.1.1"
dojo-utils.workspace = true
inquire = "0.7.5"
lazy_static.workspace = true
piltover = { git = "https://github.com/keep-starknet-strange/piltover.git", rev = "fb9d988" }
rand.workspace = true
shellexpand = "3.1.0"
spinoff.workspace = true
Expand Down
195 changes: 118 additions & 77 deletions bin/katana/src/cli/init/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use std::sync::Arc;

use anyhow::{anyhow, Result};
use cainome::cairo_serde;
use cainome::rs::abigen;
use dojo_utils::{TransactionWaiter, TransactionWaitingError};
use katana_primitives::block::BlockHash;
use katana_primitives::class::{
CompiledClassHash, ComputeClassHashError, ContractClass, ContractClassCompilationError,
ContractClassFromStrError,
};
use katana_primitives::{felt, ContractAddress, Felt};
use katana_rpc_types::class::RpcContractClass;
use piltover::{AppchainContract, AppchainContractReader, ProgramInfo};
use spinoff::{spinners, Color, Spinner};
use starknet::accounts::{Account, AccountError, ConnectedAccount, SingleOwnerAccount};
use starknet::contract::ContractFactory;
Expand All @@ -26,70 +27,47 @@ use tracing::trace;
type RpcProvider = Arc<JsonRpcClient<HttpTransport>>;
type InitializerAccount = SingleOwnerAccount<RpcProvider, LocalWallet>;

#[rustfmt::skip]
abigen!(
AppchainContract,
[
{
"type": "function",
"name": "set_program_info",
"inputs": [
{
"name": "program_hash",
"type": "core::Felt"
},
{
"name": "config_hash",
"type": "core::Felt"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "set_facts_registry",
"inputs": [
{
"name": "address",
"type": "core::starknet::contract_address::ContractAddress"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "get_facts_registry",
"inputs": [],
"outputs": [
{
"type": "core::starknet::contract_address::ContractAddress"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "get_program_info",
"inputs": [],
"outputs": [
{
"type": "(core::Felt, core::Felt)"
}
],
"state_mutability": "view"
}
]
);

const PROGRAM_HASH: Felt =
/// The StarknetOS program (SNOS) is the cairo program that executes the state
/// transition of a new Katana block from the previous block.
/// This program hash is required to be known by the settlement contract in order to
/// only accept a new state from a valid SNOS program.
///
/// This program can be found here: <https://github.com/starkware-libs/cairo-lang/blob/a86e92bfde9c171c0856d7b46580c66e004922f3/src/starkware/starknet/core/os/os.cairo>.
const SNOS_PROGRAM_HASH: Felt =
felt!("0x054d3603ed14fb897d0925c48f26330ea9950bd4ca95746dad4f7f09febffe0d");

/// To execute the SNOS program, a specific layout named "all_cairo" is required.
/// However, this layout can't be verified by the Cairo verifier that lives on Starknet.
///
/// This is why we're using an other program, the Layout Bridge program, which act as a verifier
/// written in Cairo which uses a layout supported by the Cairo verifier.
///
/// By verifying a SNOS proof using the Layout Bridge program, a new proof is generated which can be
/// verified by the Cairo verifier.
///
/// For the same reason as above, the Layout Bridge program is required to be known by the
/// settlement contract for security reasons.
///
/// This program can be found here: <https://github.com/starkware-libs/cairo-lang/blob/8276ac35830148a397e1143389f23253c8b80e93/src/starkware/cairo/cairo_verifier/layouts/all_cairo/cairo_verifier.cairo>.
const LAYOUT_BRIDGE_PROGRAM_HASH: Felt =
felt!("0x193641eb151b0f41674641089952e60bc3aded26e3cf42793655c562b8c3aa0");

/// The bootloader program hash is the program hash of the bootloader program.
///
/// This program is used to run the layout bridge program in SHARP. This program hash is also
/// required since the fact is computed based on the bootloader program hash and its output.
///
/// TODO: waiting for SHARP team to confirm if it's a custom bootloader or if we
/// can find it in cairo-lang.
const BOOTLOADER_PROGRAM_HASH: Felt =
felt!("0x5ab580b04e3532b6b18f81cfa654a05e29dd8e2352d88df1e765a84072db07");

/// The contract address that handles fact verification.
///
/// This address points to Herodotus' Atlantic Fact Registry contract on Starknet Sepolia as we rely
/// on their services to generates and verifies proofs.
///
/// See on [Voyager](https://sepolia.voyager.online/contract/0x04ce7851f00b6c3289674841fd7a1b96b6fd41ed1edc248faccd672c26371b8c).
const ATLANTIC_FACT_REGISTRY_SEPOLIA: Felt =
felt!("0x4ce7851f00b6c3289674841fd7a1b96b6fd41ed1edc248faccd672c26371b8c");

Expand Down Expand Up @@ -148,13 +126,29 @@ pub async fn deploy_settlement_contract(
let salt = Felt::from(rand::random::<u64>());
let factory = ContractFactory::new(class_hash, &account);

// appchain::constructor() https://github.com/cartridge-gg/piltover/blob/d373a844c3428383a48518adf468bf83249dec3a/src/appchain.cairo#L119-L125
const INITIAL_STATE_ROOT: Felt = Felt::ZERO;
/// When updating the piltover contract with the genesis block (ie block number 0), in the
/// attached StarknetOsOutput, the [previous block number] is expected to be
/// `0x800000000000011000000000000000000000000000000000000000000000000`. Which is the
/// maximum value of a [`Felt`].
///
/// It is a value generated by StarknetOs.
///
/// [previous block number]: https://github.com/keep-starknet-strange/piltover/blob/a7d6b17f855f2295a843bfd0ab0dcd696c6229a8/src/snos_output.cairo#L34
const INITIAL_BLOCK_NUMBER: Felt = Felt::MAX;
const INITIAL_BLOCK_HASH: BlockHash = Felt::ZERO;

// appchain::constructor() https://github.com/keep-starknet-strange/piltover/blob/a7d6b17f855f2295a843bfd0ab0dcd696c6229a8/src/appchain.cairo#L122-L128
let request = factory.deploy_v1(
vec![
account.address(), // owner
Felt::ZERO, // state_root
Felt::ZERO, // block_number
Felt::ZERO, // block_hash
// owner.
account.address(),
// state root.
INITIAL_STATE_ROOT,
// block_number must be magic value for genesis block.
INITIAL_BLOCK_NUMBER,
// block_hash.
INITIAL_BLOCK_HASH,
],
salt,
false,
Expand All @@ -179,17 +173,29 @@ pub async fn deploy_settlement_contract(
let appchain = AppchainContract::new(deployed_appchain_contract, &account);

// Compute the chain's config hash
let config_hash = compute_config_hash(
let snos_config_hash = compute_config_hash(
chain_id,
// NOTE:
//
// This is the default fee token contract address of chains generated using `katana
// init`. We shouldn't hardcode this and need to handle this more
// elegantly.
felt!("0x2e7442625bab778683501c0eadbc1ea17b3535da040a12ac7d281066e915eea"),
);

// 1. Program Info

sp.update_text("Setting program info...");

let program_info = ProgramInfo {
snos_config_hash,
snos_program_hash: SNOS_PROGRAM_HASH,
bootloader_program_hash: BOOTLOADER_PROGRAM_HASH,
layout_bridge_program_hash: LAYOUT_BRIDGE_PROGRAM_HASH,
};

let res = appchain
.set_program_info(&PROGRAM_HASH, &config_hash)
.set_program_info(&program_info)
.send()
.await
.inspect(|res| {
Expand Down Expand Up @@ -233,8 +239,12 @@ pub async fn deploy_settlement_contract(
result
}

/// Checks that the program info is correctly set on the contract according to the chain's
/// configuration.
/// Checks that the settlement contract is correctly configured.
///
/// The values checked are:-
/// * Program info (config hash, and StarknetOS program hash)
/// * Fact registry contract address
/// * Layout bridge program hash
pub async fn check_program_info(
chain_id: Felt,
appchain_address: Felt,
Expand All @@ -245,26 +255,44 @@ pub async fn check_program_info(
// Compute the chain's config hash
let config_hash = compute_config_hash(
chain_id,
// NOTE:
//
// This is the default fee token contract address of chains generated using `katana init`.
// We shouldn't hardcode this and need to handle this more elegantly.
felt!("0x2e7442625bab778683501c0eadbc1ea17b3535da040a12ac7d281066e915eea"),
);

// Assert that the values are correctly set
let (program_info_res, facts_registry_res) =
tokio::join!(appchain.get_program_info().call(), appchain.get_facts_registry().call());

let (actual_program_hash, actual_config_hash) = program_info_res?;
let actual_program_info = program_info_res?;
let facts_registry = facts_registry_res?;

if actual_program_hash != PROGRAM_HASH {
return Err(ContractInitError::InvalidProgramHash {
actual: actual_program_hash,
expected: PROGRAM_HASH,
if actual_program_info.layout_bridge_program_hash != LAYOUT_BRIDGE_PROGRAM_HASH {
return Err(ContractInitError::InvalidLayoutBridgeProgramHash {
actual: actual_program_info.layout_bridge_program_hash,
expected: LAYOUT_BRIDGE_PROGRAM_HASH,
});
}

if actual_config_hash != config_hash {
if actual_program_info.bootloader_program_hash != BOOTLOADER_PROGRAM_HASH {
return Err(ContractInitError::InvalidBootloaderProgramHash {
actual: actual_program_info.bootloader_program_hash,
expected: BOOTLOADER_PROGRAM_HASH,
});
}

if actual_program_info.snos_program_hash != SNOS_PROGRAM_HASH {
return Err(ContractInitError::InvalidSnosProgramHash {
actual: actual_program_info.snos_program_hash,
expected: SNOS_PROGRAM_HASH,
});
}

if actual_program_info.snos_config_hash != config_hash {
return Err(ContractInitError::InvalidConfigHash {
actual: actual_config_hash,
actual: actual_program_info.snos_config_hash,
expected: config_hash,
});
}
Expand Down Expand Up @@ -292,9 +320,22 @@ pub enum ContractInitError {
Initialization(AccountError<<InitializerAccount as Account>::SignError>),

#[error(
"invalid program info: program hash mismatch - expected {expected:#x}, got {actual:#x}"
"invalid program info: layout bridge program hash mismatch - expected {expected:#x}, got \
{actual:#x}"
)]
InvalidLayoutBridgeProgramHash { expected: Felt, actual: Felt },

#[error(
"invalid program info: bootloader program hash mismatch - expected {expected:#x}, got \
{actual:#x}"
)]
InvalidBootloaderProgramHash { expected: Felt, actual: Felt },

#[error(
"invalid program info: snos program hash mismatch - expected {expected:#x}, got \
{actual:#x}"
)]
InvalidProgramHash { expected: Felt, actual: Felt },
InvalidSnosProgramHash { expected: Felt, actual: Felt },

#[error("invalid program info: config hash mismatch - expected {expected:#x}, got {actual:#x}")]
InvalidConfigHash { expected: Felt, actual: Felt },
Expand Down
4 changes: 2 additions & 2 deletions crates/dojo/test-utils/src/sequencer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use katana_core::backend::Backend;
use katana_core::constants::DEFAULT_SEQUENCER_ADDRESS;
use katana_executor::implementation::blockifier::BlockifierFactory;
use katana_node::config::dev::DevConfig;
use katana_node::config::rpc::{RpcConfig, DEFAULT_RPC_ADDR, DEFAULT_RPC_MAX_CONNECTIONS};
use katana_node::config::rpc::{RpcConfig, DEFAULT_RPC_ADDR};
pub use katana_node::config::*;
use katana_node::LaunchedNode;
use katana_primitives::chain::ChainId;
Expand Down Expand Up @@ -124,9 +124,9 @@ pub fn get_default_test_config(sequencing: SequencingConfig) -> Config {
port: 0,
addr: DEFAULT_RPC_ADDR,
apis: RpcModulesList::all(),
max_connections: DEFAULT_RPC_MAX_CONNECTIONS,
max_event_page_size: Some(100),
max_proof_keys: Some(100),
..Default::default()
};

Config { sequencing, rpc, dev, chain: ChainSpec::Dev(chain).into(), ..Default::default() }
Expand Down
3 changes: 2 additions & 1 deletion crates/katana/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,13 @@ impl NodeArgs {

modules
};

Ok(RpcConfig {
apis: modules,
port: self.server.http_port,
addr: self.server.http_addr,
max_connections: self.server.max_connections,
max_request_body_size: None,
max_response_body_size: None,
cors_origins: self.server.http_cors_origins.clone(),
max_event_page_size: Some(self.server.max_event_page_size),
max_proof_keys: Some(self.server.max_proof_keys),
Expand Down
Loading

0 comments on commit 6ee7082

Please sign in to comment.