Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .github/workflows/starknet_transaction_prover_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ on:
- ".github/workflows/starknet_transaction_prover_ci.yml"
- "Cargo.lock"
- "Cargo.toml"
- "crates/apollo_starknet_os_program/**"
- "crates/blockifier/**"
- "crates/blockifier_reexecution/**"
- "crates/blockifier_test_utils/**"
- "crates/proving_utils/**"
- "crates/starknet_committer/**"
- "crates/starknet_os/**"
- "crates/starknet_os_flow_tests/**"
- "crates/starknet_patricia/**"
- "crates/starknet_transaction_prover/**"
- "scripts/build_starknet_transaction_prover.sh"
Expand Down Expand Up @@ -110,6 +113,10 @@ jobs:
working-directory: crates/starknet_transaction_prover
run: cargo test --release -p starknet_transaction_prover --features stwo_proving virtual_snos_prover_test -- --ignored --test-threads=1

- name: Run virtual OS multicall proving test
working-directory: crates/starknet_transaction_prover
run: cargo test --release -p starknet_os_flow_tests --features starknet_transaction_prover/stwo_proving prove_and_verify_multicall_tx -- --ignored --test-threads=1
Comment thread
cursor[bot] marked this conversation as resolved.

# Test that the starknet_transaction_prover Docker image builds successfully.
docker-build:
runs-on: namespace-profile-medium-ubuntu-24-04-amd64
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions crates/blockifier/src/bouncer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,11 +804,11 @@ fn class_hash_migration_data_from_state(

if should_migrate {
expect![[r#"
108608775
110756293
"#]]
.assert_debug_eq(&migration_sierra_gas.0);
expect![[r#"
266780662
272117746
"#]]
.assert_debug_eq(&migration_proving_gas.0);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Transaction execution has failed:
0: Error in the called contract (contract address: 0x00000000000000000000000000000000000000000000000000000000c0020000, class hash: 0x0000000000000000000000000000000000000000000000000000000080020000, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):
Error at pc=0:539:
1: Error in the called contract (contract address: 0x00000000000000000000000000000000000000000000000000000000c0020000, class hash: 0x0000000000000000000000000000000000000000000000000000000080020000, selector: 0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8):
Error at pc=0:781:
Error at pc=0:950:
2: Error in the contract class constructor (contract address: 0x0103ee82605273496eed8d9141c5b3ad967baa08be63aa5bc49ffae5eae454cc, class hash: 0x0000000000000000000000000000000000000000000000000000000080040000, selector: 0x028ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194):
Execution failed. Failure reason:
Error in contract (contract address: 0x0103ee82605273496eed8d9141c5b3ad967baa08be63aa5bc49ffae5eae454cc, class hash: 0x0000000000000000000000000000000000000000000000000000000080040000, selector: 0x028ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[starknet::contract(account)]
mod Account {
use array::{ArrayTrait, SpanTrait};
use starknet::account::Call;
use starknet::{ClassHash, ContractAddress, call_contract_syscall};
use starknet::info::SyscallResultTrait;
use starknet::syscalls;
Expand Down Expand Up @@ -34,6 +35,9 @@ mod Account {
starknet::VALIDATED
}

// TODO(Yoni): replace this single-call `__execute__` with the multicall-shaped
// `multi_call` below, so this account can execute INVOKE transactions whose
// calldata is `Array<Call>` natively (matching the standard account ABI).
#[external(v0)]
#[raw_output]
fn __execute__(
Expand All @@ -52,6 +56,32 @@ mod Account {
).unwrap_syscall()
}

/// Executes a sequence of calls and returns their concatenated return values.
/// The intended invocation in tests is via `__execute__`, with `__execute__`
/// forwarding `(self_address, "multi_call", serialized calls)` to this entry point.
#[external(v0)]
fn multi_call(
self: @ContractState, mut calls: Array<Call>
) -> Array<Span<felt252>> {
let mut result = ArrayTrait::new();
loop {
match calls.pop_front() {
Option::Some(call) => {
let res = call_contract_syscall(
address: call.to,
entry_point_selector: call.selector,
calldata: call.calldata,
).unwrap_syscall();
result.append(res);
},
Option::None => {
break;
},
};
};
result
}

#[external(v0)]
fn deploy_contract(
self: @ContractState,
Expand Down
1 change: 1 addition & 0 deletions crates/starknet_os_flow_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ starknet_committer = { workspace = true, features = ["testing"] }
starknet_os = { workspace = true, features = ["include_program_output", "testing"] }
starknet_patricia = { workspace = true, features = ["testing"] }
starknet_patricia_storage = { workspace = true, features = ["testing"] }
starknet_proof_verifier.workspace = true
starknet_transaction_prover.workspace = true
strum.workspace = true
tokio.workspace = true
Expand Down
10 changes: 5 additions & 5 deletions crates/starknet_os_flow_tests/src/fuzz_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ static IS_CAIRO1: LazyLock<BTreeMap<ClassHash, bool>> = LazyLock::new(|| {

/// Initial fuzz contract addresses.
static FUZZ_ADDRESS_ORCHESTRATOR_EXPECT: Expect =
expect!["0x4c885880af2af2afc2b57ed77bd4dfacd8da1768c0de60a14d854d6aa681678"];
expect!["0x727742e0b8d4b0ba3e4d1bac6cea5e523cfde238c694ddf78006f113ae1f7d6"];
static FUZZ_ADDRESS_CAIRO1_A_EXPECT: Expect =
expect!["0x3b22209e355bb17880121aad4621a7658a2daea2c0c7dd5159595c93ddfac67"];
expect!["0x1ee6d084c36adff47c27ffaac99ae535ca9608067508fa722ceeedefbc82460"];
static FUZZ_ADDRESS_CAIRO1_B_EXPECT: Expect =
expect!["0x2c1ef35cf09a851d642b1b21141e19a49aacce41a65eeeb46decd24fc55da54"];
expect!["0x48a60831f25e99646cdf88a1de37140e2809bfb99f5791e504707ab899d86cb"];
static FUZZ_ADDRESS_CAIRO0_A_EXPECT: Expect =
expect!["0x209b4338889acf7e7c4a0654b51e51bc874df786a12d77e95a2362711cfac6c"];
expect!["0x515caf6295458c854d5a577786d6cdd615bed0c02432e09822546c9f408fda1"];
static FUZZ_ADDRESS_CAIRO0_B_EXPECT: Expect =
expect!["0x437a3c2706d0fe102ddccafa7169b616c8f4b4124f0761edc08e9283592caf0"];
expect!["0x682ede4f50d9b42fe07911e67993682449ed63a69ba1f8c69764ff1d22e5e5d"];
static FUZZ_ADDRESS_ORCHESTRATOR: LazyLock<ContractAddress> = LazyLock::new(|| {
ContractAddress::try_from(felt!(FUZZ_ADDRESS_ORCHESTRATOR_EXPECT.data())).unwrap()
});
Expand Down
2 changes: 1 addition & 1 deletion crates/starknet_os_flow_tests/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,7 @@ async fn test_experimental_libfuncs_contract(#[values(true, false)] use_kzg_da:
.copied()
.unwrap_or(0);
expect![[r#"
564
569
"#]]
.assert_debug_eq(&blakes);

Expand Down
40 changes: 40 additions & 0 deletions crates/starknet_os_flow_tests/src/virtual_os_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,46 @@ async fn test_reverted_tx_os_error() {
.run_virtual_expect_error("Reverted transactions are not supported in virtual OS mode");
}

/// Proves and verifies a virtual OS run of a single transaction that performs a
/// multicall through the account contract. The inner calls can be extended over
/// time to grow syscall/builtin coverage.
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn prove_and_verify_multicall_tx() {
let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1(RunnableCairo1::Casm));

let (mut test_builder, [contract_address]) =
TestBuilder::create_standard_virtual([(test_contract, calldata![Felt::ONE, Felt::TWO])])
.await;

// Appends a single `Call` entry to `multi_call_args` as
// `[to, selector, calldata_len, *calldata]` and bumps the leading `num_calls`
// counter. All inner calls in this test target the same test contract.
let mut multi_call_args: Vec<Felt> = vec![Felt::ZERO];
let mut serialize_call = |func_name: &str, args: &[Felt]| {
multi_call_args[0] += Felt::ONE;
multi_call_args.push(*contract_address.0.key());
multi_call_args.push(selector_from_name(func_name).0);
multi_call_args.push(Felt::from(args.len()));
multi_call_args.extend_from_slice(args);
};

// TODO(Yoni): add more inner calls (e.g. sha256, secp256k1, send_message_to_l1).
// TODO(Yoni): restore the keccak inner call once the keccak syscall is allowed in
// virtual OS mode (added in a follow-up PR stacked on top of this one).
// serialize_call("test_keccak", &[]);
serialize_call("test_ec_op", &[]);

// The dummy account's `__execute__(contract_address, selector, calldata)` forwards
// to its own `multi_call` entry point.
let calldata = create_calldata(*FUNDED_ACCOUNT_ADDRESS, "multi_call", &multi_call_args);
test_builder.add_funded_account_invoke(invoke_tx_args! { calldata });

let output = test_builder.build().await.run_virtual().prove().await;
starknet_proof_verifier::verify_proof(output.proof_facts, output.proof)
.expect("proof verification should succeed");
Comment thread
Yoni-Starkware marked this conversation as resolved.
}

/// Generates proof fixtures for the proof-flow integration test.
/// To run manually: `cargo +nightly-2025-07-14 test -p starknet_os_flow_tests --features
/// starknet_transaction_prover/stwo_proving --release generate_proof_fixtures -- --ignored`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,44 +44,6 @@ use crate::test_utils::{
STRK_TOKEN_ADDRESS_SEPOLIA,
};

/// Integration test for the full prover pipeline with a `balanceOf` transaction.
/// Runs on a Sepolia environment; in live/recording mode requires a Sepolia RPC node via
/// `NODE_URL`.
#[rstest]
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn test_prove_balance_of_transaction() {
let test_mode = resolve_test_mode("test_prove_balance_of_transaction").await;

// Creates an RPC invoke transaction that calls `balanceOf` on the STRK token.
let strk_token = ContractAddress::try_from(STRK_TOKEN_ADDRESS_SEPOLIA).unwrap();
let account = ContractAddress::try_from(DUMMY_ACCOUNT_ADDRESS).unwrap();

// Calldata matches dummy account's __execute__(contract_address, selector, calldata).
let calldata = create_calldata(strk_token, "balanceOf", &[account.into()]);
let rpc_tx = build_client_side_rpc_invoke(account, calldata);

let factory = runner_factory(&test_mode.rpc_url());
let prover = VirtualSnosProver::from_runner(factory);

// Run the full prover pipeline: OS execution → proof generation.
let result = prover.prove_transaction(BlockId::Latest, rpc_tx).await;

// Finalize recording before asserting so records are saved even on failure.
test_mode.finalize();

// Verify execution and proving succeeded.
let output = result.expect("prove_transaction should succeed");

// Verify the proof against the proof facts.
let proof_facts = output.proof_facts.clone();
let proof = output.proof.clone();
tokio::task::spawn_blocking(move || verify_proof(proof_facts, proof))
.await
.expect("proof verification task panicked")
.expect("proof verification should succeed");
}

/// Integration test for the full prover pipeline with a STRK `transfer` transaction.
/// Runs on a Sepolia environment; in live/recording mode requires a Sepolia RPC node via
/// `NODE_URL`.
Expand Down
Loading