Skip to content

Commit 3a2ef85

Browse files
blockifier: test proof facts verifications (#11473)
1 parent be6d3db commit 3a2ef85

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

crates/blockifier/src/transaction/account_transactions_test.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use starknet_api::abi::abi_utils::{
1717
get_storage_var_address,
1818
selector_from_name,
1919
};
20-
use starknet_api::block::{FeeType, GasPrice};
20+
use starknet_api::block::{BlockHash, BlockNumber, FeeType, GasPrice};
2121
use starknet_api::contract_class::compiled_class_hash::{HashVersion, HashableCompiledClass};
2222
use starknet_api::contract_class::ContractClass;
2323
use starknet_api::core::{
@@ -41,6 +41,7 @@ use starknet_api::test_utils::deploy_account::executable_deploy_account_tx;
4141
use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs};
4242
use starknet_api::test_utils::{
4343
NonceManager,
44+
CURRENT_BLOCK_NUMBER,
4445
DEFAULT_L1_DATA_GAS_MAX_AMOUNT,
4546
DEFAULT_L1_GAS_AMOUNT,
4647
DEFAULT_L2_GAS_MAX_AMOUNT,
@@ -55,9 +56,12 @@ use starknet_api::transaction::fields::{
5556
ContractAddressSalt,
5657
Fee,
5758
GasVectorComputationMode,
59+
ProofFacts,
5860
Resource,
5961
ResourceBounds,
62+
SnosProofFacts,
6063
ValidResourceBounds,
64+
VIRTUAL_SNOS,
6165
};
6266
use starknet_api::transaction::{
6367
DeclareTransaction,
@@ -79,6 +83,7 @@ use starknet_api::{
7983
};
8084
use starknet_types_core::felt::Felt;
8185

86+
use crate::abi::constants::STORED_BLOCK_HASH_BUFFER;
8287
use crate::context::{BlockContext, TransactionContext};
8388
use crate::execution::call_info::CallInfo;
8489
use crate::execution::contract_class::TrackedResource;
@@ -2191,3 +2196,96 @@ fn test_missing_validate_entrypoint_rejects(
21912196
if ret == retdata![Felt::from_hex(ENTRYPOINT_NOT_FOUND_ERROR).unwrap()]
21922197
);
21932198
}
2199+
2200+
/// Converts SnosProofFacts to ProofFacts for testing.
2201+
fn snos_to_proof_facts(snos: SnosProofFacts) -> ProofFacts {
2202+
vec![
2203+
felt!(VIRTUAL_SNOS),
2204+
snos.program_hash,
2205+
felt!(snos.block_number.0),
2206+
snos.block_hash.0,
2207+
snos.config_hash,
2208+
]
2209+
.into()
2210+
}
2211+
2212+
/// Returns invalid proof_facts with a too recent block number (at the boundary).
2213+
fn proof_facts_with_too_recent_block() -> ProofFacts {
2214+
let mut snos_proof_facts =
2215+
SnosProofFacts::try_from(ProofFacts::snos_proof_facts_for_testing()).unwrap();
2216+
// Set the proof block number to the first invalid value:
2217+
// `current_block_number - STORED_BLOCK_HASH_BUFFER`
2218+
// (i.e. last allowed block + 1).
2219+
snos_proof_facts.block_number = BlockNumber(CURRENT_BLOCK_NUMBER - STORED_BLOCK_HASH_BUFFER);
2220+
snos_to_proof_facts(snos_proof_facts)
2221+
}
2222+
2223+
/// Returns invalid proof_facts with a mismatched block hash.
2224+
fn proof_facts_with_mismatched_hash() -> ProofFacts {
2225+
let mut snos_proof_facts =
2226+
SnosProofFacts::try_from(ProofFacts::snos_proof_facts_for_testing()).unwrap();
2227+
snos_proof_facts.block_hash = BlockHash(snos_proof_facts.block_hash.0 + 1);
2228+
snos_to_proof_facts(snos_proof_facts)
2229+
}
2230+
2231+
/// Returns invalid proof_facts with a zero block hash.
2232+
fn proof_facts_with_zero_block_hash() -> ProofFacts {
2233+
let mut snos_proof_facts = SnosProofFacts::try_from(ProofFacts::snos_proof_facts_for_testing())
2234+
.expect("Invalid proof facts");
2235+
snos_proof_facts.block_hash = BlockHash(Felt::ZERO);
2236+
snos_to_proof_facts(snos_proof_facts)
2237+
}
2238+
2239+
/// Returns invalid proof_facts with an invalid program hash.
2240+
fn proof_facts_with_invalid_program_hash() -> ProofFacts {
2241+
let mut snos_proof_facts = SnosProofFacts::try_from(ProofFacts::snos_proof_facts_for_testing())
2242+
.expect("Invalid proof facts");
2243+
snos_proof_facts.program_hash = Felt::from(0x12345678_u64);
2244+
snos_to_proof_facts(snos_proof_facts)
2245+
}
2246+
2247+
/// Tests the `validate_proof_facts` function for Invoke V3 transactions.
2248+
/// The test runs `perform_pre_validation_stage` and asserts that invalid cases
2249+
/// fail with `InvalidProofFacts`, while valid cases pass.
2250+
#[rstest]
2251+
#[case::valid(ProofFacts::snos_proof_facts_for_testing(), CURRENT_BLOCK_NUMBER, false)]
2252+
#[case::block_number_too_recent(proof_facts_with_too_recent_block(), CURRENT_BLOCK_NUMBER, true)]
2253+
#[case::current_block_number_too_small(
2254+
ProofFacts::snos_proof_facts_for_testing(),
2255+
STORED_BLOCK_HASH_BUFFER - 1,
2256+
true,
2257+
)]
2258+
#[case::block_hash_mismatched(proof_facts_with_mismatched_hash(), CURRENT_BLOCK_NUMBER, true)]
2259+
#[case::block_hash_zero(proof_facts_with_zero_block_hash(), CURRENT_BLOCK_NUMBER, true)]
2260+
#[case::program_hash_invalid(proof_facts_with_invalid_program_hash(), CURRENT_BLOCK_NUMBER, true)]
2261+
fn test_validate_proof_facts(
2262+
default_all_resource_bounds: ValidResourceBounds,
2263+
#[case] proof_facts: ProofFacts,
2264+
#[case] current_block_number: u64,
2265+
#[case] should_fail: bool,
2266+
) {
2267+
let mut block_context = BlockContext::create_for_account_testing();
2268+
block_context.block_info.block_number = BlockNumber(current_block_number);
2269+
2270+
let chain_info = &block_context.chain_info;
2271+
let account =
2272+
FeatureContract::AccountWithoutValidations(CairoVersion::Cairo1(RunnableCairo1::Casm));
2273+
let mut state = test_state(chain_info, BALANCE, &[(account, 1u16)]);
2274+
let account_address = account.get_instance_address(0_u16);
2275+
2276+
let tx = invoke_tx_with_default_flags(invoke_tx_args! {
2277+
sender_address: account_address,
2278+
resource_bounds: default_all_resource_bounds,
2279+
proof_facts,
2280+
});
2281+
2282+
// Run only pre-validation stage (which includes proof facts validation).
2283+
let tx_context = block_context.to_tx_context(&tx);
2284+
let result = tx.perform_pre_validation_stage(&mut state, &tx_context);
2285+
2286+
if should_fail {
2287+
assert_matches!(result, Err(TransactionPreValidationError::InvalidProofFacts(_)));
2288+
} else {
2289+
assert_matches!(result, Ok(()));
2290+
}
2291+
}

crates/starknet_api/src/transaction/fields.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,18 @@ impl From<Vec<Felt>> for ProofFacts {
702702
}
703703
}
704704

705+
impl TryFrom<ProofFacts> for SnosProofFacts {
706+
type Error = StarknetApiError;
707+
fn try_from(proof_facts: ProofFacts) -> Result<Self, Self::Error> {
708+
match ProofFactsVariant::try_from(&proof_facts) {
709+
Ok(ProofFactsVariant::Snos(snos_proof_facts)) => Ok(snos_proof_facts),
710+
_ => Err(StarknetApiError::InvalidProofFacts(format!(
711+
"Invalid SNOS proof facts: {proof_facts:?}",
712+
))),
713+
}
714+
}
715+
}
716+
705717
/// Client-provided proof used for client-side proving.
706718
#[derive(
707719
Clone,

0 commit comments

Comments
 (0)