126 lines
7.7 KiB
Rust
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"));
|
|
}
|