From dc8863a46dee8ae8dbc2683d6ff5e1bdd4cb6c26 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sun, 13 Sep 2026 08:47:31 +0200 Subject: [PATCH] v0.3.15-pre.004 --- Cargo.toml | 4 +- .../README.md | 14 +- .../USAGE.md | 8 +- .../src/runtime_resources.rs | 24 ++- .../unit_tests/runtime_resources.rs | 199 +++++++++++++++++- ...0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md | 4 +- 6 files changed, 229 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f20ddee..fa5fd12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 597 +# version: 598 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.15-pre.3" +version = "0.3.15-pre.4" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/README.md b/crates/ksp-worker-raw-transaction-ingest-lib/README.md index 50c6e0d..e03ceeb 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/README.md +++ b/crates/ksp-worker-raw-transaction-ingest-lib/README.md @@ -1,5 +1,5 @@ - + # ksp-worker-raw-transaction-ingest-lib @@ -93,14 +93,14 @@ Un inventaire privé `source_key -> latest processing/source state`, borné à 3 `RawTransactionIngestStandardLogsSource::new` reçoit : ```text -WsEndpointSettings kind solana_standard +WsEndpointSettings kind solana_standard avec capability Logs déclarée SolanaLogsSubscribeFilter SolanaCommitment Confirmed ou Finalized HttpTransportPool HttpRoleName d'hydration ``` -La construction est sans I/O. Elle refuse un endpoint WS invalide ou non standard, `Processed`, un réseau/provenance non représentable et l'absence de route HTTP `getTransaction` compatible sur le même réseau. Le filtre `All`, `AllWithVotes` ou `Mentions(pubkey)` participe uniquement à une empreinte privée ; le pubkey d'un filtre `Mentions` n'est pas recopié dans `Debug`, snapshot ou provenance textuelle. +La construction est sans I/O. Elle refuse un endpoint WS invalide ou non standard, une capability `Logs` absente ou non déclarée, `Processed`, un réseau/provenance non représentable et l'absence de route HTTP `getTransaction` compatible sur le même réseau. Le filtre `All`, `AllWithVotes` ou `Mentions(pubkey)` participe uniquement à une empreinte privée ; le pubkey d'un filtre `Mentions` n'est pas recopié dans `Debug`, snapshot ou provenance textuelle. Au runtime, le Worker ouvre `SolanaStandardWsSession::connect`, puis `logs_subscribe`. Les lignes de logs et `err` restent dans Transport et ne sont jamais stockées dans le signal Worker. Seuls `context.slot` et `signature` sont projetés vers l'hydration commune. Reconnect, resubscribe et backpressure de la subscription restent possédés par Transport. @@ -109,12 +109,12 @@ Au runtime, le Worker ouvre `SolanaStandardWsSession::connect`, puis `logs_subsc `RawTransactionIngestStandardBlockSource::new` reçoit : ```text -WsEndpointSettings kind solana_standard +WsEndpointSettings kind solana_standard avec capability Block déclarée SolanaBlockSubscribeFilter SolanaCommitment Confirmed ou Finalized ``` -Le runtime ouvre la `SolanaStandardWsSession` existante et demande exactement `Base64`, `Full`, `maxSupportedTransactionVersion = 1` et `showRewards = false`. Aucun `HttpTransportPool` n'est attaché à cette source : les transactions dont la version est explicitement `Legacy`, `0` ou `1` sont transformées directement en `RawTransactionMaterial` à partir du wire Base64 du bloc, avec signature embarquée, slot, block time, meta, version et index de transaction. +La construction est sans I/O et refuse un endpoint qui ne déclare pas explicitement la capability `Block`. Le runtime ouvre ensuite la `SolanaStandardWsSession` existante et demande exactement `Base64`, `Full`, `maxSupportedTransactionVersion = 1` et `showRewards = false`. Aucun `HttpTransportPool` n'est attaché à cette source : les transactions dont la version est explicitement `Legacy`, `0` ou `1` sont transformées directement en `RawTransactionMaterial` à partir du wire Base64 du bloc, avec signature embarquée, slot, block time, meta, version et index de transaction. La qualification est fermée : une version omise/nulle ou supérieure à `1`, une transaction non Base64, `block: null`, une erreur distante de notification, un slot de contexte incohérent ou un champ transactions absent/nul termine la source par une erreur sûre. Aucun de ces cas n'est converti en bloc vide, en succès silencieux ou en progression artificielle de frontier. @@ -125,14 +125,14 @@ Pour un bloc multi-transaction, le slot n'est projeté settled qu'après l'admis `RawTransactionIngestHeliusTransactionSource::new` reçoit : ```text -WsEndpointSettings kind helius_laserstream +WsEndpointSettings kind helius_laserstream avec capability HeliusTransaction déclarée HeliusTransactionSubscribeFilter SolanaCommitment Confirmed ou Finalized HttpTransportPool HttpRoleName d'hydration ``` -La construction est sans I/O. Elle réutilise le contrat Transport existant et impose `Full`, `Base64`, `showRewards = false` et `maxSupportedTransactionVersion = 1`. Le Worker ne lit pas Config, ne lit pas `KSP_SECRET_HELIUS_API_KEY` et ne code aucun tier provider ; l'URL résolue et le credential restent dans l'endpoint Transport fourni par le caller. +La construction est sans I/O. Elle exige la capability Transport `HeliusTransaction`, puis réutilise le contrat Transport existant et impose `Full`, `Base64`, `showRewards = false` et `maxSupportedTransactionVersion = 1`. Le Worker ne lit pas Config, ne lit pas `KSP_SECRET_HELIUS_API_KEY` et ne code aucun tier provider ; l'URL résolue et le credential restent dans l'endpoint Transport fourni par le caller. Au runtime, `HeliusLaserStreamWsSession::connect` puis `transaction_subscribe` sont utilisés. Seule une notification `Full` conforme au mode demandé est admise ; une forme `Signature`, `Unknown` ou future devient une faute source sûre. Le payload Helius `transaction` n'est jamais copié dans l'état Worker : la projection conserve uniquement signature, slot et transaction index, puis réutilise le coordinateur d'hydration commun `getTransaction observed`. diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md b/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md index 81b444c..a2b359d 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md +++ b/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md @@ -1,5 +1,5 @@ - + # Utilisation de ksp-worker-raw-transaction-ingest-lib @@ -145,7 +145,7 @@ fn standard_logs_runtime_resources( } ``` -`ws_endpoint` doit être un endpoint Transport valide de kind `solana_standard`. Le commitment doit être explicitement `Confirmed` ou `Finalized`. Le pool HTTP doit exposer `getTransaction` via le rôle indiqué sur le même réseau. `All`, `AllWithVotes` et `Mentions(pubkey)` sont acceptés par le contrat Transport ; la valeur du filtre reste privée dans le Worker. +`ws_endpoint` doit être un endpoint Transport valide de kind `solana_standard` déclarant explicitement `WsSubscriptionKind::Logs`. Un endpoint legacy dont les capabilities sont absentes est refusé fail-closed. Le commitment doit être explicitement `Confirmed` ou `Finalized`. Le pool HTTP doit exposer `getTransaction` via le rôle indiqué sur le même réseau. `All`, `AllWithVotes` et `Mentions(pubkey)` sont acceptés par le contrat Transport ; la valeur du filtre reste privée dans le Worker. ### Source Standard Block productive @@ -165,7 +165,7 @@ fn standard_block_runtime_resources( } ``` -Le Worker demande `Base64`, `Full`, `maxSupportedTransactionVersion = 1` et `showRewards = false`. Une transaction n'est RAW-direct que si sa version est explicitement `Legacy`, `0` ou `1`. Une version omise/nulle ou supérieure, `block: null`, une erreur de bloc, un champ transactions absent/nul ou une transaction non Base64 provoque une faute sûre ; ces cas ne sont jamais assimilés à une progression vide. +`ws_endpoint` doit déclarer explicitement `WsSubscriptionKind::Block`; l'absence de déclaration est refusée avant toute connexion. Le Worker demande `Base64`, `Full`, `maxSupportedTransactionVersion = 1` et `showRewards = false`. Une transaction n'est RAW-direct que si sa version est explicitement `Legacy`, `0` ou `1`. Une version omise/nulle ou supérieure, `block: null`, une erreur de bloc, un champ transactions absent/nul ou une transaction non Base64 provoque une faute sûre ; ces cas ne sont jamais assimilés à une progression vide. ### Source Helius Transaction productive @@ -193,7 +193,7 @@ fn helius_transaction_runtime_resources( } ``` -`ws_endpoint` doit être un endpoint Transport de kind `helius_laserstream`. Le caller supérieur résout éventuellement `KSP_SECRET_HELIUS_API_KEY` via Config avant de construire l'endpoint ; le Worker ne lit jamais l'environnement ni Config. Le commitment est limité à `Confirmed`/`Finalized` et la route HTTP doit supporter `getTransaction` sur le même réseau. +`ws_endpoint` doit être un endpoint Transport de kind `helius_laserstream` déclarant explicitement `WsSubscriptionKind::HeliusTransaction`. L'état capability undeclared est refusé avant toute connexion. Le caller supérieur résout éventuellement `KSP_SECRET_HELIUS_API_KEY` via Config avant de construire l'endpoint ; le Worker ne lit jamais l'environnement ni Config. Le commitment est limité à `Confirmed`/`Finalized` et la route HTTP doit supporter `getTransaction` sur le même réseau. Le Worker demande la forme Helius `Full` avec `Base64`, `showRewards = false` et `maxSupportedTransactionVersion = 1`, mais ne fait pas confiance au nested payload pour construire directement le Common RAW. Il conserve seulement signature/slot/index et hydrate par `getTransaction observed`. Une notification d'une autre forme est fail-closed. diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs b/crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs index b4a5b71..234812e 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs +++ b/crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs @@ -1,5 +1,5 @@ // file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs -// version: 43 +// version: 44 use sha2::Digest; // rust-rules: trait-import @@ -1201,8 +1201,8 @@ impl crate::RawTransactionIngestYellowstoneSource { /// Validated Helius `transactionSubscribe` plus HTTP hydration source owned by the continuous RAW transaction ingest Worker. /// -/// The caller provides one Transport-owned Helius LaserStream WebSocket endpoint, one Helius transaction filter, a Confirmed/Finalized commitment and one HTTP -/// hydration pool/role. The Worker always requests Full/Base64 notifications with `maxSupportedTransactionVersion = 1` but projects only the provider +/// The caller provides one Transport-owned Helius LaserStream WebSocket endpoint explicitly declaring `HeliusTransaction`, one Helius transaction filter, a +/// Confirmed/Finalized commitment and one HTTP hydration pool/role. The Worker always requests Full/Base64 notifications with `maxSupportedTransactionVersion = 1` but projects only the provider /// signature/slot/index reference into the source-neutral hydration coordinator; the nested Helius payload is never copied into Worker state, while endpoint /// URLs and sensitive endpoint material remain encapsulated by Transport-owned settings and are never exposed by Worker APIs or diagnostics. pub struct RawTransactionIngestHeliusTransactionSource { @@ -1233,6 +1233,9 @@ impl crate::RawTransactionIngestHeliusTransactionSource { if ws_endpoint.protocol() != ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream { return std::result::Result::Err(crate::runtime_error("runtime_resources.helius_transaction_protocol_invalid")); } + if !ws_endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction) { + return std::result::Result::Err(crate::runtime_error("runtime_resources.helius_transaction_capability_missing")); + } match commitment { ksp_onchain_transport_lib::SolanaCommitment::Confirmed | ksp_onchain_transport_lib::SolanaCommitment::Finalized => {}, ksp_onchain_transport_lib::SolanaCommitment::Processed => { @@ -1788,8 +1791,9 @@ impl std::fmt::Debug for crate::RawTransactionIngestHttpBlockPollingSource { /// Validated standard Solana `blockSubscribe` direct RAW source owned by the continuous RAW transaction ingest Worker. /// -/// The caller provides one Transport-owned standard WebSocket endpoint, one block filter and a Confirmed/Finalized commitment. The source requests Full/Base64 -/// blocks with `maxSupportedTransactionVersion = 1`, admits only explicitly qualified Legacy/V0/V1 transactions, and treats `block: null`, remote block errors, +/// The caller provides one Transport-owned standard WebSocket endpoint explicitly declaring `Block`, one block filter and a Confirmed/Finalized commitment. +/// The source requests Full/Base64 blocks with `maxSupportedTransactionVersion = 1`, admits only explicitly qualified Legacy/V0/V1 transactions, and treats +/// `block: null`, remote block errors, /// unsupported versions and incomplete block transaction shapes as safe terminal source failures rather than empty progress. pub struct RawTransactionIngestStandardBlockSource { ws_endpoint: ksp_onchain_transport_lib::WsEndpointSettings, @@ -1815,6 +1819,9 @@ impl crate::RawTransactionIngestStandardBlockSource { if ws_endpoint.protocol() != ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard { return std::result::Result::Err(crate::runtime_error("runtime_resources.standard_block_protocol_invalid")); } + if !ws_endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Block) { + return std::result::Result::Err(crate::runtime_error("runtime_resources.standard_block_capability_missing")); + } match commitment { ksp_onchain_transport_lib::SolanaCommitment::Confirmed | ksp_onchain_transport_lib::SolanaCommitment::Finalized => {}, ksp_onchain_transport_lib::SolanaCommitment::Processed => { @@ -2021,8 +2028,8 @@ impl std::fmt::Debug for crate::RawTransactionIngestStandardBlockSource { /// Validated standard Solana `logsSubscribe` plus HTTP hydration source owned by the continuous RAW transaction ingest Worker. /// -/// The caller provides one Transport-owned standard WebSocket endpoint, one standard logs filter, a Confirmed/Finalized commitment and one HTTP hydration -/// pool/role. The source keeps the WebSocket URL and filter private, never copies remote logs/errors into Worker state, and emits only signature/slot +/// The caller provides one Transport-owned standard WebSocket endpoint explicitly declaring `Logs`, one standard logs filter, a Confirmed/Finalized commitment +/// and one HTTP hydration pool/role. The source keeps the WebSocket URL and filter private, never copies remote logs/errors into Worker state, and emits only signature/slot /// references into the source-neutral hydration coordinator. pub struct RawTransactionIngestStandardLogsSource { ws_endpoint: ksp_onchain_transport_lib::WsEndpointSettings, @@ -2052,6 +2059,9 @@ impl crate::RawTransactionIngestStandardLogsSource { if ws_endpoint.protocol() != ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard { return std::result::Result::Err(crate::runtime_error("runtime_resources.standard_logs_protocol_invalid")); } + if !ws_endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Logs) { + return std::result::Result::Err(crate::runtime_error("runtime_resources.standard_logs_capability_missing")); + } match commitment { ksp_onchain_transport_lib::SolanaCommitment::Confirmed | ksp_onchain_transport_lib::SolanaCommitment::Finalized => {}, ksp_onchain_transport_lib::SolanaCommitment::Processed => { diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs b/crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs index a6b064d..b94b469 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs +++ b/crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs @@ -1,5 +1,5 @@ // file: crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs -// version: 34 +// version: 35 fn grpc_endpoint(cluster: &str) -> std::option::Option { return grpc_endpoint_with_identity(cluster, "yellowstone-fixture", "fixture-provider"); @@ -115,12 +115,48 @@ fn ws_endpoint( endpoint_name: &str, provider: &str, protocol: ksp_onchain_transport_lib::WsProtocolKind, +) -> std::option::Option { + let capabilities = if protocol == ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard { + std::vec![ + ksp_onchain_transport_lib::WsSubscriptionKind::Account, + ksp_onchain_transport_lib::WsSubscriptionKind::Block, + ksp_onchain_transport_lib::WsSubscriptionKind::Logs, + ksp_onchain_transport_lib::WsSubscriptionKind::Program, + ksp_onchain_transport_lib::WsSubscriptionKind::Root, + ksp_onchain_transport_lib::WsSubscriptionKind::Signature, + ksp_onchain_transport_lib::WsSubscriptionKind::Slot, + ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates, + ksp_onchain_transport_lib::WsSubscriptionKind::Vote, + ] + } else if protocol == ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream { + std::vec![ + ksp_onchain_transport_lib::WsSubscriptionKind::Account, + ksp_onchain_transport_lib::WsSubscriptionKind::Logs, + ksp_onchain_transport_lib::WsSubscriptionKind::Program, + ksp_onchain_transport_lib::WsSubscriptionKind::Root, + ksp_onchain_transport_lib::WsSubscriptionKind::Signature, + ksp_onchain_transport_lib::WsSubscriptionKind::Slot, + ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates, + ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction, + ] + } else { + return std::option::Option::None; + }; + return ws_endpoint_with_capabilities(cluster, endpoint_name, provider, protocol, std::option::Option::Some(capabilities)); +} + +fn ws_endpoint_with_capabilities( + cluster: &str, + endpoint_name: &str, + provider: &str, + protocol: ksp_onchain_transport_lib::WsProtocolKind, + capabilities: std::option::Option>, ) -> std::option::Option { let url = match ksp_onchain_transport_lib::WsEndpointUrl::parse("ws://127.0.0.1:10001/WS-SECRET-CANARY") { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; - return std::option::Option::Some(ksp_onchain_transport_lib::WsEndpointSettings::new( + let endpoint = ksp_onchain_transport_lib::WsEndpointSettings::new( endpoint_name, true, ksp_onchain_transport_lib::WsProviderName::new(provider), @@ -128,7 +164,11 @@ fn ws_endpoint( protocol, url, ksp_onchain_transport_lib::WsSessionSettings::default(), - )); + ); + return std::option::Option::Some(match capabilities { + std::option::Option::Some(value) => endpoint.with_subscription_capabilities(value), + std::option::Option::None => endpoint, + }); } fn supervisor_contracts( @@ -1971,6 +2011,159 @@ fn pre_006_coalescence_key_separates_network_signature_and_commitment() { return; } +#[test] +fn v0_3_15_pre_004_websocket_route_constructors_require_explicit_capability_before_io() { + let hydration_pool = match http_pool("devnet", "hydration", "get_transaction") { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + let undeclared_logs = match ws_endpoint_with_capabilities( + "devnet", + "standard-logs-undeclared", + "fixture-ws-provider", + ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, + std::option::Option::None, + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + let undeclared_logs = crate::RawTransactionIngestStandardLogsSource::new( + undeclared_logs, + ksp_onchain_transport_lib::SolanaLogsSubscribeFilter::All, + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + hydration_pool.clone(), + ksp_onchain_transport_lib::HttpRoleName::new("hydration"), + ); + let undeclared_logs = match undeclared_logs { + std::result::Result::Ok(_) => return, + std::result::Result::Err(value) => value, + }; + assert!(undeclared_logs.context().iter().any(|context| return context.value() == "runtime_resources.standard_logs_capability_missing")); + let wrong_logs = match ws_endpoint_with_capabilities( + "devnet", + "standard-logs-wrong", + "fixture-ws-provider", + ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, + std::option::Option::Some(std::vec![ksp_onchain_transport_lib::WsSubscriptionKind::Slot]), + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + let wrong_logs = crate::RawTransactionIngestStandardLogsSource::new( + wrong_logs, + ksp_onchain_transport_lib::SolanaLogsSubscribeFilter::All, + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + hydration_pool.clone(), + ksp_onchain_transport_lib::HttpRoleName::new("hydration"), + ); + let wrong_logs = match wrong_logs { + std::result::Result::Ok(_) => return, + std::result::Result::Err(value) => value, + }; + assert!(wrong_logs.context().iter().any(|context| return context.value() == "runtime_resources.standard_logs_capability_missing")); + let logs = match ws_endpoint_with_capabilities( + "devnet", + "standard-logs-exact", + "fixture-ws-provider", + ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, + std::option::Option::Some(std::vec![ksp_onchain_transport_lib::WsSubscriptionKind::Logs]), + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + assert!( + crate::RawTransactionIngestStandardLogsSource::new( + logs, + ksp_onchain_transport_lib::SolanaLogsSubscribeFilter::All, + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + hydration_pool.clone(), + ksp_onchain_transport_lib::HttpRoleName::new("hydration"), + ) + .is_ok() + ); + let undeclared_block = match ws_endpoint_with_capabilities( + "devnet", + "standard-block-undeclared", + "fixture-ws-provider", + ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, + std::option::Option::None, + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + let undeclared_block = crate::RawTransactionIngestStandardBlockSource::new( + undeclared_block, + ksp_onchain_transport_lib::SolanaBlockSubscribeFilter::All, + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + ); + let undeclared_block = match undeclared_block { + std::result::Result::Ok(_) => return, + std::result::Result::Err(value) => value, + }; + assert!(undeclared_block.context().iter().any(|context| return context.value() == "runtime_resources.standard_block_capability_missing")); + let block = match ws_endpoint_with_capabilities( + "devnet", + "standard-block-exact", + "fixture-ws-provider", + ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, + std::option::Option::Some(std::vec![ksp_onchain_transport_lib::WsSubscriptionKind::Block]), + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + assert!( + crate::RawTransactionIngestStandardBlockSource::new( + block, + ksp_onchain_transport_lib::SolanaBlockSubscribeFilter::All, + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + ) + .is_ok() + ); + let missing_helius = match ws_endpoint_with_capabilities( + "devnet", + "helius-transaction-missing", + "fixture-helius-provider", + ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream, + std::option::Option::Some(std::vec![ksp_onchain_transport_lib::WsSubscriptionKind::Logs]), + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + let missing_helius = crate::RawTransactionIngestHeliusTransactionSource::new( + missing_helius, + helius_transaction_filter(false), + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + hydration_pool.clone(), + ksp_onchain_transport_lib::HttpRoleName::new("hydration"), + ); + let missing_helius = match missing_helius { + std::result::Result::Ok(_) => return, + std::result::Result::Err(value) => value, + }; + assert!(missing_helius.context().iter().any(|context| return context.value() == "runtime_resources.helius_transaction_capability_missing")); + let helius = match ws_endpoint_with_capabilities( + "devnet", + "helius-transaction-exact", + "fixture-helius-provider", + ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream, + std::option::Option::Some(std::vec![ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction]), + ) { + std::option::Option::Some(value) => value, + std::option::Option::None => return, + }; + assert!( + crate::RawTransactionIngestHeliusTransactionSource::new( + helius, + helius_transaction_filter(false), + ksp_onchain_transport_lib::SolanaCommitment::Confirmed, + hydration_pool, + ksp_onchain_transport_lib::HttpRoleName::new("hydration"), + ) + .is_ok() + ); + return; +} + #[test] fn v0_3_13_pre_003_standard_logs_source_validates_protocol_commitment_and_hydration_route() { let accepted = standard_logs_source( diff --git a/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md b/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md index 96bf54d..34fc7ea 100644 --- a/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md +++ b/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md @@ -1,5 +1,5 @@ - + # Plan v0.3.15 — Raw Transaction Ingest Desk @@ -702,6 +702,8 @@ Budget cible : une tranche Config. Faire refuser avant I/O les constructions de sources dont les capabilities WS requises ne sont pas déclarées, avec canaris des constructeurs de routes. Aucune logique provider dans la Desk. +**État : implémenté.** Les constructeurs `Standard Logs`, `Standard Block` et `Helius Transaction` interrogent désormais uniquement `WsEndpointSettings::supports_subscription(...)` après validation du protocole et avant toute ouverture de session. L'état legacy `undeclared` est donc refusé fail-closed par le Worker. Yellowstone et HTTP Block Polling restent hors de ce gate car ils n'ouvrent aucune source WS. Aucun type Worker public ni dépendance Config n'est ajouté. + Budget cible : une tranche Worker. ### `pre.005` — scaffold Raw Transaction Ingest Desk