0.3.15-pre.014
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
|
||||
// version: 48
|
||||
// version: 49
|
||||
|
||||
use sha2::Digest; // rust-rules: trait-import
|
||||
|
||||
@@ -19,6 +19,7 @@ pub const MIN_RAW_TRANSACTION_INGEST_HTTP_POLL_INTERVAL: std::time::Duration = s
|
||||
pub const MIN_RAW_TRANSACTION_INGEST_HTTP_POLL_MAX_BLOCKS_PER_CYCLE: u16 = 1;
|
||||
|
||||
const MAX_RAW_TRANSACTION_INGEST_REPAIR_BURST: usize = 1;
|
||||
const RAW_TRANSACTION_INGEST_BLOCK_IDENTITY_FINGERPRINT_DOMAIN: &[u8] = b"ksp.raw_transaction_ingest.block_identity.v1\0";
|
||||
const RAW_TRANSACTION_INGEST_HELIUS_TRANSACTION_FILTER_FINGERPRINT_DOMAIN: &[u8] = b"ksp.raw_transaction_ingest.helius_transaction.filter.v1\0";
|
||||
const RAW_TRANSACTION_INGEST_HELIUS_TRANSACTION_HTTP_PROTOCOL: &str = "helius_ws_http";
|
||||
const RAW_TRANSACTION_INGEST_HELIUS_TRANSACTION_HTTP_SOURCE_KEY_DOMAIN: &[u8] = b"ksp.raw_transaction_ingest.helius_transaction_http.source_key.v1\0";
|
||||
@@ -3595,6 +3596,7 @@ async fn fetch_yellowstone_block_ingresses(
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return std::result::Result::Err(crate::runtime_error("source.yellowstone_block_not_available")),
|
||||
};
|
||||
log_block_identity("yellowstone_block_hydration", &hydration.network, slot, hydration.commitment, observed.endpoint_name(), observed.provider(), block);
|
||||
let received_at = match current_raw_timestamp() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
@@ -3665,6 +3667,7 @@ fn project_http_block_polling_ingresses(
|
||||
observed: &ksp_onchain_transport_lib::HttpObservedValue<std::option::Option<ksp_onchain_transport_lib::SolanaConfirmedBlock>>,
|
||||
received_at: ksp_store_lib::RawTimestamp,
|
||||
) -> ksp_core_lib::Result<std::vec::Vec<crate::RawTransactionIngress>> {
|
||||
log_block_identity("http_block_polling", &source.network, slot, source.commitment, observed.endpoint_name(), observed.provider(), block);
|
||||
let transactions = match block.transactions() {
|
||||
ksp_onchain_transport_lib::SolanaWireField::Value(value) => value,
|
||||
ksp_onchain_transport_lib::SolanaWireField::Omitted | ksp_onchain_transport_lib::SolanaWireField::Null => {
|
||||
@@ -5573,6 +5576,61 @@ fn hydration_method_code(family: RawTransactionIngestSourceFamily) -> &'static s
|
||||
};
|
||||
}
|
||||
|
||||
fn block_identity_fingerprint(block: &ksp_onchain_transport_lib::SolanaConfirmedBlock) -> std::string::String {
|
||||
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(RAW_TRANSACTION_INGEST_BLOCK_IDENTITY_FINGERPRINT_DOMAIN);
|
||||
hash_live_source_key_component(&mut hasher, block.blockhash().as_bytes());
|
||||
hash_live_source_key_component(&mut hasher, block.previous_blockhash().as_bytes());
|
||||
hasher.update(block.parent_slot().to_be_bytes());
|
||||
match block.block_height() {
|
||||
std::option::Option::Some(value) => {
|
||||
hasher.update([1_u8]);
|
||||
hasher.update(value.to_be_bytes());
|
||||
},
|
||||
std::option::Option::None => hasher.update([0_u8]),
|
||||
}
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
let mut value = std::string::String::with_capacity(71);
|
||||
value.push_str("sha256.");
|
||||
for byte in digest {
|
||||
value.push(char::from(HEX[usize::from(byte >> 4)]));
|
||||
value.push(char::from(HEX[usize::from(byte & 0x0f)]));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
fn log_block_identity(
|
||||
source_kind: &'static str,
|
||||
network: &ksp_store_lib::RawNetworkId,
|
||||
slot: u64,
|
||||
commitment: ksp_onchain_transport_lib::SolanaCommitment,
|
||||
endpoint_name: &str,
|
||||
provider_name: &ksp_onchain_transport_lib::HttpProviderName,
|
||||
block: &ksp_onchain_transport_lib::SolanaConfirmedBlock,
|
||||
) {
|
||||
let fingerprint = block_identity_fingerprint(block);
|
||||
let block_height = match block.block_height() {
|
||||
std::option::Option::Some(value) => value.to_string(),
|
||||
std::option::Option::None => "none".to_owned(),
|
||||
};
|
||||
ksp_logging_lib::debug!(
|
||||
target: crate::TRACING_TARGET,
|
||||
domain = "raw_transaction_ingest.block_identity",
|
||||
source_kind = source_kind,
|
||||
network = network.as_str(),
|
||||
slot = slot,
|
||||
provider = provider_name.as_str(),
|
||||
endpoint_id = endpoint_name,
|
||||
commitment = commitment.as_str(),
|
||||
parent_slot = block.parent_slot(),
|
||||
block_height = block_height.as_str(),
|
||||
block_identity_fingerprint = fingerprint.as_str(),
|
||||
"RAW transaction ingest observed HTTP block identity"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
fn fingerprint_filter_code(fingerprint: &[u8; 32]) -> ksp_core_lib::Result<ksp_store_lib::RawProvenanceCode> {
|
||||
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||
let mut value = std::string::String::with_capacity(71);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
|
||||
// version: 39
|
||||
// version: 40
|
||||
|
||||
//! External public, security, redaction and release-boundary hardening canaries through `v0.3.15-pre.004`.
|
||||
|
||||
@@ -1449,3 +1449,35 @@ fn v0_3_15_pre_013_yellowstone_block_hydration_is_bounded_concurrent_and_stop_pr
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_15_pre_014_cross_provider_block_identity_diagnostic_is_safe_and_covers_both_get_block_routes() {
|
||||
let resources = include_str!("../src/runtime_resources.rs");
|
||||
for required in [
|
||||
"RAW_TRANSACTION_INGEST_BLOCK_IDENTITY_FINGERPRINT_DOMAIN",
|
||||
"fn block_identity_fingerprint(",
|
||||
"fn log_block_identity(",
|
||||
"domain = \"raw_transaction_ingest.block_identity\"",
|
||||
"\"yellowstone_block_hydration\"",
|
||||
"\"http_block_polling\"",
|
||||
"block_identity_fingerprint = fingerprint.as_str()",
|
||||
"parent_slot = block.parent_slot()",
|
||||
] {
|
||||
assert!(resources.contains(required), "missing pre.014 block identity diagnostic guard: {required}");
|
||||
}
|
||||
let start = resources.find("fn log_block_identity(");
|
||||
assert!(start.is_some(), "missing pre.014 block identity logger");
|
||||
let Some(start) = start else {
|
||||
return;
|
||||
};
|
||||
let end = resources[start..].find("fn fingerprint_filter_code(");
|
||||
assert!(end.is_some(), "missing pre.014 block identity logger end marker");
|
||||
let Some(end) = end else {
|
||||
return;
|
||||
};
|
||||
let logger = &resources[start..start + end];
|
||||
for forbidden in ["blockhash =", "previous_blockhash =", "signature =", "payload =", "transaction ="] {
|
||||
assert!(!logger.contains(forbidden), "pre.014 block identity logger exposes forbidden material: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
|
||||
// version: 35
|
||||
// version: 36
|
||||
|
||||
//! Release-completeness canaries through the `v0.3.15-pre.004` WebSocket capability-enforcement tranche.
|
||||
|
||||
@@ -496,3 +496,13 @@ fn v0_3_15_pre_013_yellowstone_block_backpressure_fix_adds_no_public_surface() {
|
||||
assert!(!root.contains("YellowstoneBlockHydrationContext"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_15_pre_014_cross_provider_convergence_diagnostic_adds_no_public_worker_surface() {
|
||||
let hardening = include_str!("hardening.rs");
|
||||
let root = include_str!("../src/lib.rs");
|
||||
assert!(hardening.contains("v0_3_15_pre_014_cross_provider_block_identity_diagnostic_is_safe_and_covers_both_get_block_routes"));
|
||||
assert!(!root.contains("BlockIdentityFingerprint"));
|
||||
assert!(!root.contains("LogMessagesConflictDiagnostic"));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user