Skip to content

Commit

Permalink
Feature: support Sierra 1.6 (#328)
Browse files Browse the repository at this point in the history
* Feature: support Sierra 1.6

Problem: some contracts on Sepolia are built with Sierra 1.6, which is
not supported by the version of the CASM compiler we use. But bumping
the version of the compiler requires bumping cairo-vm and Blockifier as
well.

Solution: bump everything! We now use:
* cairo-vm 1.0.1
* cairo-lang 2.7.1
* blockifier 0.8.0-rc.2

With this, we can now compile any contract on Sepolia.

* Internal: remove deprecated `to_felt252` function

This function is no longer required as felt types now all rely on
starknet-types-core.

* Internal: remove deprecated `felt_vm2api` function

This function is no longer required as felt types now all rely on
starknet-types-core.

* Internal: remove deprecated `felt_api2vm` function

This function is no longer required as felt types now all rely on
starknet-types-core.

* clippy

* fmt

* Feature: support blocks requiring Starknet v0.13.2

* Internal: remove deprecated `felt_to_vm` function

This function is no longer required as felt types now all rely on
starknet-types-core.

* CI: add tests for DiffAssertValues resolution

* CI: regression test for diff assert values in contract subcall

* doc chain_id

* fix review: expect(todo)

* fix of the fix
  • Loading branch information
Olivier Desenfans authored Aug 29, 2024
1 parent da54de3 commit a051468
Show file tree
Hide file tree
Showing 37 changed files with 478 additions and 545 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/prove_blocks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@ jobs:
bash scripts/setup-tests.sh
- name: Prove Blocks
run: bash scripts/prove-blocks.sh -p ${{ secrets.PATHFINDER_RPC_URL }} -b 76793,76766,76775
run: |
# These blocks verify the following issues:
# * 76793: the first block that we managed to prove, only has a few invoke txs
# * 76766 / 76775: additional basic blocks
# * 86507 / 124533: a failing assert that happened because we used the wrong VersionedConstants
# * 87019: diff assert values in contract subcall
bash scripts/prove-blocks.sh -p ${{ secrets.PATHFINDER_RPC_URL }} -b 76793,76766,76775,86507,87019,124533
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ assert_matches = "1.5.0"
base64 = "0.21.3"
bitvec = { version = "1.0.1", features = ["serde"] }
# Point to the latest commit of branch msl/snos-0.6.0-rc.2
blockifier = { git = "https://github.com/Moonsong-Labs/blockifier", rev = "983e3b1cdb6621c5e6fa600f47cd69bf9e287621", features = ["testing"] }
cairo-lang-starknet = { version = "2.6.3" }
cairo-lang-starknet-classes = { version = "2.6.3" }
cairo-lang-utils = { version = "2.6.3" }
cairo-lang-casm = { version = "2.6.3" }
blockifier = { git = "https://github.com/Moonsong-Labs/sequencer", rev = "01b97d9354faefa5f0cd520b5efbe73178213f7e", features = ["testing"] }
cairo-lang-starknet = { version = "=2.7.1" }
cairo-lang-starknet-classes = { version = "=2.7.1" }
cairo-lang-utils = { version = "=2.7.1" }
cairo-lang-casm = { version = "=2.7.1" }
cairo-type-derive = { version = "0.1.0", path = "crates/cairo-type-derive" }
cairo-vm = { version = "=1.0.0-rc5", features = ["extensive_hints", "cairo-1-hints"] }
cairo-vm = { version = "=1.0.1", features = ["extensive_hints", "cairo-1-hints"] }
clap = { version = "4.5.4", features = ["derive"] }
env_logger = "0.11.3"
flate2 = "1.0.32"
Expand Down Expand Up @@ -58,7 +58,7 @@ serde_json = { version = "1.0.105", features = ["arbitrary_precision"] }
serde_with = "3.3.0"
serde_yaml = "0.9.25"
starknet = "0.11.0"
starknet_api = { version = "=0.10", features = ["testing"] }
starknet_api = { git = "https://github.com/Moonsong-Labs/sequencer", rev = "01b97d9354faefa5f0cd520b5efbe73178213f7e", features = ["testing"] }
starknet-core = "0.11.1"
starknet-crypto = "0.6.2"
starknet-os = { path = "crates/starknet-os" }
Expand Down
21 changes: 11 additions & 10 deletions crates/bin/prove_block/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet};
use std::error::Error;

use blockifier::state::cached_state::{CachedState, GlobalContractCache};
use blockifier::state::cached_state::CachedState;
use cairo_vm::types::layout_name::LayoutName;
use cairo_vm::vm::errors::cairo_run_errors::CairoRunError::VmException;
use cairo_vm::Felt252;
Expand All @@ -24,13 +24,13 @@ use starknet_os::starknet::business_logic::fact_state::contract_state_objects::C
use starknet_os::starknet::starknet_storage::CommitmentInfo;
use starknet_os::starkware_utils::commitment_tree::base_types::Height;
use starknet_os::starkware_utils::commitment_tree::patricia_tree::patricia_tree::PatriciaTree;
use starknet_os::utils::felt_api2vm;
use starknet_os::{config, run_os};
use starknet_os_types::chain_id::chain_id_from_felt;
use starknet_os_types::sierra_contract_class::GenericSierraContractClass;
use starknet_types_core::felt::Felt;

use crate::reexecute::format_commitment_facts;
use crate::rpc_utils::PathfinderClassProof;
use crate::rpc_utils::{get_starknet_version, PathfinderClassProof};
use crate::state_utils::get_processed_state_update;
use crate::types::starknet_rs_tx_to_internal_tx;

Expand Down Expand Up @@ -113,7 +113,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
reqwest::ClientBuilder::new().build().unwrap_or_else(|e| panic!("Could not build reqwest client: {e}"));

// Step 1: build the block context
let chain_id = provider.chain_id().await?.to_string();
let chain_id = chain_id_from_felt(provider.chain_id().await?);
log::debug!("provider's chain_id: {}", chain_id);
let block_with_txs = match provider.get_block_with_txs(block_id).await? {
MaybePendingBlockWithTxs::Block(block_with_txs) => block_with_txs,
Expand All @@ -122,6 +122,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
};

let starknet_version = get_starknet_version(&block_with_txs);
log::debug!("Starknet version: {:?}", starknet_version);

// We only need to get the older block number and hash. No need to fetch all the txs
let older_block = match provider
.get_block_with_tx_hashes(BlockId::Number(block_number - STORED_BLOCK_HASH_BUFFER))
Expand All @@ -134,7 +137,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
};

let block_context = build_block_context(chain_id.clone(), &block_with_txs);
let block_context = build_block_context(chain_id.clone(), &block_with_txs, starknet_version);

let old_block_number = Felt252::from(older_block.block_number);
let old_block_hash = older_block.block_hash;
Expand All @@ -155,7 +158,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
));
let blockifier_state_reader = AsyncRpcStateReader::new(provider_for_blockifier, BlockId::Number(block_number - 1));

let mut blockifier_state = CachedState::new(blockifier_state_reader, GlobalContractCache::new(1024));
let mut blockifier_state = CachedState::new(blockifier_state_reader);
let tx_execution_infos = reexecute_transactions_with_blockifier(
&mut blockifier_state,
&block_context,
Expand Down Expand Up @@ -189,9 +192,7 @@ async fn main() -> Result<(), Box<dyn Error>> {

let general_config = StarknetGeneralConfig {
starknet_os_config: StarknetOsConfig {
// TODO: the string given by provider is in decimal, the OS expects hex
// chain_id: starknet_api::core::ChainId(chain_id.clone()),
chain_id: starknet_api::core::ChainId("SN_SEPOLIA".to_string()),
chain_id,
fee_token_address: block_context.chain_info().fee_token_addresses.strk_fee_token_address,
deprecated_fee_token_address: block_context.chain_info().fee_token_addresses.eth_fee_token_address,
},
Expand Down Expand Up @@ -290,7 +291,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
.visited_pcs
.iter()
.map(|(class_hash, visited_pcs)| {
(felt_api2vm(class_hash.0), visited_pcs.iter().copied().map(Felt252::from).collect::<Vec<_>>())
(class_hash.0, visited_pcs.iter().copied().map(Felt252::from).collect::<Vec<_>>())
})
.collect();

Expand Down
24 changes: 18 additions & 6 deletions crates/bin/prove_block/src/rpc_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ use cairo_vm::Felt252;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde_json::json;
use starknet::core::types::BlockWithTxs;
use starknet_api::core::{ContractAddress, PatriciaKey};
use starknet_api::hash::StarkHash;
use starknet_api::{contract_address, patricia_key};
use starknet_api::{contract_address, felt, patricia_key};
use starknet_os::crypto::pedersen::PedersenHash;
use starknet_os::crypto::poseidon::PoseidonHash;
use starknet_os::starkware_utils::commitment_tree::base_types::{Length, NodePath};
use starknet_os::starkware_utils::commitment_tree::patricia_tree::nodes::{BinaryNodeFact, EdgeNodeFact};
use starknet_os::storage::dict_storage::DictStorage;
use starknet_os::storage::storage::{Fact, HashFunctionType};
use starknet_os::utils::{felt_api2vm, felt_vm2api};
use starknet_types_core::felt::Felt;

use crate::utils::get_all_accessed_keys;
Expand Down Expand Up @@ -137,7 +136,7 @@ pub(crate) async fn get_storage_proofs(
) -> Result<HashMap<Felt, PathfinderProof>, reqwest::Error> {
let accessed_keys_by_address = {
let mut keys = get_all_accessed_keys(tx_execution_infos);
keys.entry(contract_address!("0x1")).or_default().insert(felt_vm2api(old_block_number).try_into().unwrap());
keys.entry(contract_address!("0x1")).or_default().insert(old_block_number.try_into().unwrap());
keys
};

Expand All @@ -149,9 +148,9 @@ pub(crate) async fn get_storage_proofs(
}

for (contract_address, storage_keys) in accessed_keys_by_address {
let contract_address_felt = felt_api2vm(*contract_address.key());
let contract_address_felt = *contract_address.key();

let keys: Vec<_> = storage_keys.iter().map(|storage_key| felt_api2vm(*storage_key.key())).collect();
let keys: Vec<_> = storage_keys.iter().map(|storage_key| *storage_key.key()).collect();

let storage_proof = if keys.is_empty() {
pathfinder_get_proof(client, rpc_provider, block_number, contract_address_felt, &[]).await?
Expand Down Expand Up @@ -299,3 +298,16 @@ pub(crate) fn verify_proof<H: HashFunctionType>(key: Felt, commitment: Felt, pro

Ok(())
}

pub(crate) fn get_starknet_version(block_with_txs: &BlockWithTxs) -> blockifier::versioned_constants::StarknetVersion {
let starknet_version_str = &block_with_txs.starknet_version;
match starknet_version_str.as_ref() {
"0.13.0" => blockifier::versioned_constants::StarknetVersion::V0_13_0,
"0.13.1" => blockifier::versioned_constants::StarknetVersion::V0_13_1,
"0.13.1.1" => blockifier::versioned_constants::StarknetVersion::V0_13_1_1,
"0.13.2" => blockifier::versioned_constants::StarknetVersion::Latest,
other => {
unimplemented!("Unsupported Starknet version: {}", other)
}
}
}
50 changes: 17 additions & 33 deletions crates/bin/prove_block/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ use starknet::core::types::{
Transaction,
};
use starknet_os::io::InternalTransaction;
use starknet_types_core::felt::Felt;

// entry point for "__execute__"
const EXECUTE_ENTRY_POINT_FELT: Felt252 =
Felt252::from_hex_unchecked("0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad");

fn felt_to_vm(felt: Felt) -> Felt252 {
// Turns out that the types are the same between starknet-core and cairo-vm
felt
}

fn da_to_felt(data_availability_mode: DataAvailabilityMode) -> Felt252 {
match data_availability_mode {
DataAvailabilityMode::L1 => Felt252::ZERO,
Expand All @@ -26,62 +20,51 @@ fn da_to_felt(data_availability_mode: DataAvailabilityMode) -> Felt252 {
}

fn invoke_tx_v0_to_internal_tx(tx: InvokeTransactionV0) -> InternalTransaction {
let signature: Vec<_> = tx.signature.into_iter().map(felt_to_vm).collect();
let calldata: Vec<_> = tx.calldata.into_iter().map(felt_to_vm).collect();

InternalTransaction {
hash_value: felt_to_vm(tx.transaction_hash),
max_fee: Some(felt_to_vm(tx.max_fee)),
signature: Some(signature),
contract_address: Some(felt_to_vm(tx.contract_address)),
entry_point_selector: Some(felt_to_vm(tx.entry_point_selector)),
calldata: Some(calldata),
hash_value: tx.transaction_hash,
max_fee: Some(tx.max_fee),
signature: Some(tx.signature),
contract_address: Some(tx.contract_address),
entry_point_selector: Some(tx.entry_point_selector),
calldata: Some(tx.calldata),
version: Some(Felt252::ZERO),
..Default::default()
}
}
fn invoke_tx_v1_to_internal_tx(tx: InvokeTransactionV1) -> InternalTransaction {
let signature: Vec<_> = tx.signature.into_iter().map(felt_to_vm).collect();
let calldata: Vec<_> = tx.calldata.into_iter().map(felt_to_vm).collect();

InternalTransaction {
hash_value: felt_to_vm(tx.transaction_hash),
hash_value: tx.transaction_hash,
version: Some(Felt252::ONE),
contract_address: Some(tx.sender_address),
nonce: Some(tx.nonce),
sender_address: Some(tx.sender_address),
entry_point_selector: Some(EXECUTE_ENTRY_POINT_FELT),
entry_point_type: Some("EXTERNAL".to_string()),
signature: Some(signature),
calldata: Some(calldata),
signature: Some(tx.signature),
calldata: Some(tx.calldata),
r#type: "INVOKE_FUNCTION".to_string(),
max_fee: Some(tx.max_fee),
..Default::default()
}
}

fn invoke_tx_v3_to_internal_tx(tx: InvokeTransactionV3) -> InternalTransaction {
let signature: Vec<_> = tx.signature.into_iter().map(felt_to_vm).collect();
let calldata: Vec<_> = tx.calldata.into_iter().map(felt_to_vm).collect();
let paymaster_data: Vec<_> = tx.paymaster_data.into_iter().map(felt_to_vm).collect();
let account_deployment_data: Vec<_> = tx.account_deployment_data.into_iter().map(felt_to_vm).collect();

InternalTransaction {
hash_value: felt_to_vm(tx.transaction_hash),
sender_address: Some(felt_to_vm(tx.sender_address)),
signature: Some(signature),
nonce: Some(felt_to_vm(tx.nonce)),
hash_value: tx.transaction_hash,
sender_address: Some(tx.sender_address),
signature: Some(tx.signature),
nonce: Some(tx.nonce),
resource_bounds: Some(resource_bounds_core_to_api(&tx.resource_bounds)),
tip: Some(Felt252::from(tx.tip)),
paymaster_data: Some(paymaster_data),
account_deployment_data: Some(account_deployment_data),
paymaster_data: Some(tx.paymaster_data),
account_deployment_data: Some(tx.account_deployment_data),
nonce_data_availability_mode: Some(da_to_felt(tx.nonce_data_availability_mode)),
fee_data_availability_mode: Some(da_to_felt(tx.fee_data_availability_mode)),
version: Some(Felt252::TWO),
contract_address: Some(tx.sender_address),
entry_point_selector: Some(EXECUTE_ENTRY_POINT_FELT),
entry_point_type: Some("EXTERNAL".to_string()),
calldata: Some(calldata),
calldata: Some(tx.calldata),
..Default::default()
}
}
Expand Down Expand Up @@ -223,6 +206,7 @@ pub(crate) fn starknet_rs_tx_to_internal_tx(tx: Transaction) -> InternalTransact
#[cfg(test)]
mod tests {
use starknet::core::types::{ResourceBounds, ResourceBoundsMapping};
use starknet_types_core::felt::Felt;

use super::*;

Expand Down
4 changes: 1 addition & 3 deletions crates/bin/prove_block/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use cairo_vm::Felt252;
use starknet::core::types::{ExecuteInvocation, FunctionInvocation, TransactionTrace, TransactionTraceWithHash};
use starknet_api::core::ContractAddress;
use starknet_api::state::StorageKey;
use starknet_os::utils::felt_api2vm;

/// Receives the transaction traces of a given block
/// And extract the contracts addresses that where subcalled
Expand Down Expand Up @@ -96,8 +95,7 @@ fn get_accessed_storage_keys(call_info: &CallInfo) -> HashMap<ContractAddress, H
.or_default()
.extend(call_info.accessed_storage_keys.iter().copied());

let storage_keys: Vec<_> =
call_info.accessed_storage_keys.iter().map(|x| felt_api2vm(*x.key()).to_hex_string()).collect();
let storage_keys: Vec<_> = call_info.accessed_storage_keys.iter().map(|x| x.key().to_hex_string()).collect();
log::debug!("{}: {:?}", contract_address.to_string(), storage_keys);

for inner_call in &call_info.inner_calls {
Expand Down
21 changes: 13 additions & 8 deletions crates/rpc-replay/src/block_context.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use blockifier::block::{BlockInfo, GasPrices};
use blockifier::blockifier::block::{BlockInfo, GasPrices};
use blockifier::bouncer::BouncerConfig;
use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses};
use blockifier::versioned_constants::VersionedConstants;
use starknet::core::types::BlockWithTxs;
use starknet_api::block::{BlockNumber, BlockTimestamp};
use starknet_api::core::{ContractAddress, PatriciaKey};
use starknet_api::hash::StarkHash;
use starknet_api::{contract_address, patricia_key};
use starknet_api::core::{ChainId, ContractAddress, PatriciaKey};
use starknet_api::{contract_address, felt, patricia_key};

use crate::utils::felt_to_u128;

pub fn build_block_context(chain_id: String, block: &BlockWithTxs) -> BlockContext {
pub fn build_block_context(
chain_id: ChainId,
block: &BlockWithTxs,
starknet_version: blockifier::versioned_constants::StarknetVersion,
) -> BlockContext {
let sequencer_address_hex = block.sequencer_address.to_hex_string();
let sequencer_address = contract_address!(sequencer_address_hex.as_str());

Expand All @@ -27,7 +31,7 @@ pub fn build_block_context(chain_id: String, block: &BlockWithTxs) -> BlockConte
};

let chain_info = ChainInfo {
chain_id: starknet_api::core::ChainId(chain_id),
chain_id,
// cf. https://docs.starknet.io/tools/important-addresses/
fee_token_addresses: FeeTokenAddresses {
strk_fee_token_address: contract_address!(
Expand All @@ -39,7 +43,8 @@ pub fn build_block_context(chain_id: String, block: &BlockWithTxs) -> BlockConte
},
};

let versioned_constants = VersionedConstants::latest_constants();
let versioned_constants = VersionedConstants::get(starknet_version);
let bouncer_config = BouncerConfig::max();

BlockContext::new_unchecked(&block_info, &chain_info, versioned_constants)
BlockContext::new(block_info, chain_info, versioned_constants.clone(), bouncer_config)
}
Loading

0 comments on commit a051468

Please sign in to comment.