v0.3.4-pre.007
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-postgres-lib/unit_tests/raw_account.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
fn network() -> ksp_store_api::RawNetworkId {
|
||||
return match ksp_store_api::RawNetworkId::new("devnet") {
|
||||
@@ -8,6 +8,28 @@ fn network() -> ksp_store_api::RawNetworkId {
|
||||
};
|
||||
}
|
||||
|
||||
fn page_query(
|
||||
network_name: &str,
|
||||
pubkey: std::option::Option<ksp_store_api::Pubkey>,
|
||||
start: std::option::Option<u64>,
|
||||
end: std::option::Option<u64>,
|
||||
direction: ksp_store_api::RawSortDirection,
|
||||
) -> ksp_store_api::RawAccountStateQuery {
|
||||
let network = match ksp_store_api::RawNetworkId::new(network_name) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid test network rejected: {error:?}"),
|
||||
};
|
||||
let slots = match ksp_store_api::RawSlotRange::new(start, end) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid slot range rejected: {error:?}"),
|
||||
};
|
||||
let limit = match ksp_store_api::RawPageLimit::new(2) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid page limit rejected: {error:?}"),
|
||||
};
|
||||
return ksp_store_api::RawAccountStateQuery::new(network, pubkey, slots, direction, ksp_store_api::RawPageRequest::first(limit));
|
||||
}
|
||||
|
||||
fn state_row() -> super::RawAccountStateDbRow {
|
||||
return super::RawAccountStateDbRow {
|
||||
data: vec![1, 2, 3, 4],
|
||||
@@ -376,3 +398,128 @@ fn pre_006_additional_observation_race_and_cancellation_contract_is_transaction_
|
||||
assert!(!function.contains("ON CONFLICT DO UPDATE"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_account_cursor_v1_round_trip_is_fixed_109_bytes_and_exact() {
|
||||
let pubkey = ksp_store_api::Pubkey::new_from_array([7_u8; 32]);
|
||||
let query = page_query(
|
||||
"devnet",
|
||||
std::option::Option::Some(pubkey.clone()),
|
||||
std::option::Option::Some(10),
|
||||
std::option::Option::Some(20),
|
||||
ksp_store_api::RawSortDirection::Ascending,
|
||||
);
|
||||
let state_hash = ksp_store_api::RawContentHash::new([9_u8; 32]);
|
||||
let cursor = match crate::encode_raw_account_cursor(&query, 15, &pubkey, &state_hash) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid account cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
assert_eq!(cursor.as_bytes().len(), 109);
|
||||
assert_eq!(cursor.as_bytes().get(0..4), std::option::Option::Some(b"KSPA".as_ref()));
|
||||
assert_eq!(cursor.as_bytes().get(4).copied(), std::option::Option::Some(1));
|
||||
let decoded = match crate::decode_raw_account_cursor(&query, &cursor) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid account cursor decoding rejected: {error:?}"),
|
||||
};
|
||||
assert_eq!(decoded.last_slot, 15);
|
||||
assert_eq!(decoded.last_pubkey, [7_u8; 32]);
|
||||
assert_eq!(decoded.last_state_hash, [9_u8; 32]);
|
||||
assert_eq!(std::format!("{cursor:?}"), "RawPageCursor { len: 109 }");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_account_cursor_rejects_replay_across_query_context_and_transaction_family() {
|
||||
let pubkey = ksp_store_api::Pubkey::new_from_array([4_u8; 32]);
|
||||
let query = page_query(
|
||||
"devnet",
|
||||
std::option::Option::Some(pubkey.clone()),
|
||||
std::option::Option::Some(10),
|
||||
std::option::Option::Some(20),
|
||||
ksp_store_api::RawSortDirection::Ascending,
|
||||
);
|
||||
let state_hash = ksp_store_api::RawContentHash::new([5_u8; 32]);
|
||||
let cursor = match crate::encode_raw_account_cursor(&query, 15, &pubkey, &state_hash) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid account cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
let other_network = page_query("mainnet-beta", Some(pubkey.clone()), Some(10), Some(20), ksp_store_api::RawSortDirection::Ascending);
|
||||
let other_pubkey =
|
||||
page_query("devnet", Some(ksp_store_api::Pubkey::new_from_array([6_u8; 32])), Some(10), Some(20), ksp_store_api::RawSortDirection::Ascending);
|
||||
let other_direction = page_query("devnet", Some(pubkey.clone()), Some(10), Some(20), ksp_store_api::RawSortDirection::Descending);
|
||||
let other_range = page_query("devnet", Some(pubkey.clone()), Some(11), Some(20), ksp_store_api::RawSortDirection::Ascending);
|
||||
for candidate in [&other_network, &other_pubkey, &other_direction, &other_range] {
|
||||
let error = crate::decode_raw_account_cursor(candidate, &cursor).err();
|
||||
assert_eq!(error.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::QueryInvalid));
|
||||
}
|
||||
let transaction_query = match ksp_store_api::RawSlotRange::new(Some(10), Some(20)) {
|
||||
std::result::Result::Ok(slots) => {
|
||||
let limit = match ksp_store_api::RawPageLimit::new(2) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid transaction page limit rejected: {error:?}"),
|
||||
};
|
||||
ksp_store_api::RawTransactionQuery::new(network(), slots, ksp_store_api::RawSortDirection::Ascending, ksp_store_api::RawPageRequest::first(limit))
|
||||
},
|
||||
std::result::Result::Err(error) => panic!("valid transaction slot range rejected: {error:?}"),
|
||||
};
|
||||
let signature = ksp_store_api::RawTransactionSignature::new([8_u8; 64]);
|
||||
let transaction_cursor = match crate::encode_raw_transaction_cursor(&transaction_query, 15, &signature) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid transaction cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
let error = crate::decode_raw_account_cursor(&query, &transaction_cursor).err();
|
||||
assert_eq!(error.map(|value| return value.phase()), Some("raw_account_cursor_magic"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_account_cursor_hostile_size_magic_version_and_digest_are_rejected() {
|
||||
let query = page_query("devnet", None, None, None, ksp_store_api::RawSortDirection::Ascending);
|
||||
for size in [1_usize, 108, 109, 110, 4_096] {
|
||||
let raw = match ksp_store_api::RawPageCursor::try_new(vec![0_u8; size].into_boxed_slice()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("bounded hostile cursor rejected by API before backend test: {error:?}"),
|
||||
};
|
||||
assert!(crate::decode_raw_account_cursor(&query, &raw).is_err());
|
||||
}
|
||||
let pubkey = ksp_store_api::Pubkey::new_from_array([3_u8; 32]);
|
||||
let state_hash = ksp_store_api::RawContentHash::new([2_u8; 32]);
|
||||
let valid = match crate::encode_raw_account_cursor(&query, 42, &pubkey, &state_hash) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid account cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
for index in [0_usize, 4, 108] {
|
||||
let mut bytes = valid.as_bytes().to_vec();
|
||||
bytes[index] ^= 0xff;
|
||||
let hostile = match ksp_store_api::RawPageCursor::try_new(bytes.into_boxed_slice()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("fixed-size hostile cursor rejected by API before backend test: {error:?}"),
|
||||
};
|
||||
let error = crate::decode_raw_account_cursor(&query, &hostile).err();
|
||||
assert_eq!(error.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::QueryInvalid));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_account_page_limit_exposes_only_the_real_postgres_limit_plus_one_boundary() {
|
||||
let maximum = crate::raw_account_physical_page_limit(9_223_372_036_854_775_806);
|
||||
assert_eq!(maximum, Ok((9_223_372_036_854_775_806_usize, i64::MAX)));
|
||||
let rejected = crate::raw_account_physical_page_limit(9_223_372_036_854_775_807).err();
|
||||
assert_eq!(rejected.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::PageLimitUnsupported));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_007_account_list_row_decodes_full_reference_without_integer_narrowing() {
|
||||
let row = super::RawAccountListDbRow { pubkey: vec![1_u8; 32], slot_text: u64::MAX.to_string(), state_hash: vec![2_u8; 32] };
|
||||
let decoded = match super::decode_raw_account_list_row(&network(), row) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid account list row rejected: {error:?}"),
|
||||
};
|
||||
assert_eq!(decoded.0, u64::MAX);
|
||||
assert_eq!(decoded.1.pubkey(), &ksp_store_api::Pubkey::new_from_array([1_u8; 32]));
|
||||
assert_eq!(decoded.1.slot(), u64::MAX);
|
||||
assert_eq!(decoded.1.state_hash(), ksp_store_api::RawContentHash::new([2_u8; 32]));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user