Skip to content

feat: bump rpc spec to 0.8 #3179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fc68092
chore: bump scarb + remove unuse deps
glihm Apr 15, 2025
9c5f86c
update katana runner dep
kariy Apr 16, 2025
9bb1f0d
remove test sequencer
kariy Apr 16, 2025
1554854
remove rpc test utils
kariy Apr 16, 2025
f335a34
update `starknet` to `0.14.0`
kariy Apr 17, 2025
1e1f8d2
fix controller account
kariy Apr 17, 2025
18bccbc
handle not controller feature
kariy Apr 21, 2025
a72099d
refactor(torii-sqlite): move types into its own crate (#3170)
kariy Apr 16, 2025
3cb6c2e
ci(release): update workflow to use Ubuntu 22.04
steebchen Apr 17, 2025
6eddb43
ci(release): update runner to ubuntu-22.04 for docker build
steebchen Apr 17, 2025
6b95901
ci(workflows): update runner to ubuntu-latest-32-cores
steebchen Apr 17, 2025
0fbe17e
fix(Dockerfile): move dependencies in base image (#3173)
steebchen Apr 17, 2025
cc65162
Prepare release: v1.4.2 (#3176)
tarrencev Apr 17, 2025
271554f
chore(devcontainer): update image: v1.4.2 (#3177)
tarrencev Apr 17, 2025
d6d52d3
fix(torii-indexer): stack overflow when dealing with a high number of…
Larkooo Apr 18, 2025
6cebde6
feat(katana): add fact registry arg for `init` (#3158)
cwkang1998 Apr 21, 2025
4daa14e
feat(sozo): unreal bindings handle int64 and ControllerConnect (#3178)
caillef Apr 21, 2025
8c48c42
feat: bump cairo 2.10 and remove katana and torii dependencies (#3169)
glihm Apr 22, 2025
6b77901
fix(ci): remove katana bench
glihm Apr 22, 2025
0ff7314
fix(sozo): avoid spurious logs from external crates
glihm Apr 22, 2025
8b8fedd
wip
kariy Apr 28, 2025
75977c2
Merge branch 'main' into rpc-0.8.0
kariy Apr 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,063 changes: 741 additions & 322 deletions Cargo.lock

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -41,8 +41,8 @@ debug = true
inherits = "release"

[workspace.dependencies]
cainome = { version = "0.5.0", features = [ "abigen-rs" ] }
cainome-cairo-serde = { version = "0.1.0" }
cainome = { version = "0.6.1", features = [ "abigen-rs" ] }
cainome-cairo-serde = { version = "0.2.0" }

dojo-utils = { path = "crates/dojo/utils" }

@@ -66,13 +66,13 @@ torii-client = { path = "crates/torii/client" }
torii-graphql = { path = "crates/torii/graphql" }
torii-grpc = { path = "crates/torii/grpc" }
torii-indexer = { path = "crates/torii/indexer" }
torii-mcp = { path = "crates/torii/mcp" }
torii-relay = { path = "crates/torii/libp2p" }
torii-runner = { path = "crates/torii/runner" }
torii-server = { path = "crates/torii/server" }
torii-sqlite = { path = "crates/torii/sqlite/sqlite" }
torii-sqlite-types = { path = "crates/torii/sqlite/types" }
torii-typed-data = { path = "crates/torii/typed-data" }
torii-mcp = { path = "crates/torii/mcp" }

# sozo
sozo-ops = { path = "crates/sozo/ops" }
@@ -83,6 +83,8 @@ sozo-walnut = { path = "crates/sozo/walnut" }
# macros
merge-options = { path = "crates/macros/merge-options" }

katana-runner = { git = "https://github.com/dojoengine/katana", branch = "rpc-0.8.0" }

anyhow = "1.0.89"
arbitrary = { version = "1.3.2", features = [ "derive" ] }
assert_fs = "1.1"
@@ -189,7 +191,6 @@ walkdir = "2.5.0"
ipfs-api-backend-hyper = { git = "https://github.com/ferristseng/rust-ipfs-api", rev = "af2c17f7b19ef5b9898f458d97a90055c3605633", features = [ "with-hyper-rustls", "with-send-sync" ] }
mime_guess = "2.0"


# server
hyper = "0.14.27"
warp = "0.3"
@@ -211,7 +212,7 @@ criterion = "0.5.1"
pprof = { version = "0.13.0", features = [ "criterion", "flamegraph" ] }

# Slot integration. Dojo don't need to manually include `account_sdk` as dependency as `slot` already re-exports it.
slot = { git = "https://github.com/cartridge-gg/slot", rev = "1298a30" }
slot = { git = "https://github.com/cartridge-gg/slot", rev = "adac33e" }

# alloy core
alloy-primitives = { version = "0.8", default-features = false }
@@ -226,7 +227,7 @@ alloy-rpc-types-eth = { version = "0.4", default-features = false }
alloy-signer = { version = "0.4", default-features = false }
alloy-transport = { version = "0.4", default-features = false }

starknet = "0.12.0"
starknet = "0.14.0"
starknet-crypto = "0.7.1"
starknet-types-core = { version = "0.1.7", features = [ "arbitrary", "hash" ] }

17 changes: 16 additions & 1 deletion bin/sozo/src/commands/call.rs
Original file line number Diff line number Diff line change
@@ -141,7 +141,10 @@ impl CallArgs {
contract_address,
match &e {
ProviderError::StarknetError(StarknetError::ContractError(e)) => {
format!("Contract error: {}", e.revert_error.clone())
format!(
"Contract error: {}",
format_execution_error(&e.revert_error)
)
}
_ => e.to_string(),
}
@@ -153,3 +156,15 @@ impl CallArgs {
})
}
}

fn format_execution_error(error: &starknet::core::types::ContractExecutionError) -> String {
match error {
starknet::core::types::ContractExecutionError::Message(msg) => msg.clone(),
starknet::core::types::ContractExecutionError::Nested(inner) => {
let address = format!("0x{:x}", inner.contract_address);
let selector = format!("0x{:x}", inner.selector);
let inner_error = format_execution_error(&inner.error);
format!("Error in contract at {address} when calling {selector}:\n {inner_error}",)
}
}
}
44 changes: 20 additions & 24 deletions bin/sozo/src/commands/options/account/controller.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::collections::HashMap;
use std::sync::Arc;

use anyhow::{bail, Result};
use dojo_world::contracts::contract_info::ContractInfo;
use slot::account_sdk::account::session::hash::{Policy, ProvedPolicy};
use slot::account_sdk::account::session::account::SessionAccount;
use slot::account_sdk::account::session::merkle::MerkleTree;
use slot::account_sdk::account::session::SessionAccount;
use slot::account_sdk::account::session::policy::{CallPolicy, MerkleLeaf, Policy, ProvedPolicy};
use slot::account_sdk::provider::CartridgeJsonRpcProvider;
use slot::session::{FullSessionInfo, PolicyMethod};
use starknet::core::types::Felt;
use starknet::core::utils::get_selector_from_name;
@@ -14,14 +14,8 @@ use starknet::providers::Provider;
use tracing::trace;
use url::Url;

// Why the Arc? becaues the Controller account implementation over on `account_sdk` crate is
// riddled with `+ Clone` bounds on its Provider generic. So we explicitly specify that the Provider
// impl here is wrapped in an Arc to satisfy the Clone bound. Otherwise, you would get a 'trait
// bound not satisfied' error.
//
// This type comes from account_sdk, which doesn't derive Debug.
#[allow(missing_debug_implementations)]
pub type ControllerSessionAccount<P> = SessionAccount<Arc<P>>;
pub type ControllerAccount = SessionAccount;

/// Create a new Catridge Controller account based on session key.
///
@@ -34,18 +28,14 @@ pub type ControllerSessionAccount<P> = SessionAccount<Arc<P>>;
/// * Starknet mainnet
/// * Starknet sepolia
/// * Slot hosted networks
#[tracing::instrument(name = "create_controller", skip(rpc_url, provider, contracts))]
pub async fn create_controller<P>(
#[tracing::instrument(name = "create_controller", skip(rpc_url, rpc_provider, contracts))]
pub async fn create_controller(
// Ideally we can get the url from the provider so we dont have to pass an extra url param here
rpc_url: Url,
provider: P,
rpc_provider: CartridgeJsonRpcProvider,
contracts: &HashMap<String, ContractInfo>,
) -> Result<ControllerSessionAccount<P>>
where
P: Provider,
P: Send + Sync,
{
let chain_id = provider.chain_id().await?;
) -> Result<ControllerAccount> {
let chain_id = rpc_provider.chain_id().await?;

trace!(target: "account::controller", "Loading Slot credentials.");
let credentials = slot::credential::Credentials::load()?;
@@ -62,7 +52,7 @@ where
// Check if the session exists, if not create a new one
let session_details = match slot::session::get(chain_id)? {
Some(session) => {
trace!(target: "account::controller", expires_at = %session.session.expires_at, policies = session.session.policies.len(), "Found existing session.");
trace!(target: "account::controller", expires_at = %session.session.inner.expires_at, policies = session.session.proved_policies.len(), "Found existing session.");

// Check if the policies have changed
let is_equal = is_equal_to_existing(&policies, &session);
@@ -73,7 +63,7 @@ where
trace!(
target: "account::controller",
new_policies = policies.len(),
existing_policies = session.session.policies.len(),
existing_policies = session.session.requested_policies.len(),
"Policies have changed. Creating new session."
);

@@ -92,7 +82,7 @@ where
}
};

Ok(session_details.into_account(Arc::new(provider)))
Ok(session_details.into_account(rpc_provider))
}

// Check if the new policies are equal to the ones in the existing session
@@ -102,7 +92,13 @@ where
fn is_equal_to_existing(new_policies: &[PolicyMethod], session_info: &FullSessionInfo) -> bool {
let new_policies = new_policies
.iter()
.map(|p| Policy::new(p.target, get_selector_from_name(&p.method).unwrap()))
.map(|p| {
Policy::Call(CallPolicy {
authorized: Some(true),
contract_address: p.target,
selector: get_selector_from_name(&p.method).expect("valid selector"),
})
})
.collect::<Vec<Policy>>();

// Copied from Session::new
@@ -118,7 +114,7 @@ fn is_equal_to_existing(new_policies: &[PolicyMethod], session_info: &FullSessio
.collect::<Vec<ProvedPolicy>>();

let new_policies_root = MerkleTree::compute_root(hashes[0], new_policies[0].proof.clone());
new_policies_root == session_info.session.authorization_root
new_policies_root == session_info.session.inner.allowed_policies_root
}

/// Policies are the building block of a session key. It's what defines what methods are allowed for
23 changes: 15 additions & 8 deletions bin/sozo/src/commands/options/account/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;

use anyhow::{anyhow, Result};
use clap::Args;
use dojo_utils::env::DOJO_ACCOUNT_ADDRESS_ENV_VAR;
use dojo_world::config::Environment;
use dojo_world::contracts::ContractInfo;
#[cfg(feature = "controller")]
use slot::account_sdk::provider::CartridgeJsonRpcProvider;
use starknet::accounts::{ExecutionEncoding, SingleOwnerAccount};
use starknet::core::types::{BlockId, BlockTag, Felt};
use starknet::providers::Provider;
@@ -17,10 +20,11 @@ use super::starknet::StarknetOptions;

#[cfg(feature = "controller")]
pub mod controller;
pub mod provider;
mod r#type;

#[cfg(feature = "controller")]
use controller::ControllerSessionAccount;
use controller::ControllerAccount;
pub use r#type::*;

// INVARIANT:
@@ -76,7 +80,7 @@ impl AccountOptions {
///
/// # Arguments
///
/// * `provider` - Starknet provider.
/// * `provider` - Starknet provider (only if you're NOT creating a Controller account).
/// * `env_metadata` - Environment pulled from configuration.
/// * `starknet` - Starknet options.
/// * `contracts` - The [`ContractInfo`] mappings. This one could have been gated behind the
@@ -96,8 +100,9 @@ impl AccountOptions {
#[cfg(feature = "controller")]
if self.controller {
let url = starknet.url(env_metadata)?;
let account = self.controller(url, provider, contracts).await?;
return Ok(SozoAccount::Controller(account));
let cartridge_provider = CartridgeJsonRpcProvider::new(url.clone());
let account = self.controller(url, cartridge_provider.clone(), contracts).await?;
return Ok(SozoAccount::new_controller(cartridge_provider, account));
}

let _ = starknet;
@@ -109,9 +114,9 @@ impl AccountOptions {

pub async fn std_account<P>(
&self,
provider: P,
provider: Arc<P>,
env_metadata: Option<&Environment>,
) -> Result<SingleOwnerAccount<P, LocalWallet>>
) -> Result<SingleOwnerAccount<Arc<P>, LocalWallet>>
where
P: Provider,
P: Send + Sync,
@@ -153,6 +158,8 @@ impl AccountOptions {

#[cfg(test)]
mod tests {
use std::sync::Arc;

use clap::Parser;
use katana_runner::RunnerCtx;
use starknet::accounts::ExecutionEncoder;
@@ -234,7 +241,7 @@ mod tests {

// HACK: SingleOwnerAccount doesn't expose a way to check `encoding` type used in struct, so
// checking it by encoding a dummy call and checking which method it used to encode the call
let account = cmd.account.std_account(runner.provider(), None).await.unwrap();
let account = cmd.account.std_account(Arc::new(runner.provider()), None).await.unwrap();
let result = account.encode_calls(&dummy_call);
// 0x0 is the data offset.
assert!(*result.get(3).unwrap() == Felt::from_hex("0x0").unwrap());
@@ -252,7 +259,7 @@ mod tests {

// HACK: SingleOwnerAccount doesn't expose a way to check `encoding` type used in struct, so
// checking it by encoding a dummy call and checking which method it used to encode the call
let account = cmd.account.std_account(runner.provider(), None).await.unwrap();
let account = cmd.account.std_account(Arc::new(runner.provider()), None).await.unwrap();
let result = account.encode_calls(&dummy_call);
// 0x2 is the Calldata len.
assert!(*result.get(3).unwrap() == Felt::from_hex("0x2").unwrap());
58 changes: 52 additions & 6 deletions bin/sozo/src/commands/options/account/provider.rs
Original file line number Diff line number Diff line change
@@ -4,12 +4,13 @@ use async_trait::async_trait;
use starknet::core::types::{
BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction,
BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction,
ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter,
EventsPage, FeeEstimate, Felt, FunctionCall, InvokeTransactionResult,
MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs,
MaybePendingStateUpdate, MsgFromL1, SimulatedTransaction, SimulationFlag,
SimulationFlagForEstimateFee, SyncStatusType, Transaction, TransactionReceiptWithBlockInfo,
TransactionStatus, TransactionTrace, TransactionTraceWithHash,
ConfirmedBlockId, ContractClass, ContractStorageKeys, DeclareTransactionResult,
DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, Felt, FunctionCall,
Hash256, InvokeTransactionResult, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes,
MaybePendingBlockWithTxs, MaybePendingStateUpdate, MessageWithStatus, MsgFromL1,
SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StorageProof,
SyncStatusType, Transaction, TransactionReceiptWithBlockInfo, TransactionStatus,
TransactionTrace, TransactionTraceWithHash,
};
use starknet::providers::{Provider, ProviderError, ProviderRequestData, ProviderResponseData};

@@ -102,6 +103,16 @@ where
}
}

async fn get_messages_status(
&self,
transaction_hash: Hash256,
) -> Result<Vec<MessageWithStatus>, ProviderError> {
match self {
Self::Left(p) => p.get_messages_status(transaction_hash).await,
Self::Right(q) => q.get_messages_status(transaction_hash).await,
}
}

async fn get_transaction_status<H>(
&self,
transaction_hash: H,
@@ -304,6 +315,41 @@ where
}
}

async fn get_storage_proof<B, H, A, K>(
&self,
block_id: B,
class_hashes: H,
contract_addresses: A,
contracts_storage_keys: K,
) -> Result<StorageProof, ProviderError>
where
B: AsRef<ConfirmedBlockId> + Send + Sync,
H: AsRef<[Felt]> + Send + Sync,
A: AsRef<[Felt]> + Send + Sync,
K: AsRef<[ContractStorageKeys]> + Send + Sync,
{
match self {
Self::Left(p) => {
p.get_storage_proof(
block_id,
class_hashes,
contract_addresses,
contracts_storage_keys,
)
.await
}
Self::Right(q) => {
q.get_storage_proof(
block_id,
class_hashes,
contract_addresses,
contracts_storage_keys,
)
.await
}
}
}

async fn add_invoke_transaction<I>(
&self,
invoke_transaction: I,
Loading