mirror of
https://github.com/logos-blockchain/lez-fuzzing.git
synced 2026-06-07 03:29:26 +00:00
fix: targets and props
This commit is contained in:
parent
9c7409fbe7
commit
f411509eb2
@ -18,12 +18,10 @@ fuzz_target!(|data: &[u8]| {
|
||||
let recomputed2 = hashable.block_hash();
|
||||
assert_eq!(recomputed, recomputed2, "block_hash() is not deterministic");
|
||||
|
||||
// Log divergence between stored and recomputed hash for coverage guidance.
|
||||
// We do NOT assert equality because adversarially-crafted fuzz inputs can
|
||||
// store an arbitrary hash field without matching the body content.
|
||||
let stored_hash = block.header.hash;
|
||||
if stored_hash == recomputed {
|
||||
// Hashes match — this is the expected case for a valid sequencer-produced block
|
||||
let _ = stored_hash;
|
||||
}
|
||||
// We intentionally do NOT assert that the stored header hash equals the
|
||||
// recomputed one: adversarially-crafted fuzz inputs can store an arbitrary
|
||||
// hash field that does not match the body content, and that is a valid input
|
||||
// for the purpose of this target (which only tests hash stability, not
|
||||
// block validity).
|
||||
let _ = (block.header.hash, recomputed);
|
||||
});
|
||||
|
||||
@ -21,7 +21,7 @@ fuzz_target!(|data: &[u8]| {
|
||||
|
||||
// Generate up to 8 transactions and apply them
|
||||
let n_txs: u8 = u8::arbitrary(&mut u).unwrap_or(0) % 8;
|
||||
for _ in 0..n_txs {
|
||||
for i in 0..n_txs {
|
||||
let Ok(tx) = arbitrary_transaction(&mut u) else {
|
||||
break;
|
||||
};
|
||||
@ -34,8 +34,12 @@ fuzz_target!(|data: &[u8]| {
|
||||
// Clone state before to detect state leakage on failure
|
||||
let state_snapshot = state.clone();
|
||||
|
||||
let block_id: u64 = 1;
|
||||
let timestamp: u64 = 0;
|
||||
// Advance block_id and timestamp each iteration so the state machine
|
||||
// sees a realistic monotonically-increasing context. Using the same
|
||||
// block_id=1 / timestamp=0 for every tx hides bugs that only manifest
|
||||
// when the block context changes across a multi-transaction sequence.
|
||||
let block_id: u64 = 1 + u64::from(i);
|
||||
let timestamp: u64 = u64::from(i);
|
||||
let result = tx.execute_check_on_state(&mut state, block_id, timestamp);
|
||||
|
||||
if result.is_err() {
|
||||
|
||||
@ -13,7 +13,7 @@ fuzz_target!(|data: &[u8]| {
|
||||
let tx2 = borsh::from_slice::<NSSATransaction>(&re_encoded)
|
||||
.expect("second decode of re-encoded tx must succeed");
|
||||
assert_eq!(
|
||||
borsh::to_vec(&tx).unwrap(),
|
||||
re_encoded,
|
||||
borsh::to_vec(&tx2).unwrap(),
|
||||
"NSSATransaction roundtrip encoding divergence"
|
||||
);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use common::{block::HashableBlockData, transaction::NSSATransaction};
|
||||
use nssa::{AccountId, PrivateKey};
|
||||
|
||||
use crate::arbitrary_types::ArbNSSATransaction;
|
||||
use proptest::prelude::*;
|
||||
use testnet_initial_state::initial_pub_accounts_private_keys;
|
||||
|
||||
@ -9,26 +11,15 @@ use testnet_initial_state::initial_pub_accounts_private_keys;
|
||||
/// A best-effort attempt to create a structurally plausible `NSSATransaction`
|
||||
/// from unstructured bytes. Falls back to raw borsh decoding.
|
||||
pub fn arbitrary_transaction(u: &mut Unstructured<'_>) -> arbitrary::Result<NSSATransaction> {
|
||||
// Prefer structured generation; raw decode as fallback
|
||||
// Prefer structured generation (via Arbitrary impls); raw borsh decode as fallback.
|
||||
if bool::arbitrary(u)? {
|
||||
let raw = Vec::<u8>::arbitrary(u)?;
|
||||
borsh::from_slice::<NSSATransaction>(&raw).map_err(|_| arbitrary::Error::IncorrectFormat)
|
||||
} else {
|
||||
// Generate a minimal empty public tx using known test keys
|
||||
let signing_key = PrivateKey::try_new([u8::arbitrary(u)?; 32])
|
||||
.map_err(|_| arbitrary::Error::IncorrectFormat)?;
|
||||
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
vec![],
|
||||
vec![],
|
||||
u128::arbitrary(u)?,
|
||||
)
|
||||
.map_err(|_| arbitrary::Error::IncorrectFormat)?;
|
||||
let witness = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
|
||||
Ok(NSSATransaction::Public(nssa::PublicTransaction::new(
|
||||
message, witness,
|
||||
)))
|
||||
// Use the full ArbNSSATransaction generator, which produces both Public and
|
||||
// ProgramDeployment variants with realistic account IDs, nonces, and witness sets —
|
||||
// far richer than the previous degenerate single-byte key / empty-message path.
|
||||
ArbNSSATransaction::arbitrary(u).map(|w| w.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,11 +44,18 @@ impl ProtocolInvariant for StateIsolationOnFailure {
|
||||
|
||||
fn check(&self, ctx: &InvariantCtx<'_>) -> Option<InvariantViolation> {
|
||||
if ctx.result.is_err() {
|
||||
// Capture snapshot totals for comparison
|
||||
let _before_total = ctx.balances_before.total();
|
||||
let _state_after = ctx.state_after;
|
||||
// TODO: implement actual balance extraction from V03State once API is confirmed
|
||||
// (use state_after.get_account_by_id per known account and compare with before)
|
||||
for (acc_id, &expected_balance) in &ctx.balances_before.0 {
|
||||
let actual_balance = ctx.state_after.get_account_by_id(*acc_id).balance;
|
||||
if actual_balance != expected_balance {
|
||||
return Some(InvariantViolation {
|
||||
invariant: self.name(),
|
||||
message: format!(
|
||||
"balance changed despite tx rejection: account {:?} had {expected_balance} before, {actual_balance} after",
|
||||
acc_id,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user