Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Commit

Permalink
add runtime_api folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Yogalholic authored and tdelabro committed Nov 21, 2023
1 parent 237019d commit 709857a
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 0 deletions.
101 changes: 101 additions & 0 deletions crates/pallets/starknet/runtime_api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
[package]
name = "pallet-starknet-runtime-api"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# Madara primitives
mp-block = { workspace = true }
mp-chain-id = { workspace = true }
mp-commitments = { workspace = true }
mp-digest-log = { workspace = true }
mp-fee = { workspace = true }
mp-felt = { workspace = true, features = ["parity-scale-codec", "serde"] }
mp-hashers = { workspace = true }
mp-sequencer-address = { workspace = true, features = ["parity-scale-codec"] }
mp-state = { workspace = true }
mp-storage = { workspace = true, features = ["parity-scale-codec"] }
mp-transactions = { workspace = true, features = ["scale-info"] }

blockifier = { workspace = true, features = [
"testing",
"parity-scale-codec",
"scale-info",
] }
starknet-core = { workspace = true }
starknet-crypto = { workspace = true, features = ["alloc"] }
starknet_api = { workspace = true, features = [
"scale-info",
"parity-scale-codec",
] }

# Substrate frame
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
# Substrate Client
sc-cli = { workspace = true, optional = true }
# Substrate primitives
sp-api = { workspace = true }
sp-arithmetic = { workspace = true }
sp-core = { workspace = true }
sp-inherents = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
# Frame pallets

# Other third party dependencies
cairo-lang-casm-contract-class = { workspace = true, optional = true, features = [
"std",
] }
derive_more = { workspace = true }
hashbrown = { workspace = true }
hex = { workspace = true }
indexmap = { workspace = true }
log = { workspace = true }
parity-scale-codec = { workspace = true, features = ["derive"] }
reqwest = { workspace = true, optional = true, features = [
"blocking",
"rustls-tls",
] }
scale-info = { workspace = true, features = ["derive"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_with = { workspace = true }

[dev-dependencies]
pallet-timestamp = { workspace = true }
pretty_assertions = { workspace = true }
test-case = "3.1.0"
lazy_static = "1.4.0"
hexlit = "0.5.5"
assert_matches = "1.5.0"
starknet-ff = { workspace = true }
project-root = "0.2.2"

[features]
default = ["std"]
std = [
# Substrate
"frame-support/std",
"frame-system/std",
"sc-cli",
"sp-io/std",
"sp-runtime/std",
"frame-benchmarking?/std",
"scale-info/std",
"pallet-timestamp/std",
"sp-inherents/std",
# Starknet
"starknet-crypto/std",
"blockifier/std",
"mp-sequencer-address/std",
"mp-felt/std",
# Other third party dependencies
"dep:reqwest",
"dep:cairo-lang-casm-contract-class",
"parity-scale-codec/std",
]
135 changes: 135 additions & 0 deletions crates/pallets/starknet/runtime_api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! Definition of the runtime API for the StarkNet pallet.
// Adding allow unused type parameters to avoid clippy errors
// generated by the `decl_runtime_apis` macro.
// Specifically, the macro generates a trait (`StarknetRuntimeApi`) with unused type parameters.
#![allow(clippy::extra_unused_type_parameters)]

use alloc::sync::Arc;

use blockifier::execution::contract_class::ContractClass;
use mp_felt::Felt252Wrapper;
use mp_transactions::{Transaction, TxType, UserTransaction};
use sp_api::BlockT;
pub extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;

use sp_runtime::DispatchError;
use starknet_api::api_core::{ChainId, ClassHash, ContractAddress, EntryPointSelector, Nonce};
use starknet_api::block::{BlockNumber, BlockTimestamp};
use starknet_api::hash::StarkFelt;
use starknet_api::state::StorageKey;
use starknet_api::transaction::{Calldata, Event as StarknetEvent, TransactionHash};

#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)]
pub enum StarknetTransactionExecutionError {
ContractNotFound,
ClassAlreadyDeclared,
ClassHashNotFound,
InvalidContractClass,
ContractError,
}

sp_api::decl_runtime_apis! {
pub trait StarknetRuntimeApi {
/// Returns the nonce associated with the given address in the given block
fn nonce(contract_address: ContractAddress) -> Nonce;
/// Returns a storage slot value
fn get_storage_at(address: ContractAddress, key: StorageKey) -> Result<StarkFelt, DispatchError>;
/// Returns a `Call` response.
fn call(address: ContractAddress, function_selector: EntryPointSelector, calldata: Calldata) -> Result<Vec<Felt252Wrapper>, DispatchError>;
/// Returns the contract class hash at the given address.
fn contract_class_hash_by_address(address: ContractAddress) -> ClassHash;
/// Returns the contract class for the given class hash.
fn contract_class_by_class_hash(class_hash: ClassHash) -> Option<ContractClass>;
/// Returns the chain id.
fn chain_id() -> Felt252Wrapper;
/// Returns fee estimate
fn estimate_fee(transactions: Vec<UserTransaction>) -> Result<Vec<(u64, u64)>, DispatchError>;
/// Filters extrinsic transactions to return only Starknet transactions
///
/// To support runtime upgrades, the client must be unaware of the specific extrinsic
/// details. To achieve this, the client uses an OpaqueExtrinsic type to represent and
/// manipulate extrinsics. However, the client cannot decode and filter extrinsics due to
/// this limitation. The solution is to offload decoding and filtering to the RuntimeApi in
/// the runtime itself, accomplished through the extrinsic_filter method. This enables the
/// client to operate seamlessly while abstracting the extrinsic complexity.
fn extrinsic_filter(xts: Vec<<Block as BlockT>::Extrinsic>) -> Vec<Transaction>;
fn get_events_for_tx_hash(xts: Vec<<Block as BlockT>::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: Felt252Wrapper) -> Option<(TxType, Vec<StarknetEvent>)>;

/// Return the list of StarknetEvent evmitted during this block, along with the hash of the starknet transaction they bellong to
///
/// `block_extrinsics` is the list of all the extrinsic executed during this block, it is used in order to match
fn get_starknet_events_and_their_associated_tx_hash(block_extrinsics: Vec<<Block as BlockT>::Extrinsic>, chain_id: Felt252Wrapper) -> Vec<(Felt252Wrapper, StarknetEvent)>;
/// Return the outcome of the tx execution
fn get_tx_execution_outcome(tx_hash: TransactionHash) -> Option<Vec<u8>>;
/// Return the block context
fn get_block_context() -> BlockContext;
}

pub trait ConvertTransactionRuntimeApi {
/// Converts the transaction to an UncheckedExtrinsic for submission to the pool.
fn convert_transaction(transaction: UserTransaction) -> Result<<Block as BlockT>::Extrinsic, DispatchError>;
/// Converts the DispatchError to an understandable error for the client
fn convert_error(error: DispatchError) -> StarknetTransactionExecutionError;
}
}

#[derive(Clone, Debug, parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)]
pub struct BlockContext {
pub chain_id: String,
pub block_number: u64,
pub block_timestamp: u64,

// Fee-related.
pub sequencer_address: ContractAddress,
pub fee_token_address: ContractAddress,
pub vm_resource_fee_cost: Vec<(String, sp_arithmetic::fixed_point::FixedU128)>,
pub gas_price: u128, // In wei.

// Limits.
pub invoke_tx_max_n_steps: u32,
pub validate_max_n_steps: u32,
pub max_recursion_depth: u32,
}

#[cfg(feature = "std")]
use std::collections::HashMap;

#[cfg(not(feature = "std"))]
use hashbrown::HashMap;

impl From<BlockContext> for blockifier::block_context::BlockContext {
fn from(value: BlockContext) -> Self {
Self {
chain_id: ChainId(value.chain_id),
block_number: BlockNumber(value.block_number),
block_timestamp: BlockTimestamp(value.block_timestamp),
sequencer_address: value.sequencer_address,
fee_token_address: value.fee_token_address,
vm_resource_fee_cost: Arc::new(HashMap::from_iter(value.vm_resource_fee_cost)),
gas_price: value.gas_price,
invoke_tx_max_n_steps: value.invoke_tx_max_n_steps,
validate_max_n_steps: value.validate_max_n_steps,
max_recursion_depth: value.max_recursion_depth,
}
}
}

impl From<blockifier::block_context::BlockContext> for BlockContext {
fn from(value: blockifier::block_context::BlockContext) -> Self {
Self {
chain_id: value.chain_id.0,
block_number: value.block_number.0,
block_timestamp: value.block_timestamp.0,
sequencer_address: value.sequencer_address,
fee_token_address: value.fee_token_address,
vm_resource_fee_cost: Vec::from_iter(value.vm_resource_fee_cost.iter().map(|(k, v)| (k.clone(), *v))),
gas_price: value.gas_price,
invoke_tx_max_n_steps: value.invoke_tx_max_n_steps,
validate_max_n_steps: value.validate_max_n_steps,
max_recursion_depth: value.max_recursion_depth,
}
}
}

0 comments on commit 709857a

Please sign in to comment.