v0.2.9-pre.008
This commit is contained in:
@@ -1,10 +1,37 @@
|
||||
// file: crates/ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
fn filter_name(value: &str) -> crate::YellowstoneSubscribeFilterName {
|
||||
return crate::YellowstoneSubscribeFilterName::new(value).expect("fixture filter name must validate");
|
||||
}
|
||||
|
||||
fn minimal_transaction_info(signature_byte: u8, index: u64) -> yellowstone_grpc_proto::geyser::SubscribeUpdateTransactionInfo {
|
||||
let mut meta = yellowstone_grpc_proto::solana::storage::confirmed_block::TransactionStatusMeta::default();
|
||||
meta.fee = 5_000;
|
||||
return yellowstone_grpc_proto::geyser::SubscribeUpdateTransactionInfo {
|
||||
signature: vec![signature_byte; 64],
|
||||
is_vote: false,
|
||||
transaction: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::Transaction {
|
||||
signatures: vec![vec![signature_byte; 64]],
|
||||
message: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::Message {
|
||||
header: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::MessageHeader {
|
||||
num_required_signatures: 1,
|
||||
num_readonly_signed_accounts: 0,
|
||||
num_readonly_unsigned_accounts: 0,
|
||||
}),
|
||||
account_keys: vec![vec![1_u8; 32]],
|
||||
recent_blockhash: vec![2_u8; 32],
|
||||
instructions: vec![],
|
||||
versioned: false,
|
||||
address_table_lookups: vec![],
|
||||
config: std::option::Option::None,
|
||||
}),
|
||||
}),
|
||||
meta: std::option::Option::Some(meta),
|
||||
index,
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn yellowstone_subscribe_filter_name_is_bounded_globally_unique_and_debug_redacted() {
|
||||
assert!(crate::YellowstoneSubscribeFilterName::new("").is_err());
|
||||
@@ -553,3 +580,199 @@ fn yellowstone_transaction_status_update_preserves_error_and_rejects_malformed_s
|
||||
};
|
||||
assert!(super::decode_transaction_status_update(malformed).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn yellowstone_block_filter_encodes_complete_current_wire_and_redacts_selectors() {
|
||||
let mut filter = crate::YellowstoneSubscribeBlockFilter::new();
|
||||
let account = ksp_core_lib::Pubkey::new_from_array([31_u8; 32]);
|
||||
assert!(filter.push_account_include(account).is_ok());
|
||||
filter.set_include_transactions(std::option::Option::Some(true));
|
||||
filter.set_include_accounts(std::option::Option::Some(false));
|
||||
filter.set_include_entries(std::option::Option::Some(true));
|
||||
let cuckoo = crate::YellowstoneCuckooFilter::new(vec![0_u8; 16], 4, 4, 8, 9, crate::YellowstoneCuckooHashAlgorithm::SipHash)
|
||||
.expect("block Cuckoo filter must validate");
|
||||
filter.set_cuckoo_account_include(std::option::Option::Some(cuckoo));
|
||||
let wire = filter.to_wire();
|
||||
assert_eq!(wire.account_include, vec![account.to_string()]);
|
||||
assert_eq!(wire.include_transactions, std::option::Option::Some(true));
|
||||
assert_eq!(wire.include_accounts, std::option::Option::Some(false));
|
||||
assert_eq!(wire.include_entries, std::option::Option::Some(true));
|
||||
assert!(wire.cuckoo_account_include.is_some());
|
||||
let debug = format!("{filter:?}");
|
||||
assert!(debug.contains("account_include_count"));
|
||||
assert!(!debug.contains(&account.to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn yellowstone_block_update_reuses_transaction_account_entry_dtos_and_preserves_server_counts() {
|
||||
let blockhash = ksp_core_lib::Pubkey::new_from_array([21_u8; 32]).to_string();
|
||||
let parent_blockhash = ksp_core_lib::Pubkey::new_from_array([22_u8; 32]).to_string();
|
||||
let reward_pubkey = ksp_core_lib::Pubkey::new_from_array([23_u8; 32]);
|
||||
let account_pubkey = ksp_core_lib::Pubkey::new_from_array([24_u8; 32]);
|
||||
let wire = yellowstone_grpc_proto::geyser::SubscribeUpdate {
|
||||
filters: vec!["blocks-main".to_owned()],
|
||||
update_oneof: std::option::Option::Some(yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof::Block(
|
||||
yellowstone_grpc_proto::geyser::SubscribeUpdateBlock {
|
||||
slot: 500,
|
||||
blockhash: blockhash.clone(),
|
||||
rewards: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::Rewards {
|
||||
rewards: vec![yellowstone_grpc_proto::solana::storage::confirmed_block::Reward {
|
||||
pubkey: reward_pubkey.to_string(),
|
||||
lamports: 10,
|
||||
post_balance: 11,
|
||||
reward_type: yellowstone_grpc_proto::solana::storage::confirmed_block::RewardType::Fee as i32,
|
||||
commission: "".to_owned(),
|
||||
commission_bps: "".to_owned(),
|
||||
}],
|
||||
num_partitions: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::NumPartitions { num_partitions: 3 }),
|
||||
}),
|
||||
block_time: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::UnixTimestamp { timestamp: 1_700_000_000 }),
|
||||
block_height: std::option::Option::Some(yellowstone_grpc_proto::solana::storage::confirmed_block::BlockHeight { block_height: 499 }),
|
||||
transactions: vec![minimal_transaction_info(7, 2)],
|
||||
parent_slot: 499,
|
||||
parent_blockhash: parent_blockhash.clone(),
|
||||
executed_transaction_count: 12,
|
||||
updated_account_count: 34,
|
||||
accounts: vec![yellowstone_grpc_proto::geyser::SubscribeUpdateAccountInfo {
|
||||
pubkey: vec![24_u8; 32],
|
||||
lamports: 77,
|
||||
owner: vec![25_u8; 32],
|
||||
executable: false,
|
||||
rent_epoch: 4,
|
||||
data: vec![1_u8, 2, 3],
|
||||
write_version: 8,
|
||||
txn_signature: std::option::Option::Some(vec![7_u8; 64]),
|
||||
}],
|
||||
entries_count: 56,
|
||||
entries: vec![yellowstone_grpc_proto::geyser::SubscribeUpdateEntry {
|
||||
slot: 500,
|
||||
index: 4,
|
||||
num_hashes: 5,
|
||||
hash: vec![26_u8; 32],
|
||||
executed_transaction_count: 6,
|
||||
starting_transaction_index: 7,
|
||||
}],
|
||||
},
|
||||
)),
|
||||
created_at: std::option::Option::Some(yellowstone_grpc_proto::prost_types::Timestamp { seconds: 12, nanos: 34 }),
|
||||
};
|
||||
let update = super::decode_block_update(wire).expect("block update fixture must decode");
|
||||
assert_eq!(update.filters()[0].as_str(), "blocks-main");
|
||||
assert_eq!(update.slot(), 500);
|
||||
assert_eq!(update.blockhash(), blockhash);
|
||||
assert_eq!(update.parent_slot(), 499);
|
||||
assert_eq!(update.parent_blockhash(), parent_blockhash);
|
||||
assert_eq!(update.block_time(), std::option::Option::Some(1_700_000_000));
|
||||
assert_eq!(update.block_height(), std::option::Option::Some(499));
|
||||
assert_eq!(update.executed_transaction_count(), 12);
|
||||
assert_eq!(update.transactions().len(), 1);
|
||||
assert_eq!(update.transactions()[0].index(), 2);
|
||||
assert_eq!(update.updated_account_count(), 34);
|
||||
assert_eq!(update.accounts().len(), 1);
|
||||
assert_eq!(update.accounts()[0].pubkey(), &account_pubkey);
|
||||
assert_eq!(update.entries_count(), 56);
|
||||
assert_eq!(update.entries().len(), 1);
|
||||
assert_eq!(update.entries()[0].starting_transaction_index(), 7);
|
||||
let rewards = update.rewards().expect("block rewards must be present");
|
||||
assert_eq!(rewards.rewards().len(), 1);
|
||||
assert_eq!(rewards.num_partitions(), std::option::Option::Some(3));
|
||||
assert_eq!(rewards.rewards()[0].pubkey(), &reward_pubkey);
|
||||
let debug = format!("{update:?}");
|
||||
assert!(!debug.contains(&blockhash));
|
||||
assert!(!debug.contains(&parent_blockhash));
|
||||
assert!(!debug.contains(&reward_pubkey.to_string()));
|
||||
assert!(!debug.contains(&account_pubkey.to_string()));
|
||||
let malformed = yellowstone_grpc_proto::geyser::SubscribeUpdate {
|
||||
filters: vec!["blocks-main".to_owned()],
|
||||
update_oneof: std::option::Option::Some(yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof::Block(
|
||||
yellowstone_grpc_proto::geyser::SubscribeUpdateBlock {
|
||||
slot: 1,
|
||||
blockhash: "not-a-solana-hash".to_owned(),
|
||||
rewards: std::option::Option::None,
|
||||
block_time: std::option::Option::None,
|
||||
block_height: std::option::Option::None,
|
||||
transactions: vec![],
|
||||
parent_slot: 0,
|
||||
parent_blockhash: ksp_core_lib::Pubkey::new_from_array([1_u8; 32]).to_string(),
|
||||
executed_transaction_count: 0,
|
||||
updated_account_count: 0,
|
||||
accounts: vec![],
|
||||
entries_count: 0,
|
||||
entries: vec![],
|
||||
},
|
||||
)),
|
||||
created_at: std::option::Option::None,
|
||||
};
|
||||
assert!(super::decode_block_update(malformed).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn yellowstone_block_meta_and_entry_updates_preserve_optional_and_legacy_entry_fields() {
|
||||
let blockhash = ksp_core_lib::Pubkey::new_from_array([41_u8; 32]).to_string();
|
||||
let parent_blockhash = ksp_core_lib::Pubkey::new_from_array([42_u8; 32]).to_string();
|
||||
let meta_wire = yellowstone_grpc_proto::geyser::SubscribeUpdate {
|
||||
filters: vec!["meta".to_owned()],
|
||||
update_oneof: std::option::Option::Some(yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof::BlockMeta(
|
||||
yellowstone_grpc_proto::geyser::SubscribeUpdateBlockMeta {
|
||||
slot: 900,
|
||||
blockhash: blockhash.clone(),
|
||||
rewards: std::option::Option::None,
|
||||
block_time: std::option::Option::None,
|
||||
block_height: std::option::Option::None,
|
||||
parent_slot: 899,
|
||||
parent_blockhash: parent_blockhash.clone(),
|
||||
executed_transaction_count: 17,
|
||||
entries_count: 18,
|
||||
},
|
||||
)),
|
||||
created_at: std::option::Option::None,
|
||||
};
|
||||
let meta = super::decode_block_meta_update(meta_wire).expect("block-meta update must decode");
|
||||
assert_eq!(meta.slot(), 900);
|
||||
assert_eq!(meta.blockhash(), blockhash);
|
||||
assert_eq!(meta.parent_blockhash(), parent_blockhash);
|
||||
assert_eq!(meta.rewards(), std::option::Option::None);
|
||||
assert_eq!(meta.block_time(), std::option::Option::None);
|
||||
assert_eq!(meta.block_height(), std::option::Option::None);
|
||||
assert_eq!(meta.executed_transaction_count(), 17);
|
||||
assert_eq!(meta.entries_count(), 18);
|
||||
assert!(!format!("{meta:?}").contains(&blockhash));
|
||||
let entry_wire = yellowstone_grpc_proto::geyser::SubscribeUpdate {
|
||||
filters: vec!["entries".to_owned()],
|
||||
update_oneof: std::option::Option::Some(yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof::Entry(
|
||||
yellowstone_grpc_proto::geyser::SubscribeUpdateEntry {
|
||||
slot: 900,
|
||||
index: 3,
|
||||
num_hashes: 4,
|
||||
hash: vec![43_u8; 32],
|
||||
executed_transaction_count: 5,
|
||||
starting_transaction_index: 0,
|
||||
},
|
||||
)),
|
||||
created_at: std::option::Option::Some(yellowstone_grpc_proto::prost_types::Timestamp { seconds: 6, nanos: 7 }),
|
||||
};
|
||||
let entry = super::decode_entry_update(entry_wire).expect("entry update must decode");
|
||||
assert_eq!(entry.filters()[0].as_str(), "entries");
|
||||
assert_eq!(entry.entry().slot(), 900);
|
||||
assert_eq!(entry.entry().index(), 3);
|
||||
assert_eq!(entry.entry().num_hashes(), 4);
|
||||
assert_eq!(entry.entry().hash().as_bytes(), &[43_u8; 32]);
|
||||
assert_eq!(entry.entry().executed_transaction_count(), 5);
|
||||
assert_eq!(entry.entry().starting_transaction_index(), 0);
|
||||
assert!(!format!("{entry:?}").contains("43, 43"));
|
||||
let malformed_entry = yellowstone_grpc_proto::geyser::SubscribeUpdate {
|
||||
filters: vec!["entries".to_owned()],
|
||||
update_oneof: std::option::Option::Some(yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof::Entry(
|
||||
yellowstone_grpc_proto::geyser::SubscribeUpdateEntry {
|
||||
slot: 1,
|
||||
index: 0,
|
||||
num_hashes: 0,
|
||||
hash: vec![0_u8; 31],
|
||||
executed_transaction_count: 0,
|
||||
starting_transaction_index: 0,
|
||||
},
|
||||
)),
|
||||
created_at: std::option::Option::None,
|
||||
};
|
||||
assert!(super::decode_entry_update(malformed_entry).is_err());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user