Files
khadhroony-solana-project/crates/ksp-raw-transaction-lib/unit_tests/canonical.rs
2026-09-06 17:15:51 +02:00

248 lines
10 KiB
Rust

// file: crates/ksp-raw-transaction-lib/unit_tests/canonical.rs
// version: 2
fn network() -> std::option::Option<ksp_store_api::RawNetworkId> {
return match ksp_store_api::RawNetworkId::new("devnet") {
std::result::Result::Ok(value) => std::option::Option::Some(value),
std::result::Result::Err(_) => std::option::Option::None,
};
}
fn signature() -> std::option::Option<ksp_store_api::RawTransactionSignature> {
let result = crate::parse_raw_transaction_signature("1".repeat(64).as_str());
return match result {
std::result::Result::Ok(value) => std::option::Option::Some(value),
std::result::Result::Err(_) => std::option::Option::None,
};
}
fn material(
block_time: std::option::Option<i64>,
transaction_data: std::string::String,
meta: crate::RawTransactionWireField<serde_json::Value>,
version: crate::RawTransactionWireField<crate::RawTransactionVersion>,
transaction_index: crate::RawTransactionWireField<u32>,
) -> std::option::Option<crate::RawTransactionMaterial> {
let network = match network() {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let signature = match signature() {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
return std::option::Option::Some(crate::RawTransactionMaterial::binary_base64(
network,
signature,
123,
block_time,
transaction_data,
meta,
version,
transaction_index,
));
}
#[test]
fn pre_002_canonical_raw_v1_golden_bytes_and_hash_are_exact() {
let material = match material(
std::option::Option::Some(1_700_000_000),
"AQID".to_owned(),
crate::RawTransactionWireField::Value(serde_json::json!({"z": 1, "a": {"y": true, "x": null}})),
crate::RawTransactionWireField::Value(crate::RawTransactionVersion::Legacy),
crate::RawTransactionWireField::Value(7_u32),
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let transaction = crate::canonicalize_raw_transaction(material);
assert!(transaction.is_ok());
let transaction = match transaction {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let expected = b"{\"transaction\":[\"AQID\",\"base64\"],\"meta\":{\"a\":{\"x\":null,\"y\":true},\"z\":1},\"version\":\"legacy\",\"transactionIndex\":7}";
assert_eq!(transaction.payload().bytes(), expected);
assert_eq!(transaction.payload().byte_len(), 112);
assert_eq!(transaction.payload().format_id().as_str(), crate::RAW_TRANSACTION_FORMAT_ID);
assert_eq!(transaction.payload().format_version(), crate::RAW_TRANSACTION_FORMAT_VERSION);
assert_eq!(
transaction.payload().content_hash().as_bytes(),
&[
34, 7, 146, 210, 177, 93, 38, 47, 218, 36, 44, 178, 32, 119, 78, 233, 221, 239, 254, 191, 4, 220, 250, 218, 188, 248, 239, 118, 169, 177, 167, 195
]
);
assert_eq!(transaction.slot(), 123);
assert_eq!(transaction.block_time().map(|value| return value.unix_millis()), std::option::Option::Some(1_700_000_000_000));
assert_eq!(transaction.reference().network().as_str(), "devnet");
assert_eq!(transaction.reference().signature().as_bytes(), &[0_u8; 64]);
return;
}
#[test]
fn pre_002_wire_omitted_null_and_value_states_remain_distinct() {
let omitted = match material(
std::option::Option::None,
"AQID".to_owned(),
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let omitted = super::canonical_payload_bytes(&omitted);
assert!(omitted.is_ok());
if let std::result::Result::Ok(omitted) = omitted {
assert_eq!(omitted, b"{\"transaction\":[\"AQID\",\"base64\"]}");
}
let nulls = match material(
std::option::Option::None,
"AQID".to_owned(),
crate::RawTransactionWireField::Null,
crate::RawTransactionWireField::Null,
crate::RawTransactionWireField::Null,
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let nulls = super::canonical_payload_bytes(&nulls);
assert!(nulls.is_ok());
if let std::result::Result::Ok(nulls) = nulls {
assert_eq!(nulls, b"{\"transaction\":[\"AQID\",\"base64\"],\"meta\":null,\"version\":null,\"transactionIndex\":null}");
}
return;
}
#[test]
fn pre_002_canonical_json_sorts_objects_preserves_arrays_and_escapes_strings() {
let meta = serde_json::json!({
"z": [3, 2, 1],
"quote": "a\"b\\c\n",
"a": {"n": -12.5, "b": false, "a": true}
});
let material = match material(
std::option::Option::None,
"A\"B".to_owned(),
crate::RawTransactionWireField::Value(meta),
crate::RawTransactionWireField::Value(crate::RawTransactionVersion::Number(0)),
crate::RawTransactionWireField::Value(u32::MAX),
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let bytes = super::canonical_payload_bytes(&material);
assert!(bytes.is_ok());
if let std::result::Result::Ok(bytes) = bytes {
let expected = b"{\"transaction\":[\"A\\\"B\",\"base64\"],\"meta\":{\"a\":{\"a\":true,\"b\":false,\"n\":-12.5},\"quote\":\"a\\\"b\\\\c\\n\",\"z\":[3,2,1]},\"version\":0,\"transactionIndex\":4294967295}";
assert_eq!(bytes, expected);
}
return;
}
#[test]
fn pre_002_block_time_rejects_negative_overflow_and_store_maximum_overrun() {
for block_time in [-1_i64, i64::MAX, 253_402_300_800_i64] {
let material = match material(
std::option::Option::Some(block_time),
"AQID".to_owned(),
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let result = crate::canonicalize_raw_transaction(material);
assert!(result.is_err());
if let std::result::Result::Err(error) = result {
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_MATERIAL_INVALID);
}
}
let maximum = match material(
std::option::Option::Some(253_402_300_799_i64),
"AQID".to_owned(),
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let maximum = crate::canonicalize_raw_transaction(maximum);
assert!(maximum.is_ok());
if let std::result::Result::Ok(maximum) = maximum {
assert_eq!(maximum.block_time().map(|value| return value.unix_millis()), std::option::Option::Some(253_402_300_799_000));
}
return;
}
#[test]
fn pre_002_payload_bound_is_enforced_by_common_before_store_construction() {
let material = match material(
std::option::Option::None,
"A".repeat(ksp_store_api::MAX_RAW_PAYLOAD_BYTES),
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
crate::RawTransactionWireField::Omitted,
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let result = crate::canonicalize_raw_transaction(material);
assert!(result.is_err());
if let std::result::Result::Err(error) = result {
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_CANONICALIZATION_INVALID);
}
return;
}
#[test]
fn pre_002_material_and_wire_debug_do_not_render_transaction_or_meta_material() {
let secret_transaction = "SECRET_TRANSACTION_BODY";
let secret_meta = "SECRET_META_VALUE";
let material = match material(
std::option::Option::None,
secret_transaction.to_owned(),
crate::RawTransactionWireField::Value(serde_json::json!({"secret": secret_meta})),
crate::RawTransactionWireField::Value(crate::RawTransactionVersion::Legacy),
crate::RawTransactionWireField::Value(1_u32),
) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let debug = std::format!("{material:?}");
assert!(!debug.contains(secret_transaction));
assert!(!debug.contains(secret_meta));
assert_eq!(std::format!("{:?}", crate::RawTransactionWireField::Value(secret_meta)), "Value(..)");
return;
}
#[test]
fn pre_004_embedded_signature_material_preserves_block_fields_and_canonicalizes() {
let network = match ksp_store_api::RawNetworkId::new("devnet") {
std::result::Result::Ok(network) => network,
std::result::Result::Err(_) => return,
};
let material = crate::RawTransactionMaterial::binary_base64_with_embedded_signature(
network,
430_000_123,
std::option::Option::Some(1_787_072_400),
"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
crate::RawTransactionWireField::Value(serde_json::json!({"err":null,"fee":5000})),
crate::RawTransactionWireField::Value(crate::RawTransactionVersion::Legacy),
crate::RawTransactionWireField::Value(0_u32),
);
assert!(material.is_ok());
let transaction = match material.and_then(crate::canonicalize_raw_transaction) {
std::result::Result::Ok(transaction) => transaction,
std::result::Result::Err(_) => return,
};
assert_eq!(transaction.reference().signature().as_bytes(), &[0_u8; 64]);
assert_eq!(transaction.slot(), 430_000_123);
assert_eq!(transaction.block_time().map(|value| return value.unix_millis()), std::option::Option::Some(1_787_072_400_000));
assert!(transaction.payload().bytes().starts_with(b"{\"transaction\":[\"AQAAAA"));
assert!(transaction.payload().bytes().ends_with(b"\"version\":\"legacy\",\"transactionIndex\":0}"));
return;
}