Files
khadhroony-solana-project/crates/ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs
2026-08-24 11:55:17 +02:00

126 lines
7.7 KiB
Rust

// file: crates/ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs
// version: 1
fn filter_name(value: &str) -> crate::YellowstoneSubscribeFilterName {
return crate::YellowstoneSubscribeFilterName::new(value).expect("fixture filter name must validate");
}
#[test]
fn yellowstone_subscribe_filter_name_is_bounded_globally_unique_and_debug_redacted() {
assert!(crate::YellowstoneSubscribeFilterName::new("").is_err());
assert!(crate::YellowstoneSubscribeFilterName::new(" leading").is_err());
assert!(crate::YellowstoneSubscribeFilterName::new("trailing ").is_err());
assert!(crate::YellowstoneSubscribeFilterName::new("line\nbreak").is_err());
assert!(crate::YellowstoneSubscribeFilterName::new("x".repeat(129)).is_err());
let name = filter_name("account-primary");
assert_eq!(name.as_str(), "account-primary");
assert!(!format!("{name:?}").contains("account-primary"));
let mut request = crate::YellowstoneSubscribeRequest::new();
assert!(request.insert_account_filter(name.clone(), crate::YellowstoneSubscribeAccountFilter::new()).is_ok());
let duplicate = request.insert_slot_filter(name, crate::YellowstoneSubscribeSlotFilter::new());
assert!(duplicate.is_err());
}
#[test]
fn yellowstone_subscribe_empty_and_named_empty_maps_encode_exactly() {
let empty = crate::YellowstoneSubscribeRequest::new().to_wire().expect("empty request must encode");
assert!(empty.accounts.is_empty());
assert!(empty.slots.is_empty());
assert!(empty.transactions.is_empty());
assert!(empty.transactions_status.is_empty());
assert!(empty.blocks.is_empty());
assert!(empty.blocks_meta.is_empty());
assert!(empty.entry.is_empty());
assert_eq!(empty.commitment, std::option::Option::None);
assert!(empty.accounts_data_slice.is_empty());
assert_eq!(empty.ping, std::option::Option::None);
assert_eq!(empty.from_slot, std::option::Option::None);
let mut request = crate::YellowstoneSubscribeRequest::new();
assert!(request.insert_account_filter(filter_name("accounts"), crate::YellowstoneSubscribeAccountFilter::new()).is_ok());
assert!(request.insert_slot_filter(filter_name("slots"), crate::YellowstoneSubscribeSlotFilter::new()).is_ok());
assert!(request.insert_transaction_filter(filter_name("transactions"), crate::YellowstoneSubscribeTransactionFilter::new()).is_ok());
assert!(request.insert_transaction_status_filter(filter_name("transaction-status"), crate::YellowstoneSubscribeTransactionFilter::new()).is_ok());
assert!(request.insert_block_filter(filter_name("blocks"), crate::YellowstoneSubscribeBlockFilter::new()).is_ok());
assert!(request.insert_blocks_meta_filter(filter_name("blocks-meta"), crate::YellowstoneSubscribeBlocksMetaFilter::new()).is_ok());
assert!(request.insert_entry_filter(filter_name("entry"), crate::YellowstoneSubscribeEntryFilter::new()).is_ok());
let wire = request.to_wire().expect("named empty request must encode");
assert_eq!(wire.accounts.len(), 1);
assert_eq!(wire.slots.len(), 1);
assert_eq!(wire.transactions.len(), 1);
assert_eq!(wire.transactions_status.len(), 1);
assert_eq!(wire.blocks.len(), 1);
assert_eq!(wire.blocks_meta.len(), 1);
assert_eq!(wire.entry.len(), 1);
assert_eq!(wire.accounts.get("accounts"), std::option::Option::Some(&yellowstone_grpc_proto::geyser::SubscribeRequestFilterAccounts::default()));
assert_eq!(wire.slots.get("slots"), std::option::Option::Some(&yellowstone_grpc_proto::geyser::SubscribeRequestFilterSlots::default()));
assert_eq!(
wire.transactions.get("transactions"),
std::option::Option::Some(&yellowstone_grpc_proto::geyser::SubscribeRequestFilterTransactions::default())
);
assert_eq!(
wire.transactions_status.get("transaction-status"),
std::option::Option::Some(&yellowstone_grpc_proto::geyser::SubscribeRequestFilterTransactions::default())
);
assert_eq!(wire.blocks.get("blocks"), std::option::Option::Some(&yellowstone_grpc_proto::geyser::SubscribeRequestFilterBlocks::default()));
assert!(wire.blocks_meta.contains_key("blocks-meta"));
assert!(wire.entry.contains_key("entry"));
}
#[test]
fn yellowstone_subscribe_common_fields_preserve_optional_and_ordered_wire_semantics() {
let mut request = crate::YellowstoneSubscribeRequest::new();
request.set_commitment(std::option::Option::Some(crate::SolanaCommitment::Finalized));
let first = crate::YellowstoneAccountsDataSlice::new(8, 16).expect("first slice must validate");
let second = crate::YellowstoneAccountsDataSlice::new(64, 0).expect("zero-length slice remains representable");
assert!(request.push_accounts_data_slice(first).is_ok());
assert!(request.push_accounts_data_slice(second).is_ok());
request.set_ping(std::option::Option::Some(crate::YellowstoneSubscribePing::new(-7)));
request.set_from_slot(std::option::Option::Some(42));
assert_eq!(request.commitment(), std::option::Option::Some(crate::SolanaCommitment::Finalized));
assert_eq!(request.accounts_data_slices(), &[first, second]);
assert_eq!(request.ping(), std::option::Option::Some(crate::YellowstoneSubscribePing::new(-7)));
assert_eq!(request.from_slot(), std::option::Option::Some(42));
let wire = request.to_wire().expect("common fields must encode");
assert_eq!(wire.commitment, std::option::Option::Some(yellowstone_grpc_proto::geyser::CommitmentLevel::Finalized as i32));
assert_eq!(wire.accounts_data_slice.len(), 2);
assert_eq!(wire.accounts_data_slice[0].offset, 8);
assert_eq!(wire.accounts_data_slice[0].length, 16);
assert_eq!(wire.accounts_data_slice[1].offset, 64);
assert_eq!(wire.accounts_data_slice[1].length, 0);
assert_eq!(wire.ping.map(|ping| return ping.id), std::option::Option::Some(-7));
assert_eq!(wire.from_slot, std::option::Option::Some(42));
}
#[test]
fn yellowstone_subscribe_common_bounds_reject_before_wire_conversion() {
assert!(crate::YellowstoneAccountsDataSlice::new(0, 64 * 1024 * 1024).is_ok());
assert!(crate::YellowstoneAccountsDataSlice::new(0, 64 * 1024 * 1024 + 1).is_err());
assert!(crate::YellowstoneAccountsDataSlice::new(u64::MAX, 1).is_err());
let mut slices = crate::YellowstoneSubscribeRequest::new();
for index in 0..128_u64 {
let slice = crate::YellowstoneAccountsDataSlice::new(index, 1).expect("bounded fixture slice must validate");
assert!(slices.push_accounts_data_slice(slice).is_ok());
}
let excess = crate::YellowstoneAccountsDataSlice::new(129, 1).expect("excess fixture slice itself must validate");
assert!(slices.push_accounts_data_slice(excess).is_err());
let mut filters = crate::YellowstoneSubscribeRequest::new();
for index in 0..1_024_u32 {
let name = crate::YellowstoneSubscribeFilterName::new(format!("f{index}")).expect("bounded filter name must validate");
assert!(filters.insert_account_filter(name, crate::YellowstoneSubscribeAccountFilter::new()).is_ok());
}
let excess_name = crate::YellowstoneSubscribeFilterName::new("excess").expect("excess filter name must validate independently");
assert!(filters.insert_account_filter(excess_name, crate::YellowstoneSubscribeAccountFilter::new()).is_err());
}
#[test]
fn yellowstone_subscribe_debug_omits_filter_names_and_future_payloads() {
let mut request = crate::YellowstoneSubscribeRequest::new();
assert!(request.insert_account_filter(filter_name("sensitive-label"), crate::YellowstoneSubscribeAccountFilter::new()).is_ok());
request.set_ping(std::option::Option::Some(crate::YellowstoneSubscribePing::new(9)));
request.set_from_slot(std::option::Option::Some(77));
let debug = format!("{request:?}");
assert!(!debug.contains("sensitive-label"));
assert!(debug.contains("account_filter_count"));
assert!(debug.contains("from_slot"));
}