v0.3.13-pre.002
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/grpc_subscribe.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
const MAX_GRPC_BLOCKHASH_TEXT_LENGTH_BYTES: usize = 128;
|
||||
const MAX_GRPC_BLOCK_VECTOR_COUNT: usize = 65_536;
|
||||
@@ -2529,13 +2529,34 @@ impl YellowstoneSubscribeEntryFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque deterministic identity material for one complete Yellowstone Subscribe request.
|
||||
///
|
||||
/// The encoded bytes remain private. `Hash` feeds those canonical bytes to a caller-provided hasher while `Debug` exposes only their length.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct YellowstoneSubscribeRequestIdentity {
|
||||
bytes: std::vec::Vec<u8>,
|
||||
}
|
||||
|
||||
impl std::hash::Hash for crate::YellowstoneSubscribeRequestIdentity {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
state.write(&(self.bytes.len() as u64).to_be_bytes());
|
||||
state.write(self.bytes.as_slice());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for crate::YellowstoneSubscribeRequestIdentity {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter.debug_struct("YellowstoneSubscribeRequestIdentity").field("byte_len", &self.bytes.len()).finish();
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider-neutral standard Yellowstone subscribe request owned by KSP.
|
||||
///
|
||||
/// The seven upstream maps are represented independently and retain named empty entries. An entirely empty map is the logical KSP representation of no active
|
||||
/// filter in that family; protobuf map encoding does not distinguish an omitted map from an empty map. Filter-group names are globally unique across all seven
|
||||
/// maps so the names echoed by `SubscribeUpdate.filters` remain unambiguous. `Debug` exposes only counts and common scalar options, never filter names or
|
||||
/// future
|
||||
/// filter payloads.
|
||||
/// future filter payloads.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct YellowstoneSubscribeRequest {
|
||||
accounts: std::collections::BTreeMap<crate::YellowstoneSubscribeFilterName, crate::YellowstoneSubscribeAccountFilter>,
|
||||
@@ -2551,7 +2572,7 @@ pub struct YellowstoneSubscribeRequest {
|
||||
from_slot: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
impl YellowstoneSubscribeRequest {
|
||||
impl crate::YellowstoneSubscribeRequest {
|
||||
/// Creates an empty subscribe request. Empty requests are valid because later bidi lifecycle code uses request mutations to clear filters or carry ping
|
||||
/// state.
|
||||
#[must_use]
|
||||
@@ -2762,6 +2783,40 @@ impl YellowstoneSubscribeRequest {
|
||||
return self.from_slot;
|
||||
}
|
||||
|
||||
/// Builds one opaque deterministic identity for the complete logical Subscribe request.
|
||||
///
|
||||
/// The identity preserves filter-family separation, globally sorted filter names, exact filter wire payloads and common request options. Its Debug surface
|
||||
/// exposes only the encoded byte length. Callers may hash the opaque value but cannot recover the underlying identity bytes through this API.
|
||||
pub fn identity(&self) -> ksp_core_lib::Result<crate::YellowstoneSubscribeRequestIdentity> {
|
||||
let validation = self.validate();
|
||||
if let std::result::Result::Err(error) = validation {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
let mut bytes = std::vec::Vec::new();
|
||||
append_subscribe_identity_map(&mut bytes, b"accounts", &self.accounts, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"blocks", &self.blocks, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"blocks_meta", &self.blocks_meta, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"entry", &self.entry, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"slots", &self.slots, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"transactions", &self.transactions, |filter| return filter.to_wire());
|
||||
append_subscribe_identity_map(&mut bytes, b"transactions_status", &self.transactions_status, |filter| return filter.to_wire());
|
||||
let mut common = match self.to_wire() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
common.accounts.clear();
|
||||
common.blocks.clear();
|
||||
common.blocks_meta.clear();
|
||||
common.entry.clear();
|
||||
common.slots.clear();
|
||||
common.transactions.clear();
|
||||
common.transactions_status.clear();
|
||||
let common = yellowstone_grpc_proto::prost::Message::encode_to_vec(&common);
|
||||
append_subscribe_identity_component(&mut bytes, b"common");
|
||||
append_subscribe_identity_component(&mut bytes, common.as_slice());
|
||||
return std::result::Result::Ok(crate::YellowstoneSubscribeRequestIdentity { bytes });
|
||||
}
|
||||
|
||||
/// Validates all deterministic common subscribe-request bounds before any network I/O.
|
||||
pub fn validate(&self) -> ksp_core_lib::Result<()> {
|
||||
if self.total_filter_count() > MAX_GRPC_SUBSCRIBE_FILTER_GROUP_COUNT {
|
||||
@@ -3710,13 +3765,38 @@ fn commitment_to_wire(commitment: std::option::Option<crate::SolanaCommitment>)
|
||||
});
|
||||
}
|
||||
|
||||
impl std::default::Default for YellowstoneSubscribeRequest {
|
||||
fn append_subscribe_identity_component(output: &mut std::vec::Vec<u8>, value: &[u8]) {
|
||||
output.extend_from_slice(&(value.len() as u64).to_be_bytes());
|
||||
output.extend_from_slice(value);
|
||||
return;
|
||||
}
|
||||
|
||||
fn append_subscribe_identity_map<V, W, F>(
|
||||
output: &mut std::vec::Vec<u8>,
|
||||
family: &[u8],
|
||||
values: &std::collections::BTreeMap<crate::YellowstoneSubscribeFilterName, V>,
|
||||
mut to_wire: F,
|
||||
) where
|
||||
W: yellowstone_grpc_proto::prost::Message,
|
||||
F: FnMut(&V) -> W,
|
||||
{
|
||||
append_subscribe_identity_component(output, family);
|
||||
output.extend_from_slice(&(values.len() as u64).to_be_bytes());
|
||||
for (name, filter) in values {
|
||||
append_subscribe_identity_component(output, name.as_str().as_bytes());
|
||||
let wire = yellowstone_grpc_proto::prost::Message::encode_to_vec(&to_wire(filter));
|
||||
append_subscribe_identity_component(output, wire.as_slice());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::YellowstoneSubscribeRequest {
|
||||
fn default() -> Self {
|
||||
return Self::new();
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for YellowstoneSubscribeRequest {
|
||||
impl std::fmt::Debug for crate::YellowstoneSubscribeRequest {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("YellowstoneSubscribeRequest")
|
||||
|
||||
Reference in New Issue
Block a user