v0.3.10-pre.002
This commit is contained in:
73
crates/ksp-raw-transaction-lib/unit_tests/acquisition.rs
Normal file
73
crates/ksp-raw-transaction-lib/unit_tests/acquisition.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
// file: crates/ksp-raw-transaction-lib/unit_tests/acquisition.rs
|
||||
// version: 1
|
||||
|
||||
fn canonical_transaction() -> std::option::Option<ksp_store_api::RawTransaction> {
|
||||
let network = match ksp_store_api::RawNetworkId::new("devnet") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let signature = match crate::parse_raw_transaction_signature("1".repeat(64).as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let material = crate::RawTransactionMaterial::binary_base64(
|
||||
network,
|
||||
signature,
|
||||
42,
|
||||
std::option::Option::None,
|
||||
"AQID",
|
||||
crate::RawTransactionWireField::Omitted,
|
||||
crate::RawTransactionWireField::Omitted,
|
||||
crate::RawTransactionWireField::Omitted,
|
||||
);
|
||||
return match crate::canonicalize_raw_transaction(material) {
|
||||
std::result::Result::Ok(value) => std::option::Option::Some(value),
|
||||
std::result::Result::Err(_) => std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
fn provenance() -> std::option::Option<ksp_store_api::RawAcquisitionProvenance> {
|
||||
let provider = match ksp_store_api::RawProvenanceCode::new("fixture") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let protocol = match ksp_store_api::RawProvenanceCode::new("fixture.protocol") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let method = match ksp_store_api::RawProvenanceCode::new("fixture.method") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let received_at = match ksp_store_api::RawTimestamp::from_unix_millis(1_700_000_000_000) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
return std::option::Option::Some(ksp_store_api::RawAcquisitionProvenance::new(
|
||||
provider,
|
||||
protocol,
|
||||
method,
|
||||
ksp_store_api::RawAcquisitionOrigin::Import,
|
||||
received_at,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_acquisition_preserves_producer_key_and_exact_transaction_reference() {
|
||||
let transaction = match canonical_transaction() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let provenance = match provenance() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let key = ksp_store_api::RawObservationKey::new([7_u8; 32]);
|
||||
let acquisition = crate::assemble_raw_transaction_acquisition(transaction, key, provenance);
|
||||
assert_eq!(acquisition.observation().observation_key(), key);
|
||||
assert_eq!(acquisition.observation().transaction(), acquisition.transaction().reference());
|
||||
assert_eq!(std::format!("{acquisition:?}"), "RawTransactionAcquisition(..)");
|
||||
let (transaction, observation) = acquisition.into_parts();
|
||||
assert_eq!(observation.transaction(), transaction.reference());
|
||||
return;
|
||||
}
|
||||
219
crates/ksp-raw-transaction-lib/unit_tests/canonical.rs
Normal file
219
crates/ksp-raw-transaction-lib/unit_tests/canonical.rs
Normal file
@@ -0,0 +1,219 @@
|
||||
// file: crates/ksp-raw-transaction-lib/unit_tests/canonical.rs
|
||||
// version: 1
|
||||
|
||||
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;
|
||||
}
|
||||
33
crates/ksp-raw-transaction-lib/unit_tests/signature.rs
Normal file
33
crates/ksp-raw-transaction-lib/unit_tests/signature.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
// file: crates/ksp-raw-transaction-lib/unit_tests/signature.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn pre_002_signature_parser_accepts_exact_sixty_four_zero_bytes() {
|
||||
let text = "1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES);
|
||||
let signature = crate::parse_raw_transaction_signature(text.as_str());
|
||||
assert!(signature.is_ok());
|
||||
if let std::result::Result::Ok(signature) = signature {
|
||||
assert_eq!(signature.as_bytes(), &[0_u8; 64]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_signature_parser_rejects_text_bounds_invalid_base58_and_noncanonical_lengths() {
|
||||
for text in [
|
||||
"1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES - 1),
|
||||
"1".repeat(crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES + 1),
|
||||
format!("{}0", "1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES - 1)),
|
||||
"1".repeat(65),
|
||||
"z".repeat(crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES),
|
||||
] {
|
||||
let result = crate::parse_raw_transaction_signature(text.as_str());
|
||||
assert!(result.is_err());
|
||||
if let std::result::Result::Err(error) = result {
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_SIGNATURE_INVALID);
|
||||
let debug = std::format!("{error:?}");
|
||||
assert!(!debug.contains(text.as_str()));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user