From bd376dc479b246ff3b80380d507d7e029392202e Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sun, 13 Sep 2026 08:11:35 +0200 Subject: [PATCH] v0.3.15-pre.003 --- Cargo.toml | 4 +- ...e.ksp-app-raw-transaction-ingest-desk.json | 146 ++++++++ config/examples/std.transport.example.json | 34 +- config/schemas/std.transport.schema.json | 20 ++ config/std.transport.json | 162 ++++++++- crates/ksp-app-backfill-desk/tauri.conf.json | 1 + .../tests/desktop_contract.rs | 5 +- crates/ksp-app-config-desk/tauri.conf.json | 1 + .../tests/desktop_contract.rs | 8 +- .../unit_tests/profiles.rs | 5 +- crates/ksp-app-solprices-desk/tauri.conf.json | 1 + .../tests/desktop_contract.rs | 10 +- crates/ksp-app-store-desk/tauri.conf.json | 1 + .../tests/desktop_contract.rs | 5 +- crates/ksp-app-wallet-desk/tauri.conf.json | 1 + .../tests/desktop_contract.rs | 8 +- .../tests/release_compliance.rs | 4 +- crates/ksp-config-lib/README.md | 8 +- crates/ksp-config-lib/USAGE.md | 9 +- crates/ksp-config-lib/src/lib.rs | 6 +- crates/ksp-config-lib/src/registry.rs | 17 +- crates/ksp-config-lib/src/transport.rs | 45 ++- crates/ksp-config-lib/tests/ownership.rs | 3 +- crates/ksp-config-lib/tests/public_api.rs | 37 +- crates/ksp-config-lib/unit_tests/composite.rs | 67 +++- ...e.ksp-app-raw-transaction-ingest-desk.json | 146 ++++++++ .../unit_tests/fixtures/std.transport.json | 34 +- crates/ksp-config-lib/unit_tests/registry.rs | 62 ++-- crates/ksp-config-lib/unit_tests/transport.rs | 75 +++- deltas/0.3.15/pre.003.md | 333 ++++++++++++++++++ ...0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md | 39 +- ...032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md | 6 +- 32 files changed, 1198 insertions(+), 105 deletions(-) create mode 100644 config/composite.ksp-app-raw-transaction-ingest-desk.json create mode 100644 crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-raw-transaction-ingest-desk.json create mode 100644 deltas/0.3.15/pre.003.md diff --git a/Cargo.toml b/Cargo.toml index 1011abd..f20ddee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 596 +# version: 597 [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.2.fix.1" +version = "0.3.15-pre.3" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/config/composite.ksp-app-raw-transaction-ingest-desk.json b/config/composite.ksp-app-raw-transaction-ingest-desk.json new file mode 100644 index 0000000..3f3f4db --- /dev/null +++ b/config/composite.ksp-app-raw-transaction-ingest-desk.json @@ -0,0 +1,146 @@ +{ + "format_version": 1, + "default_profile": "devnet_public", + "profiles": [ + { + "profile_id": "devnet_public", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "devnet_public" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "helius_devnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "helius_devnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "orbitflare_devnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "orbitflare_devnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "mainnet_public", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "mainnet_public" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "helius_mainnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "helius_mainnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "publicnode_mainnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "publicnode_mainnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "publicnode_testnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "supertrace" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "publicnode_testnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "testnet" + } + ] + } + ] +} diff --git a/config/examples/std.transport.example.json b/config/examples/std.transport.example.json index 5d244eb..48e60c9 100644 --- a/config/examples/std.transport.example.json +++ b/config/examples/std.transport.example.json @@ -87,7 +87,15 @@ "provider": "solana-public", "cluster": "mainnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] }, { "name": "mainnet_helius_ws", @@ -99,7 +107,17 @@ "session": { "notification_queue_capacity": 512, "max_active_subscriptions": 2048 - } + }, + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] }, @@ -140,7 +158,17 @@ "provider": "helius", "cluster": "devnet", "kind": "helius_laserstream", - "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}" + "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] } diff --git a/config/schemas/std.transport.schema.json b/config/schemas/std.transport.schema.json index 7a35cf6..bfce5a5 100644 --- a/config/schemas/std.transport.schema.json +++ b/config/schemas/std.transport.schema.json @@ -348,6 +348,26 @@ }, "session": { "$ref": "#/$defs/wsSessionOverride" + }, + "capabilities": { + "type": "array", + "minItems": 1, + "maxItems": 10, + "uniqueItems": true, + "items": { + "enum": [ + "account", + "block", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "vote", + "helius_transaction" + ] + } } } }, diff --git a/config/std.transport.json b/config/std.transport.json index 21ac4da..075bf88 100644 --- a/config/std.transport.json +++ b/config/std.transport.json @@ -75,7 +75,66 @@ "provider": "solana-public", "cluster": "devnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_DEVNET_WS_URL:-wss://api.devnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_DEVNET_WS_URL:-wss://api.devnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] + } + ] + }, + { + "profile_id": "helius_devnet", + "endpoints": [ + { + "name": "solana_devnet_public", + "enabled": true, + "provider": "solana-public", + "cluster": "devnet", + "url": "${KSP_PUBLIC_SOLANA_DEVNET_HTTP_URL:-https://api.devnet.solana.com}", + "connect_timeout_ms": 5000, + "request_timeout_ms": 15000, + "max_idle_connections_per_host": 8, + "roles": [ + { + "role": "default", + "enabled": true, + "request_kinds": [ + "*" + ], + "priority": 100, + "limits": { + "requests_per_second": 5, + "burst_capacity": 10, + "max_concurrent_requests": 8, + "pause_after_rate_limit_ms": 1000 + } + } + ] + } + ], + "ws_endpoints": [ + { + "name": "helius_devnet_ws", + "enabled": true, + "provider": "helius", + "cluster": "devnet", + "kind": "helius_laserstream", + "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] }, @@ -116,7 +175,15 @@ "provider": "solana-public", "cluster": "devnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_DEVNET_WS_URL:-wss://api.devnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_DEVNET_WS_URL:-wss://api.devnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] } ], "grpc_endpoints": [ @@ -174,7 +241,66 @@ "provider": "solana-public", "cluster": "mainnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] + } + ] + }, + { + "profile_id": "helius_mainnet", + "endpoints": [ + { + "name": "solana_mainnet_public", + "enabled": true, + "provider": "solana-public", + "cluster": "mainnet", + "url": "${KSP_PUBLIC_SOLANA_MAINNET_HTTP_URL:-https://api.mainnet.solana.com}", + "connect_timeout_ms": 5000, + "request_timeout_ms": 15000, + "max_idle_connections_per_host": 8, + "roles": [ + { + "role": "default", + "enabled": true, + "request_kinds": [ + "*" + ], + "priority": 100, + "limits": { + "requests_per_second": 5, + "burst_capacity": 10, + "max_concurrent_requests": 8, + "pause_after_rate_limit_ms": 1000 + } + } + ] + } + ], + "ws_endpoints": [ + { + "name": "helius_mainnet_ws", + "enabled": true, + "provider": "helius", + "cluster": "mainnet", + "kind": "helius_laserstream", + "url": "wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] }, @@ -269,7 +395,15 @@ "provider": "solana-public", "cluster": "mainnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] } ] }, @@ -310,7 +444,15 @@ "provider": "solana-public", "cluster": "mainnet", "kind": "solana_standard", - "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}" + "url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet.solana.com}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] } ], "grpc_endpoints": [ @@ -367,7 +509,15 @@ "provider": "solana-public", "cluster": "testnet", "kind": "solana_standard", - "url": "wss://api.testnet.solana.com" + "url": "wss://api.testnet.solana.com", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] } ], "grpc_endpoints": [ diff --git a/crates/ksp-app-backfill-desk/tauri.conf.json b/crates/ksp-app-backfill-desk/tauri.conf.json index 3a7b78f..c25737f 100644 --- a/crates/ksp-app-backfill-desk/tauri.conf.json +++ b/crates/ksp-app-backfill-desk/tauri.conf.json @@ -53,6 +53,7 @@ ], "resources": { "../../config/composite.ksp-app-backfill-desk.json": "config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json": "config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json": "config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-backfill-desk/tests/desktop_contract.rs b/crates/ksp-app-backfill-desk/tests/desktop_contract.rs index 68cc661..7e092bb 100644 --- a/crates/ksp-app-backfill-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-backfill-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs -// version: 17 +// version: 18 //! Structural desktop contract checks for the Backfill Desk scaffold. @@ -145,9 +145,10 @@ fn pre_003_composite_packaging_follows_atomic_config_registry_contract() { std::option::Option::Some(value) => value, std::option::Option::None => return, }; - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); for required in [ "../../config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-config-desk/tauri.conf.json b/crates/ksp-app-config-desk/tauri.conf.json index 192ddc2..37d6e5e 100644 --- a/crates/ksp-app-config-desk/tauri.conf.json +++ b/crates/ksp-app-config-desk/tauri.conf.json @@ -53,6 +53,7 @@ ], "resources": { "../../config/composite.ksp-app-backfill-desk.json": "config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json": "config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json": "config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-config-desk/tests/desktop_contract.rs b/crates/ksp-app-config-desk/tests/desktop_contract.rs index 06e48e6..bdd8d90 100644 --- a/crates/ksp-app-config-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-config-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-config-desk/tests/desktop_contract.rs -// version: 13 +// version: 14 //! Desktop build/shell contract audits for Config Desk. @@ -110,11 +110,15 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writab let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); assert!(resources.is_some(), "packaged Config resources map must exist"); if let std::option::Option::Some(resources) = resources { - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); assert_eq!( resources.get("../../config/composite.ksp-app-backfill-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-backfill-desk.json"), ); + assert_eq!( + resources.get("../../config/composite.ksp-app-raw-transaction-ingest-desk.json").and_then(serde_json::Value::as_str), + std::option::Option::Some("config/composite.ksp-app-raw-transaction-ingest-desk.json"), + ); assert_eq!( resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"), diff --git a/crates/ksp-app-config-desk/unit_tests/profiles.rs b/crates/ksp-app-config-desk/unit_tests/profiles.rs index b2458fa..b48305e 100644 --- a/crates/ksp-app-config-desk/unit_tests/profiles.rs +++ b/crates/ksp-app-config-desk/unit_tests/profiles.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-config-desk/unit_tests/profiles.rs -// version: 8 +// version: 9 #[test] fn profile_inventory_exposes_registered_profile_documents() { @@ -21,6 +21,9 @@ fn profile_inventory_exposes_registered_profile_documents() { assert!(inventory.iter().any(|document| -> bool { return document.file_id == ksp_config_lib::FILE_ID_STD_WALLET; })); + assert!(inventory.iter().any(|document| -> bool { + return document.file_id == ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK; + })); assert!(inventory.iter().any(|document| -> bool { return document.file_id == ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK; })); diff --git a/crates/ksp-app-solprices-desk/tauri.conf.json b/crates/ksp-app-solprices-desk/tauri.conf.json index 74ffd60..8722785 100644 --- a/crates/ksp-app-solprices-desk/tauri.conf.json +++ b/crates/ksp-app-solprices-desk/tauri.conf.json @@ -53,6 +53,7 @@ ], "resources": { "../../config/composite.ksp-app-backfill-desk.json": "config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json": "config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json": "config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-solprices-desk/tests/desktop_contract.rs b/crates/ksp-app-solprices-desk/tests/desktop_contract.rs index a949d87..43b487d 100644 --- a/crates/ksp-app-solprices-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-solprices-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs -// version: 12 +// version: 13 //! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`. @@ -85,17 +85,21 @@ fn pre_002_package_is_mixed_lib_bin_and_frontend_is_scaffold_only() { } #[test] -fn v0_3_8_pre_006_packaging_contains_current_fifteen_config_resources() { +fn v0_3_8_pre_006_packaging_contains_current_sixteen_config_resources() { let root = app_root(); let tauri = read_json(root.join("tauri.conf.json").as_path()); let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); assert!(resources.is_some()); if let std::option::Option::Some(resources) = resources { - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); assert_eq!( resources.get("../../config/composite.ksp-app-backfill-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-backfill-desk.json"), ); + assert_eq!( + resources.get("../../config/composite.ksp-app-raw-transaction-ingest-desk.json").and_then(serde_json::Value::as_str), + std::option::Option::Some("config/composite.ksp-app-raw-transaction-ingest-desk.json"), + ); assert_eq!( resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"), diff --git a/crates/ksp-app-store-desk/tauri.conf.json b/crates/ksp-app-store-desk/tauri.conf.json index 960377b..77ebccb 100644 --- a/crates/ksp-app-store-desk/tauri.conf.json +++ b/crates/ksp-app-store-desk/tauri.conf.json @@ -53,6 +53,7 @@ ], "resources": { "../../config/composite.ksp-app-backfill-desk.json": "config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json": "config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json": "config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-store-desk/tests/desktop_contract.rs b/crates/ksp-app-store-desk/tests/desktop_contract.rs index 19e06dd..503d6d2 100644 --- a/crates/ksp-app-store-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-store-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-store-desk/tests/desktop_contract.rs -// version: 10 +// version: 11 //! Desktop template and frontend contract tests for the Store Desk scaffold. @@ -153,7 +153,8 @@ fn pre_006_composite_and_packaged_resources_cover_store_desk_and_the_complete_co let resources = tauri["bundle"]["resources"].as_object(); assert!(resources.is_some()); if let std::option::Option::Some(resources) = resources { - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); + assert!(resources.contains_key("../../config/composite.ksp-app-raw-transaction-ingest-desk.json")); assert!(resources.contains_key("../../config/composite.ksp-app-store-desk.json")); assert!(resources.contains_key("../../config/std.store.json")); assert!(resources.contains_key("../../config/schemas/std.store.schema.json")); diff --git a/crates/ksp-app-wallet-desk/tauri.conf.json b/crates/ksp-app-wallet-desk/tauri.conf.json index 7a47b7b..f0678f2 100644 --- a/crates/ksp-app-wallet-desk/tauri.conf.json +++ b/crates/ksp-app-wallet-desk/tauri.conf.json @@ -53,6 +53,7 @@ ], "resources": { "../../config/composite.ksp-app-backfill-desk.json": "config/composite.ksp-app-backfill-desk.json", + "../../config/composite.ksp-app-raw-transaction-ingest-desk.json": "config/composite.ksp-app-raw-transaction-ingest-desk.json", "../../config/composite.ksp-app-solprices-desk.json": "config/composite.ksp-app-solprices-desk.json", "../../config/composite.ksp-app-store-desk.json": "config/composite.ksp-app-store-desk.json", "../../config/composite.ksp-app-wallet-desk.json": "config/composite.ksp-app-wallet-desk.json", diff --git a/crates/ksp-app-wallet-desk/tests/desktop_contract.rs b/crates/ksp-app-wallet-desk/tests/desktop_contract.rs index bc84f67..2c94bd2 100644 --- a/crates/ksp-app-wallet-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-wallet-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs -// version: 33 +// version: 34 //! Desktop build, shell and Config-status contract audits for Wallet Desk. @@ -432,11 +432,15 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist"); if let std::option::Option::Some(resources) = resources { - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); assert_eq!( resources.get("../../config/composite.ksp-app-backfill-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-backfill-desk.json"), ); + assert_eq!( + resources.get("../../config/composite.ksp-app-raw-transaction-ingest-desk.json").and_then(serde_json::Value::as_str), + std::option::Option::Some("config/composite.ksp-app-raw-transaction-ingest-desk.json"), + ); assert_eq!( resources.get("../../config/composite.ksp-app-solprices-desk.json").and_then(serde_json::Value::as_str), std::option::Option::Some("config/composite.ksp-app-solprices-desk.json"), diff --git a/crates/ksp-app-wallet-desk/tests/release_compliance.rs b/crates/ksp-app-wallet-desk/tests/release_compliance.rs index 05d914c..b587dbc 100644 --- a/crates/ksp-app-wallet-desk/tests/release_compliance.rs +++ b/crates/ksp-app-wallet-desk/tests/release_compliance.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/tests/release_compliance.rs -// version: 12 +// version: 13 //! Release-wide deterministic compliance canaries for Wallet Desk. @@ -199,7 +199,7 @@ fn packaged_resources_include_only_registered_config_sources_and_schemas() { std::option::Option::Some(value) => value, std::option::Option::None => return, }; - assert_eq!(resources.len(), 15); + assert_eq!(resources.len(), 16); for (source, destination) in resources { let destination = destination.as_str(); assert!(destination.is_some(), "resource destination must be textual"); diff --git a/crates/ksp-config-lib/README.md b/crates/ksp-config-lib/README.md index 7133819..a6232bd 100644 --- a/crates/ksp-config-lib/README.md +++ b/crates/ksp-config-lib/README.md @@ -1,5 +1,5 @@ - + # ksp-config-lib @@ -35,8 +35,9 @@ La crate centralise les documents JSON, leurs schemas, les profils et compositio Le registre par défaut connaît : ```text -cfg.composite.ksp-app-backfill-desk -> config/composite.ksp-app-backfill-desk.json -cfg.composite.ksp-app-solprices-desk -> config/composite.ksp-app-solprices-desk.json +cfg.composite.ksp-app-backfill-desk -> config/composite.ksp-app-backfill-desk.json +cfg.composite.ksp-app-raw-transaction-ingest-desk -> config/composite.ksp-app-raw-transaction-ingest-desk.json +cfg.composite.ksp-app-solprices-desk -> config/composite.ksp-app-solprices-desk.json cfg.composite.ksp-app-store-desk -> config/composite.ksp-app-store-desk.json cfg.composite.ksp-app-wallet-desk -> config/composite.ksp-app-wallet-desk.json cfg.std.logging -> config/std.logging.json @@ -103,6 +104,7 @@ Le document Logging refuse les valeurs de sensibilité `Secret` dans sa configur - [`../../config/std.store.json`](../../config/std.store.json) — targets Store PostgreSQL Devnet/Mainnet/Testnet et settings runtime bornés ; - [`../../config/std.wallet.json`](../../config/std.wallet.json) — racine Wallet globale et sous-répertoire optionnel par profil ; - [`../../config/composite.ksp-app-backfill-desk.json`](../../config/composite.ksp-app-backfill-desk.json) — composition Logging/Transport/Store de Backfill Desk ; +- [`../../config/composite.ksp-app-raw-transaction-ingest-desk.json`](../../config/composite.ksp-app-raw-transaction-ingest-desk.json) — profils cohérents Logging/Transport/Store du Raw Transaction Ingest Desk ; - [`../../config/composite.ksp-app-solprices-desk.json`](../../config/composite.ksp-app-solprices-desk.json) — composition Logging/Off-chain Transport de SOL Prices Desk ; - [`../../config/composite.ksp-app-store-desk.json`](../../config/composite.ksp-app-store-desk.json) — composition Logging/Store de Store Desk ; - [`../../config/composite.ksp-app-wallet-desk.json`](../../config/composite.ksp-app-wallet-desk.json) — composition Logging/Off-chain Transport/On-chain Transport/Wallet de Wallet Desk ; diff --git a/crates/ksp-config-lib/USAGE.md b/crates/ksp-config-lib/USAGE.md index 2bc09b8..68f392d 100644 --- a/crates/ksp-config-lib/USAGE.md +++ b/crates/ksp-config-lib/USAGE.md @@ -1,5 +1,5 @@ - + # Utilisation de ksp-config-lib @@ -28,6 +28,7 @@ Les arguments compris par Config sont : ```text --cfgpath=/path/to/config --schemapath=/path/to/schemas +--filemap=cfg.composite.ksp-app-raw-transaction-ingest-desk=my-raw-ingest-desk.json --filemap=cfg.composite.ksp-app-solprices-desk=my-solprices-desk.json --filemap=cfg.composite.ksp-app-wallet-desk=my-wallet-desk.json --filemap=cfg.std.logging=my-logging.json @@ -161,7 +162,9 @@ Le provider affiche `solana-yellowstone-grpc.publicnode.com:443` ; le profil ver L'accesseur historique `into_transport_settings()` conserve volontairement son tuple `(HTTP, Option)`. Un consumer ayant besoin des trois backends utilise `into_all_transport_settings()` ou les accesseurs séparés afin de ne pas casser silencieusement les consumers V2. -Les protocoles WebSocket restent `kind = "solana_standard"` et `kind = "helius_laserstream"`. Helius LaserStream WebSocket conserve ses URLs Config-owned et sa clé `KSP_SECRET_HELIUS_API_KEY`; cette surface est indépendante de Yellowstone gRPC. +Les protocoles WebSocket restent `kind = "solana_standard"` et `kind = "helius_laserstream"`. Chaque endpoint peut en plus déclarer `capabilities`, liste de descriptors `WsSubscriptionKind` (`account`, `block`, `logs`, `program`, `root`, `signature`, `slot`, `slots_updates`, `vote`, `helius_transaction`). L'absence de cette liste reste backward-compatible mais ne constitue aucune preuve de support ; une liste présente est mappée explicitement vers Transport puis validée contre le protocole. Config ne déduit jamais une capability depuis `provider`. + +Les profils Solana standard versionnés déclarent conservativement les six familles stables `account/logs/program/root/signature/slot` et ne déclarent donc pas `block`. Les profils `helius_devnet` et `helius_mainnet` déclarent les sept familles Helius déjà supportées par la façade (`account/logs/program/root/signature/slot/slots_updates`) plus `helius_transaction`, sans `block` ni `vote`. Helius LaserStream WebSocket conserve ses URLs Config-owned et sa clé `KSP_SECRET_HELIUS_API_KEY`; cette surface est indépendante de Yellowstone gRPC. Les scalaires `*_ms` restent des valeurs Config et sont convertis en `std::time::Duration` par l'adapter. La dépendance reste unidirectionnelle : Config connaît les contrats Transport pour les construire ; Transport ne connaît ni Config, ni `.env`, ni les variables KSP. @@ -289,7 +292,7 @@ let component = match composite.component("wallet") { let wallet = engine.resolve_wallet_config_profile(component.resolved(), &environment); ``` -La même forme existe pour Logging via `resolve_logging_config_profile`. Le composite `cfg.composite.ksp-app-solprices-desk` référence `logging` et `offchain_transport`. Le composite `cfg.composite.ksp-app-wallet-desk` référence `logging`, `offchain_transport`, `transport` et `wallet`; chaque application valide ses frontières de composition au bootstrap. +La même forme existe pour Logging via `resolve_logging_config_profile`. Le composite `cfg.composite.ksp-app-raw-transaction-ingest-desk` référence exactement `logging`, `transport` et `store`; ses profils couplent explicitement un profil Transport et un profil Store du même réseau logique (`devnet`, `mainnet` ou `testnet`) afin que l'application n'assemble jamais arbitrairement deux réseaux. Le composite `cfg.composite.ksp-app-solprices-desk` référence `logging` et `offchain_transport`. Le composite `cfg.composite.ksp-app-wallet-desk` référence `logging`, `offchain_transport`, `transport` et `wallet`; chaque application valide ses frontières de composition au bootstrap. ## 6. Management de `std.logging.json` diff --git a/crates/ksp-config-lib/src/lib.rs b/crates/ksp-config-lib/src/lib.rs index 3bfebaf..cde0274 100644 --- a/crates/ksp-config-lib/src/lib.rs +++ b/crates/ksp-config-lib/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/src/lib.rs -// version: 23 +// version: 24 #![warn(missing_docs)] #![deny(unreachable_pub)] @@ -153,6 +153,8 @@ pub use self::registry::ConfigFileKind; pub use self::registry::ConfigFileRegistry; /// Default physical filename for the Backfill Desk composite configuration document. pub use self::registry::DEFAULT_COMPOSITE_KSP_APP_BACKFILL_DESK_FILENAME; +/// Default physical filename for the Raw Transaction Ingest Desk composite configuration document. +pub use self::registry::DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME; /// Default physical filename for the SOL Prices Desk composite configuration document. pub use self::registry::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME; /// Default physical filename for the Store Desk composite configuration document. @@ -183,6 +185,8 @@ pub use self::registry::DEFAULT_STD_WALLET_FILENAME; pub use self::registry::DEFAULT_STD_WALLET_SCHEMA_FILENAME; /// Logical file identifier for the Backfill Desk composite configuration document. pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK; +/// Logical file identifier for the Raw Transaction Ingest Desk composite configuration document. +pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK; /// Logical file identifier for the SOL Prices Desk composite configuration document. pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK; /// Logical file identifier for the Store Desk composite configuration document. diff --git a/crates/ksp-config-lib/src/registry.rs b/crates/ksp-config-lib/src/registry.rs index b0494f8..73cc91f 100644 --- a/crates/ksp-config-lib/src/registry.rs +++ b/crates/ksp-config-lib/src/registry.rs @@ -1,10 +1,12 @@ // file: crates/ksp-config-lib/src/registry.rs -// version: 15 +// version: 16 /// Bootstrap argument used to replace a known Config filename mapping. pub const ARG_FILE_MAP: &str = "--filemap"; /// Default physical filename for the Backfill Desk composite configuration document. pub const DEFAULT_COMPOSITE_KSP_APP_BACKFILL_DESK_FILENAME: &str = "composite.ksp-app-backfill-desk.json"; +/// Default physical filename for the Raw Transaction Ingest Desk composite configuration document. +pub const DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME: &str = "composite.ksp-app-raw-transaction-ingest-desk.json"; /// Default physical filename for the SOL Prices Desk composite configuration document. pub const DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME: &str = "composite.ksp-app-solprices-desk.json"; /// Default physical filename for the Store Desk composite configuration document. @@ -35,6 +37,8 @@ pub const DEFAULT_STD_WALLET_FILENAME: &str = "std.wallet.json"; pub const DEFAULT_STD_WALLET_SCHEMA_FILENAME: &str = "std.wallet.schema.json"; /// Logical file identifier for the Backfill Desk composite configuration document. pub const FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK: &str = "cfg.composite.ksp-app-backfill-desk"; +/// Logical file identifier for the Raw Transaction Ingest Desk composite configuration document. +pub const FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK: &str = "cfg.composite.ksp-app-raw-transaction-ingest-desk"; /// Logical file identifier for the SOL Prices Desk composite configuration document. pub const FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK: &str = "cfg.composite.ksp-app-solprices-desk"; /// Logical file identifier for the Store Desk composite configuration document. @@ -178,6 +182,16 @@ impl ConfigFileRegistry { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; + let raw_transaction_ingest_composite = ConfigFileDescriptor::new( + FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK, + ConfigFileKind::Config, + DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME, + std::option::Option::Some(FILE_ID_SCHEMA_COMPOSITE), + ); + let raw_transaction_ingest_composite = match raw_transaction_ingest_composite { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; let solprices_composite = ConfigFileDescriptor::new( FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK, ConfigFileKind::Config, @@ -300,6 +314,7 @@ impl ConfigFileRegistry { }; return crate::build_registry([ backfill_composite, + raw_transaction_ingest_composite, solprices_composite, store_desk_composite, wallet_composite, diff --git a/crates/ksp-config-lib/src/transport.rs b/crates/ksp-config-lib/src/transport.rs index 2673619..cd13f14 100644 --- a/crates/ksp-config-lib/src/transport.rs +++ b/crates/ksp-config-lib/src/transport.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/src/transport.rs -// version: 5 +// version: 6 /// Effective standard on-chain Transport configuration resolved from Config and mapped to HTTP plus optional WebSocket and Yellowstone gRPC runtime contracts. #[derive(Clone, Eq, PartialEq)] @@ -259,6 +259,8 @@ struct EffectiveWsEndpointSource { kind: String, url: String, #[serde(default)] + capabilities: std::option::Option>, + #[serde(default)] session: std::option::Option, } @@ -812,7 +814,7 @@ fn map_ws_endpoints( std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; - endpoints.push(ksp_onchain_transport_lib::WsEndpointSettings::new( + let mut endpoint = ksp_onchain_transport_lib::WsEndpointSettings::new( source.name, source.enabled, ksp_onchain_transport_lib::WsProviderName::new(source.provider), @@ -820,7 +822,20 @@ fn map_ws_endpoints( protocol, url, session, - )); + ); + if let std::option::Option::Some(capability_sources) = source.capabilities { + let mut capabilities = std::vec::Vec::::with_capacity(capability_sources.len()); + for capability_source in capability_sources { + let capability = map_ws_subscription_capability(capability_source.as_str(), profile, endpoint_name.as_str()); + let capability = match capability { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; + capabilities.push(capability); + } + endpoint = endpoint.with_subscription_capabilities(capabilities); + } + endpoints.push(endpoint); } return std::result::Result::Ok(endpoints); } @@ -841,6 +856,30 @@ fn map_ws_protocol_kind( }; } +fn map_ws_subscription_capability( + value: &str, + profile: &crate::ResolvedConfigProfile, + endpoint_name: &str, +) -> ksp_core_lib::Result { + return match value { + "account" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Account), + "block" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Block), + "logs" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Logs), + "program" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Program), + "root" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Root), + "signature" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Signature), + "slot" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Slot), + "slots_updates" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates), + "vote" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::Vote), + "helius_transaction" => std::result::Result::Ok(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction), + _ => std::result::Result::Err( + effective_error(profile, "effective WebSocket subscription capability is unsupported") + .with_context("endpoint_name", endpoint_name) + .with_context("ws_capability", value), + ), + }; +} + fn map_ws_session_settings( defaults: &EffectiveWsSessionSource, overrides: std::option::Option<&EffectiveWsSessionOverrideSource>, diff --git a/crates/ksp-config-lib/tests/ownership.rs b/crates/ksp-config-lib/tests/ownership.rs index 54cc213..9c4abe4 100644 --- a/crates/ksp-config-lib/tests/ownership.rs +++ b/crates/ksp-config-lib/tests/ownership.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/tests/ownership.rs -// version: 9 +// version: 10 //! Workspace ownership audits for KSP application configuration boundaries. @@ -262,6 +262,7 @@ fn workspace_crates_do_not_hardcode_config_managed_physical_files() { }; for token in [ "\".env\"", + "\"composite.ksp-app-raw-transaction-ingest-desk.json\"", "\"composite.ksp-app-solprices-desk.json\"", "\"composite.ksp-app-wallet-desk.json\"", "\"composite.schema.json\"", diff --git a/crates/ksp-config-lib/tests/public_api.rs b/crates/ksp-config-lib/tests/public_api.rs index b926a00..51c5ab4 100644 --- a/crates/ksp-config-lib/tests/public_api.rs +++ b/crates/ksp-config-lib/tests/public_api.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/tests/public_api.rs -// version: 28 +// version: 29 //! Integration tests for the public `ksp-config-lib` bootstrap, registry, JSON/profile/composite, environment-resolution, sensitivity, //! Logging/Transport/Store adapters and management contracts. @@ -80,23 +80,24 @@ fn registry_descriptor_inventory_is_available_from_crate_root() { assert!(registry.is_ok(), "public registry should remain constructible: {registry:?}"); if let std::result::Result::Ok(registry) = registry { let descriptors: std::vec::Vec<&ksp_config_lib::ConfigFileDescriptor> = registry.descriptors().collect(); - assert_eq!(descriptors.len(), 15); + assert_eq!(descriptors.len(), 16); assert_eq!(descriptors[0].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK); - assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK); - assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK); - assert_eq!(descriptors[3].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK); - assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING); - assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT); - assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_STD_STORE); - assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT); - assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET); - assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE); - assert_eq!(descriptors[10].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING); - assert_eq!(descriptors[11].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT); - assert_eq!(descriptors[12].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_STORE); - assert_eq!(descriptors[13].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT); - assert_eq!(descriptors[14].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET); - let schema_file_id = descriptors[8].schema_file_id(); + assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK); + assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK); + assert_eq!(descriptors[3].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK); + assert_eq!(descriptors[4].file_id().as_str(), ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK); + assert_eq!(descriptors[5].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING); + assert_eq!(descriptors[6].file_id().as_str(), ksp_config_lib::FILE_ID_STD_OFFCHAIN_TRANSPORT); + assert_eq!(descriptors[7].file_id().as_str(), ksp_config_lib::FILE_ID_STD_STORE); + assert_eq!(descriptors[8].file_id().as_str(), ksp_config_lib::FILE_ID_STD_TRANSPORT); + assert_eq!(descriptors[9].file_id().as_str(), ksp_config_lib::FILE_ID_STD_WALLET); + assert_eq!(descriptors[10].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE); + assert_eq!(descriptors[11].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING); + assert_eq!(descriptors[12].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT); + assert_eq!(descriptors[13].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_STORE); + assert_eq!(descriptors[14].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_TRANSPORT); + assert_eq!(descriptors[15].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET); + let schema_file_id = descriptors[9].schema_file_id(); assert!(schema_file_id.is_some(), "public Wallet descriptor should preserve schema association"); if let std::option::Option::Some(schema_file_id) = schema_file_id { assert_eq!(schema_file_id.as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_WALLET); @@ -167,6 +168,8 @@ fn composite_schema_and_provenance_contracts_are_available_from_crate_root() { } assert_eq!(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK, "cfg.composite.ksp-app-backfill-desk"); assert_eq!(ksp_config_lib::DEFAULT_COMPOSITE_KSP_APP_BACKFILL_DESK_FILENAME, "composite.ksp-app-backfill-desk.json"); + assert_eq!(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK, "cfg.composite.ksp-app-raw-transaction-ingest-desk"); + assert_eq!(ksp_config_lib::DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME, "composite.ksp-app-raw-transaction-ingest-desk.json"); assert_eq!(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK, "cfg.composite.ksp-app-solprices-desk"); assert_eq!(ksp_config_lib::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME, "composite.ksp-app-solprices-desk.json"); assert_eq!(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK, "cfg.composite.ksp-app-store-desk"); diff --git a/crates/ksp-config-lib/unit_tests/composite.rs b/crates/ksp-config-lib/unit_tests/composite.rs index b98f312..0d6a847 100644 --- a/crates/ksp-config-lib/unit_tests/composite.rs +++ b/crates/ksp-config-lib/unit_tests/composite.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/unit_tests/composite.rs -// version: 4 +// version: 5 const TEST_COMPOSITE_FILENAME: &str = "examples/composite.example.json"; const TEST_COMPOSITE_FILE_ID: &str = "cfg.composite.test"; @@ -128,6 +128,71 @@ fn duplicate_component_ids_are_rejected_inside_one_composite_profile() { cleanup_fixture(&fixture); } +#[test] +fn v0_3_15_pre_003_raw_ingest_composite_keeps_transport_and_store_networks_coherent() { + let workspace = workspace_root(); + let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas")); + assert!(bootstrap.is_ok(), "committed Config roots should be valid: {bootstrap:?}"); + let registry = crate::ConfigFileRegistry::defaults(); + assert!(registry.is_ok(), "default Config registry should be valid: {registry:?}"); + let file_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK); + assert!(file_id.is_ok(), "Raw Transaction Ingest Desk composite file_id should be valid: {file_id:?}"); + let (bootstrap, registry, file_id) = match (bootstrap, registry, file_id) { + (std::result::Result::Ok(bootstrap), std::result::Result::Ok(registry), std::result::Result::Ok(file_id)) => (bootstrap, registry, file_id), + _ => return, + }; + let engine = crate::ConfigDocumentEngine::new(bootstrap, registry); + let mut process = std::collections::BTreeMap::::new(); + process.insert("KSP_SECRET_HELIUS_API_KEY".to_owned(), "helius-composite-canary".to_owned()); + process.insert("KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN".to_owned(), "orbitflare-composite-canary".to_owned()); + process.insert("KSP_SECRET_PUBLICNODE_MAINNET_GRPC_X_TOKEN".to_owned(), "publicnode-mainnet-composite-canary".to_owned()); + process.insert("KSP_SECRET_PUBLICNODE_TESTNET_GRPC_X_TOKEN".to_owned(), "publicnode-testnet-composite-canary".to_owned()); + let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new()); + for (profile_id, expected_network) in [ + ("devnet_public", "devnet"), + ("helius_devnet", "devnet"), + ("orbitflare_devnet", "devnet"), + ("mainnet_public", "mainnet"), + ("helius_mainnet", "mainnet"), + ("publicnode_mainnet", "mainnet"), + ("publicnode_testnet", "testnet"), + ] { + let composite = engine.load_resolved_composite(&file_id, std::option::Option::Some(profile_id)); + assert!(composite.is_ok(), "Raw Ingest composite profile {profile_id} should resolve: {composite:?}"); + let composite = match composite { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => continue, + }; + assert_eq!(composite.profile_id(), profile_id); + let transport_component = composite.component("transport"); + let store_component = composite.component("store"); + assert!(transport_component.is_some(), "profile {profile_id} should contain Transport"); + assert!(store_component.is_some(), "profile {profile_id} should contain Store"); + let (transport_component, store_component) = match (transport_component, store_component) { + (std::option::Option::Some(transport), std::option::Option::Some(store)) => (transport, store), + _ => continue, + }; + assert_eq!(transport_component.resolved().profile_id(), profile_id); + assert_eq!(store_component.resolved().profile_id(), expected_network); + let transport = engine.resolve_transport_config_profile(transport_component.resolved(), &environment); + let store = engine.resolve_store_config_profile(store_component.resolved(), &environment); + assert!(transport.is_ok(), "Transport profile {profile_id} should map: {transport:?}"); + assert!(store.is_ok(), "Store profile {expected_network} should map: {store:?}"); + let (transport, store) = match (transport, store) { + (std::result::Result::Ok(transport), std::result::Result::Ok(store)) => (transport, store), + _ => continue, + }; + assert_eq!(store.settings().network().as_str(), expected_network); + assert!(transport.http_settings().endpoints().iter().all(|endpoint| return endpoint.cluster().as_str() == expected_network)); + if let std::option::Option::Some(ws) = transport.ws_settings() { + assert!(ws.endpoints().iter().all(|endpoint| return endpoint.cluster().as_str() == expected_network)); + } + if let std::option::Option::Some(grpc) = transport.grpc_settings() { + assert!(grpc.endpoints().iter().all(|endpoint| return endpoint.cluster().as_str() == expected_network)); + } + } +} + fn fixture_example_engine() -> ksp_core_lib::Result { let workspace = workspace_root(); let fixture_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures"); diff --git a/crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-raw-transaction-ingest-desk.json b/crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-raw-transaction-ingest-desk.json new file mode 100644 index 0000000..d6eff9a --- /dev/null +++ b/crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-raw-transaction-ingest-desk.json @@ -0,0 +1,146 @@ +{ + "format_version": 1, + "default_profile": "devnet_public", + "profiles": [ + { + "profile_id": "devnet_public", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "helius_devnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "helius_devnet" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "orbitflare_devnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "devnet" + } + ] + }, + { + "profile_id": "mainnet_public", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "helius_mainnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "publicnode_mainnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "mainnet" + } + ] + }, + { + "profile_id": "publicnode_testnet", + "documents": [ + { + "component_id": "logging", + "file_id": "cfg.std.logging", + "profile_id": "local_dev" + }, + { + "component_id": "transport", + "file_id": "cfg.std.transport", + "profile_id": "secret_test" + }, + { + "component_id": "store", + "file_id": "cfg.std.store", + "profile_id": "testnet" + } + ] + } + ] +} diff --git a/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json b/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json index 2df195d..5fd64e9 100644 --- a/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json +++ b/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json @@ -70,7 +70,15 @@ "resubscribe": "never", "notification_queue_capacity": 48, "max_pending_requests": 24 - } + }, + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot" + ] }, { "name": "fixture_helius_ws", @@ -78,7 +86,17 @@ "provider": "helius", "cluster": "mainnet", "kind": "helius_laserstream", - "url": "wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}" + "url": "wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] }, @@ -119,7 +137,17 @@ "provider": "helius", "cluster": "devnet", "kind": "helius_laserstream", - "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}" + "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}", + "capabilities": [ + "account", + "logs", + "program", + "root", + "signature", + "slot", + "slots_updates", + "helius_transaction" + ] } ] } diff --git a/crates/ksp-config-lib/unit_tests/registry.rs b/crates/ksp-config-lib/unit_tests/registry.rs index 64453de..0ce630e 100644 --- a/crates/ksp-config-lib/unit_tests/registry.rs +++ b/crates/ksp-config-lib/unit_tests/registry.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/unit_tests/registry.rs -// version: 13 +// version: 14 #[test] fn descriptors_expose_complete_registry_in_deterministic_file_id_order() { @@ -7,30 +7,33 @@ fn descriptors_expose_complete_registry_in_deterministic_file_id_order() { assert!(registry.is_ok(), "default registry should be valid: {registry:?}"); if let std::result::Result::Ok(registry) = registry { let descriptors: std::vec::Vec<&crate::ConfigFileDescriptor> = registry.descriptors().collect(); - assert_eq!(descriptors.len(), 15); + assert_eq!(descriptors.len(), 16); assert_eq!(descriptors[0].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK); assert_eq!(descriptors[0].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_BACKFILL_DESK_FILENAME)); assert_eq!(descriptors[0].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE)); - assert_eq!(descriptors[1].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK); - assert_eq!(descriptors[2].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK); - assert_eq!(descriptors[2].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_STORE_DESK_FILENAME)); - assert_eq!(descriptors[2].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE)); - assert_eq!(descriptors[3].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK); - assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_STD_LOGGING); - assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT); - assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_STD_STORE); - assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT); - assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_STD_WALLET); - assert_eq!(descriptors[8].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME)); - assert_eq!(descriptors[8].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET)); - assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE); - assert_eq!(descriptors[10].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING); - assert_eq!(descriptors[11].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT); - assert_eq!(descriptors[12].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_STORE); - assert_eq!(descriptors[13].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT); - assert_eq!(descriptors[14].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET); - assert!(descriptors[0..9].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config)); - assert!(descriptors[9..15].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema)); + assert_eq!(descriptors[1].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK); + assert_eq!(descriptors[1].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME)); + assert_eq!(descriptors[1].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE)); + assert_eq!(descriptors[2].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK); + assert_eq!(descriptors[3].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK); + assert_eq!(descriptors[3].filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_STORE_DESK_FILENAME)); + assert_eq!(descriptors[3].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE)); + assert_eq!(descriptors[4].file_id().as_str(), crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK); + assert_eq!(descriptors[5].file_id().as_str(), crate::FILE_ID_STD_LOGGING); + assert_eq!(descriptors[6].file_id().as_str(), crate::FILE_ID_STD_OFFCHAIN_TRANSPORT); + assert_eq!(descriptors[7].file_id().as_str(), crate::FILE_ID_STD_STORE); + assert_eq!(descriptors[8].file_id().as_str(), crate::FILE_ID_STD_TRANSPORT); + assert_eq!(descriptors[9].file_id().as_str(), crate::FILE_ID_STD_WALLET); + assert_eq!(descriptors[9].filename(), std::path::Path::new(crate::DEFAULT_STD_WALLET_FILENAME)); + assert_eq!(descriptors[9].schema_file_id().map(crate::ConfigFileId::as_str), std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_WALLET)); + assert_eq!(descriptors[10].file_id().as_str(), crate::FILE_ID_SCHEMA_COMPOSITE); + assert_eq!(descriptors[11].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_LOGGING); + assert_eq!(descriptors[12].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_OFFCHAIN_TRANSPORT); + assert_eq!(descriptors[13].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_STORE); + assert_eq!(descriptors[14].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_TRANSPORT); + assert_eq!(descriptors[15].file_id().as_str(), crate::FILE_ID_SCHEMA_STD_WALLET); + assert!(descriptors[0..10].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Config)); + assert!(descriptors[10..16].iter().all(|descriptor| return descriptor.kind() == crate::ConfigFileKind::Schema)); } } @@ -365,16 +368,18 @@ fn absolute_fixture_path() -> std::path::PathBuf { } #[test] -fn defaults_register_generic_composite_schema_and_four_runtime_composites() { +fn defaults_register_generic_composite_schema_and_five_runtime_composites() { let registry = crate::ConfigFileRegistry::defaults(); let schema_id = crate::ConfigFileId::new(crate::FILE_ID_SCHEMA_COMPOSITE); let backfill_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK); + let raw_ingest_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK); let solprices_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK); let store_desk_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_STORE_DESK); let wallet_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK); assert!(registry.is_ok(), "default registry should be valid: {registry:?}"); assert!(schema_id.is_ok(), "composite schema file_id should be valid: {schema_id:?}"); assert!(backfill_id.is_ok(), "Backfill Desk composite runtime file_id should be valid: {backfill_id:?}"); + assert!(raw_ingest_id.is_ok(), "Raw Transaction Ingest Desk composite runtime file_id should be valid: {raw_ingest_id:?}"); assert!(solprices_id.is_ok(), "SOL Prices Desk composite runtime file_id should be valid: {solprices_id:?}"); assert!(store_desk_id.is_ok(), "Store Desk composite runtime file_id should be valid: {store_desk_id:?}"); assert!(wallet_id.is_ok(), "Wallet Desk composite runtime file_id should be valid: {wallet_id:?}"); @@ -382,34 +387,41 @@ fn defaults_register_generic_composite_schema_and_four_runtime_composites() { std::result::Result::Ok(registry), std::result::Result::Ok(schema_id), std::result::Result::Ok(backfill_id), + std::result::Result::Ok(raw_ingest_id), std::result::Result::Ok(solprices_id), std::result::Result::Ok(store_desk_id), std::result::Result::Ok(wallet_id), - ) = (registry, schema_id, backfill_id, solprices_id, store_desk_id, wallet_id) + ) = (registry, schema_id, backfill_id, raw_ingest_id, solprices_id, store_desk_id, wallet_id) { let schema = registry.descriptor(&schema_id); let backfill = registry.descriptor(&backfill_id); + let raw_ingest = registry.descriptor(&raw_ingest_id); let solprices = registry.descriptor(&solprices_id); let store_desk = registry.descriptor(&store_desk_id); let wallet = registry.descriptor(&wallet_id); assert!(schema.is_ok(), "generic composite schema should be registered: {schema:?}"); assert!(backfill.is_ok(), "Backfill Desk runtime composite should be registered: {backfill:?}"); + assert!(raw_ingest.is_ok(), "Raw Transaction Ingest Desk runtime composite should be registered: {raw_ingest:?}"); assert!(solprices.is_ok(), "SOL Prices Desk runtime composite should be registered: {solprices:?}"); assert!(store_desk.is_ok(), "Store Desk runtime composite should be registered: {store_desk:?}"); assert!(wallet.is_ok(), "Wallet Desk runtime composite should be registered: {wallet:?}"); if let ( std::result::Result::Ok(schema), std::result::Result::Ok(backfill), + std::result::Result::Ok(raw_ingest), std::result::Result::Ok(solprices), std::result::Result::Ok(store_desk), std::result::Result::Ok(wallet), - ) = (schema, backfill, solprices, store_desk, wallet) + ) = (schema, backfill, raw_ingest, solprices, store_desk, wallet) { assert_eq!(schema.kind(), crate::ConfigFileKind::Schema); assert_eq!(schema.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_SCHEMA_FILENAME)); assert_eq!(backfill.kind(), crate::ConfigFileKind::Config); assert_eq!(backfill.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_BACKFILL_DESK_FILENAME)); assert_eq!(backfill.schema_file_id(), std::option::Option::Some(&schema_id)); + assert_eq!(raw_ingest.kind(), crate::ConfigFileKind::Config); + assert_eq!(raw_ingest.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK_FILENAME)); + assert_eq!(raw_ingest.schema_file_id(), std::option::Option::Some(&schema_id)); assert_eq!(solprices.kind(), crate::ConfigFileKind::Config); assert_eq!(solprices.filename(), std::path::Path::new(crate::DEFAULT_COMPOSITE_KSP_APP_SOLPRICES_DESK_FILENAME)); assert_eq!(solprices.schema_file_id(), std::option::Option::Some(&schema_id)); diff --git a/crates/ksp-config-lib/unit_tests/transport.rs b/crates/ksp-config-lib/unit_tests/transport.rs index 6678e22..bc7a889 100644 --- a/crates/ksp-config-lib/unit_tests/transport.rs +++ b/crates/ksp-config-lib/unit_tests/transport.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/unit_tests/transport.rs -// version: 13 +// version: 14 #[test] fn fixture_transport_profile_maps_complete_runtime_contract() { @@ -51,6 +51,19 @@ fn fixture_transport_profile_maps_complete_runtime_contract() { assert_eq!(endpoint.provider().as_str(), "fixture-provider"); assert_eq!(endpoint.cluster().as_str(), "fixture-cluster"); assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard); + assert_eq!( + endpoint.subscription_capabilities(), + std::option::Option::Some( + &[ + 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, + ][..], + ) + ); assert_eq!(endpoint.url().as_str(), "wss://fallback.invalid"); assert_eq!(endpoint.session().command_timeout(), std::time::Duration::from_millis(4500)); assert_eq!(endpoint.session().close_timeout(), std::time::Duration::from_millis(4000)); @@ -70,6 +83,21 @@ fn fixture_transport_profile_maps_complete_runtime_contract() { assert_eq!(helius.provider().as_str(), "helius"); assert_eq!(helius.cluster().as_str(), "mainnet"); assert_eq!(helius.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream); + assert_eq!( + helius.subscription_capabilities(), + std::option::Option::Some( + &[ + 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, + ][..], + ) + ); assert_eq!(helius.url().as_str(), "wss://mainnet.helius-rpc.com/?api-key=fixture-helius-key"); let _connect_future = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::connect(helius.clone()); } @@ -117,6 +145,8 @@ fn committed_transport_document_maps_default_and_explicit_profiles() { if let std::option::Option::Some(ws) = ws { assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.devnet.solana.com"); assert_eq!(ws.endpoints()[0].protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard); + assert!(ws.endpoints()[0].supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Logs)); + assert!(!ws.endpoints()[0].supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Block)); } } if let std::result::Result::Ok(mainnet) = mainnet { @@ -129,6 +159,8 @@ fn committed_transport_document_maps_default_and_explicit_profiles() { assert!(ws.is_some(), "committed V3 Mainnet profile should expose WebSocket settings"); if let std::option::Option::Some(ws) = ws { assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.mainnet.solana.com"); + assert!(ws.endpoints()[0].supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Logs)); + assert!(!ws.endpoints()[0].supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Block)); } } } @@ -529,6 +561,47 @@ fn helius_laserstream_mainnet_and_devnet_api_key_map_to_protocol_and_safe_redact assert!(devnet_debug.contains(crate::REDACTED_CONFIG_VALUE)); } +#[test] +fn v0_3_15_pre_003_committed_helius_profiles_map_transaction_capability_without_block_or_vote() { + let engine = committed_engine(); + let engine = match engine { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => return, + }; + let canary = "helius-pre-003-api-key-canary"; + let mut process = std::collections::BTreeMap::::new(); + process.insert("KSP_SECRET_HELIUS_API_KEY".to_owned(), canary.to_owned()); + let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new()); + for (profile_id, cluster, expected_url) in [ + ("helius_devnet", "devnet", "wss://devnet.helius-rpc.com/?api-key=helius-pre-003-api-key-canary"), + ("helius_mainnet", "mainnet", "wss://mainnet.helius-rpc.com/?api-key=helius-pre-003-api-key-canary"), + ] { + let resolved = engine.load_resolved_transport_config(std::option::Option::Some(profile_id), &environment); + assert!(resolved.is_ok(), "committed Helius profile {profile_id} should resolve: {resolved:?}"); + let resolved = match resolved { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => continue, + }; + assert_eq!(resolved.http_settings().endpoints()[0].cluster().as_str(), cluster); + let ws = resolved.ws_settings(); + assert!(ws.is_some(), "committed Helius profile {profile_id} should expose WebSocket settings"); + if let std::option::Option::Some(ws) = ws { + assert_eq!(ws.endpoints().len(), 1); + let endpoint = &ws.endpoints()[0]; + assert_eq!(endpoint.provider().as_str(), "helius"); + assert_eq!(endpoint.cluster().as_str(), cluster); + assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream); + assert_eq!(endpoint.url().as_str(), expected_url); + assert!(endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Logs)); + assert!(endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction)); + assert!(!endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Block)); + assert!(!endpoint.supports_subscription(ksp_onchain_transport_lib::WsSubscriptionKind::Vote)); + } + let debug = format!("{resolved:?}"); + assert!(!debug.contains(canary)); + } +} + #[test] fn transport_secret_url_provenance_uses_process_and_process_beats_dotenv() { let engine = fixture_engine(); diff --git a/deltas/0.3.15/pre.003.md b/deltas/0.3.15/pre.003.md new file mode 100644 index 0000000..a967cbd --- /dev/null +++ b/deltas/0.3.15/pre.003.md @@ -0,0 +1,333 @@ + + + +# Delta `0.3.15-pre.003` — mapping Config des capabilities WS et composite Raw Ingest Desk + +## Base requise + +```text +0.3.15-pre.002-fix.001 appliquée +workspace.package.version = 0.3.15-pre.2.fix.1 +deltas/0.3.15/pre.002-fix.001.md présent +``` + +## Gate de la base + +Le gate opérateur communiqué après `pre.002-fix.001` est propre : + +```text +cargo fmt --all : PASS +cargo fmt --all -- --check : PASS +General Rust rule audit : clean +Rust export completeness audit : 0 candidate(s) +KSP workspace Rust rule audit : clean +Markdown table audit : clean (318 table(s), 187 file(s)) +cargo check --workspace : PASS +cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS +ksp-onchain-transport-lib unit tests : 395 passed / 0 failed +ksp-onchain-transport-lib public_api : 54 passed / 0 failed +ksp-onchain-transport-lib release_completeness : 47 passed / 0 failed +live smoke tests : ignored / opt-in uniquement +``` + +Ce gate qualifie la base directe de `pre.003` avant toute modification Config. + +## Objectif + +Implémenter strictement la tranche `pre.003` du plan `036` : + +```text +porter les capabilities WS explicites dans le schema std.transport +mapper ces capabilities vers WsSubscriptionKind sans second enum runtime +committer des déclarations conservatrices sur les profils Transport existants +committer les profils Helius nécessaires à la future Desk sans inférence provider +ajouter le composite Raw Transaction Ingest Desk +forcer la cohérence Transport + Store par réseau dans ce composite +enregistrer le nouveau composite dans le registry Config +synchroniser les ressources Config packagées des Desk existantes +préserver l'absence de frontend et de runtime Worker dans cette tranche +``` + +L'enforcement par les constructeurs Worker reste exclusivement réservé à `pre.004`. + +## Schema et mapping des capabilities WS + +`std.transport.schema.json` accepte désormais sur chaque endpoint WebSocket le champ optionnel : + +```text +capabilities: array unique borné à 10 entrées +``` + +Descripteurs admis : + +```text +account +block +logs +program +root +signature +slot +slots_updates +vote +helius_transaction +``` + +Le mapping Config convertit chaque descripteur vers le `WsSubscriptionKind` Transport existant puis utilise `WsEndpointSettings::with_subscription_capabilities(...)`. + +Aucun enum Config public supplémentaire n'est créé et aucune capability n'est dérivée du champ `provider`. + +L'absence du champ reste backward-readable et conserve la sémantique fail-closed introduite par Transport en `pre.002`. + +## Déclarations committed conservatrices + +Les endpoints `solana_standard` committed déclarent exactement la surface stable utilisée par KSP : + +```text +Account +Logs +Program +Root +Signature +Slot +``` + +Ils ne déclarent pas : + +```text +Block +SlotsUpdates +Vote +HeliusTransaction +``` + +En particulier, `blockSubscribe` n'est jamais supposé disponible par simple appartenance au protocole Solana standard. + +Les endpoints `helius_laserstream` committed déclarent : + +```text +Account +Logs +Program +Root +Signature +Slot +SlotsUpdates +HeliusTransaction +``` + +Ils ne déclarent ni `Block` ni `Vote`. + +## Profils Helius committed + +Deux profils Transport sont ajoutés : + +```text +helius_devnet +helius_mainnet +``` + +Chacun compose : + +```text +HTTP public du même réseau pour hydration +WS HeliusLaserStream du même réseau +KSP_SECRET_HELIUS_API_KEY résolu uniquement côté Config/backend +capability HeliusTransaction explicitement déclarée +``` + +Le secret ne traverse aucune nouvelle projection publique ou frontend. + +## Composite Raw Transaction Ingest Desk + +Le nouveau document : + +```text +config/composite.ksp-app-raw-transaction-ingest-desk.json +``` + +est enregistré sous : + +```text +cfg.composite.ksp-app-raw-transaction-ingest-desk +``` + +Il utilise le schema composite générique existant et possède `devnet_public` comme profil par défaut. + +Profils applicatifs committed : + +```text +devnet_public -> Transport devnet_public + Store devnet +helius_devnet -> Transport helius_devnet + Store devnet +orbitflare_devnet -> Transport orbitflare_devnet + Store devnet +mainnet_public -> Transport mainnet_public + Store mainnet +helius_mainnet -> Transport helius_mainnet + Store mainnet +publicnode_mainnet -> Transport publicnode_mainnet + Store mainnet +publicnode_testnet -> Transport publicnode_testnet + Store testnet +``` + +Chaque profil compose également `cfg.std.logging/supertrace`. + +`mainnet_backfill_pool` est volontairement absent : un profil explicitement façonné pour Backfill ne devient pas une dépendance implicite du Worker live. Cette séparation préserve les deux producteurs indépendants du même RAW Store. + +## Registry et packaging Config + +Le registry Config passe de 15 à 16 descripteurs avec le nouveau composite. + +Les cinq Desk existantes utilisant le runtime Config packagé embarquent donc désormais 16 ressources : + +```text +ksp-app-backfill-desk +ksp-app-config-desk +ksp-app-solprices-desk +ksp-app-store-desk +ksp-app-wallet-desk +``` + +Le nouveau composite est uniquement une ressource Config partagée à ce stade ; aucune nouvelle crate Desk n'est créée en `pre.003`. + +Les canaris exacts de packaging, registry et inventaire Config sont recalibrés à 16 ressources/descripteurs. + +## Tests et canaris ajoutés ou étendus + +La tranche couvre notamment : + +```text +mapping exact SolanaStandard des capabilities déclarées +mapping exact HeliusLaserStream des capabilities déclarées +profils committed standard : Logs oui / Block non +profils committed Helius : HeliusTransaction oui / Block et Vote non +redaction de KSP_SECRET_HELIUS_API_KEY dans les projections Debug +résolution des sept profils du composite Raw Ingest Desk +égalité de réseau Store / HTTP / WS / gRPC pour chaque profil applicatif +inventaire exact du registry public +présence du composite dans les ressources packagées des cinq Desk existantes +présence du composite dans l'inventaire Config Desk +``` + +## Documentation + +`ksp-config-lib/README.md` et `USAGE.md` restent version-neutral et documentent : + +```text +le nouveau composite Raw Ingest Desk +la déclaration explicite capabilities des endpoints WS +les descripteurs admis +l'absence d'inférence par provider +la surface conservatrice standard committed +les profils Helius committed et leur secret Config-owned +la cohérence Transport + Store du composite applicatif +``` + +Le plan `036` et la validation `032` sont réconciliés avec les faits de `pre.003` sans transformer le forecast en tableau. + +## Fichiers ajoutés + +```text +config/composite.ksp-app-raw-transaction-ingest-desk.json +crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-raw-transaction-ingest-desk.json +deltas/0.3.15/pre.003.md +``` + +## Fichiers modifiés + +```text +Cargo.toml +config/examples/std.transport.example.json +config/schemas/std.transport.schema.json +config/std.transport.json +crates/ksp-app-backfill-desk/tauri.conf.json +crates/ksp-app-backfill-desk/tests/desktop_contract.rs +crates/ksp-app-config-desk/tauri.conf.json +crates/ksp-app-config-desk/tests/desktop_contract.rs +crates/ksp-app-config-desk/unit_tests/profiles.rs +crates/ksp-app-solprices-desk/tauri.conf.json +crates/ksp-app-solprices-desk/tests/desktop_contract.rs +crates/ksp-app-store-desk/tauri.conf.json +crates/ksp-app-store-desk/tests/desktop_contract.rs +crates/ksp-app-wallet-desk/tauri.conf.json +crates/ksp-app-wallet-desk/tests/desktop_contract.rs +crates/ksp-app-wallet-desk/tests/release_compliance.rs +crates/ksp-config-lib/README.md +crates/ksp-config-lib/USAGE.md +crates/ksp-config-lib/src/lib.rs +crates/ksp-config-lib/src/registry.rs +crates/ksp-config-lib/src/transport.rs +crates/ksp-config-lib/tests/ownership.rs +crates/ksp-config-lib/tests/public_api.rs +crates/ksp-config-lib/unit_tests/composite.rs +crates/ksp-config-lib/unit_tests/fixtures/std.transport.json +crates/ksp-config-lib/unit_tests/registry.rs +crates/ksp-config-lib/unit_tests/transport.rs +docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md +docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md +``` + +## Fichiers supprimés + +```text +aucun +``` + +## Version Cargo + +Cette tranche modifie Config/runtime mapping et packaging : + +```text +header Cargo.toml : 596 -> 597 +workspace.package.version : 0.3.15-pre.2.fix.1 -> 0.3.15-pre.3 +``` + +Tous les crates workspace héritent de cette version. + +## Validations exécutées dans l'environnement d'assemblage + +```text +General Rust rule audit : clean +Rust export completeness audit : 0 candidate(s) +KSP workspace Rust rule audit : clean +Markdown table audit : clean +JSON parse audit : clean +std.transport JSON Schema validation : PASS +composite JSON Schema validation : PASS +capability declarations committed : PASS +composite Transport/Store network coupling statique : PASS +packaged Config resource inventory : 16/16 sur les cinq Desk existantes +versions de fichiers Rust modifiés : incrémentées exactement d'une unité +``` + +## Validations non exécutées dans l'environnement d'assemblage + +La toolchain Cargo/Rust n'est pas disponible dans l'environnement d'assemblage. Le gate opérateur doit confirmer : + +```bash +cargo fmt --all +cargo fmt --all -- --check +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.15 +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test -p ksp-config-lib --all-targets --all-features +cargo test --workspace --all-targets --all-features +``` + +## Décisions prises + +```text +Config porte la déclaration de capability ; Transport reste propriétaire de sa sémantique typed +aucune capability n'est inférée depuis un provider name +les profils standard committed n'annoncent pas Block sans preuve explicite d'endpoint +les profils Helius committed n'annoncent ni Block ni Vote +les profils Helius peuvent hydrater via HTTP public du même réseau +le composite Raw Ingest couple toujours Transport et Store du même réseau +mainnet_backfill_pool reste hors composite Raw Ingest +aucun frontend et aucun Start/Stop Worker ne sont ouverts avant les tranches prévues +``` + +## Questions ouvertes + +```text +aucune pour pre.003 +``` + +La prochaine responsabilité reste `pre.004` : faire appliquer les capabilities WS déclarées par les constructeurs Worker avant toute I/O. 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 85189f0..96bf54d 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 @@ -191,15 +191,16 @@ Aucun gap Store n'est identifié. L'application ne dépend jamais de `ksp-store- ## 6. Profils Transport réellement committed -| Profil/config | Réseau | Surfaces | Secret requis | Committed ? | Observation | -|-------------------------|------------------------------|---------------------------------------|-----------------------|----------------------|-------------------------------------------| -| `devnet_public` | devnet | HTTP + WS Solana standard | non | oui | pas de capability WS fine aujourd’hui | -| `orbitflare_devnet` | devnet | HTTP + WS standard + Yellowstone gRPC | token gRPC secret | conditionnel | profil complet seulement si secret résolu | -| `mainnet_public` | mainnet | HTTP + WS Solana standard | non | oui | pas de capability WS fine aujourd’hui | -| `mainnet_backfill_pool` | mainnet | plusieurs HTTP + WS standard | selon endpoint/config | oui si profil résolu | priorités/rôles restent Transport-owned | -| `publicnode_mainnet` | mainnet | HTTP + WS standard + Yellowstone gRPC | x-token secret | conditionnel | gRPC provider-gated | -| `publicnode_testnet` | testnet | HTTP + WS standard + Yellowstone gRPC | x-token secret | conditionnel | gRPC provider-gated | -| Helius exemple | mainnet/devnet selon exemple | WS `helius_laserstream` | API key secret | non committed | exemple != profil actif | +| Profil/config | Réseau | Surfaces | Secret requis | Committed ? | Observation | +|-------------------------|---------|---------------------------------------|-------------------|-------------|-----------------------------------------------------------------| +| `devnet_public` | devnet | HTTP + WS Solana standard | non | oui | capabilities stables déclarées ; `Logs` oui ; `Block` non | +| `helius_devnet` | devnet | HTTP public + WS Helius | API key Helius | oui | `HeliusTransaction` oui ; `Block`/`Vote` non | +| `orbitflare_devnet` | devnet | HTTP + WS standard + Yellowstone gRPC | token gRPC secret | oui | `Logs` déclaré ; gRPC composable seulement si secret résolu | +| `mainnet_public` | mainnet | HTTP + WS Solana standard | non | oui | capabilities stables déclarées ; `Logs` oui ; `Block` non | +| `helius_mainnet` | mainnet | HTTP public + WS Helius | API key Helius | oui | `HeliusTransaction` oui ; `Block`/`Vote` non | +| `mainnet_backfill_pool` | mainnet | plusieurs HTTP + WS standard | selon endpoints | oui | `Logs` déclaré ; profil conservé hors composite Raw Ingest Desk | +| `publicnode_mainnet` | mainnet | HTTP + WS standard + Yellowstone gRPC | x-token secret | oui | `Logs` déclaré ; gRPC composable seulement si secret résolu | +| `publicnode_testnet` | testnet | HTTP + WS standard + Yellowstone gRPC | x-token secret | oui | `Logs` déclaré ; gRPC composable seulement si secret résolu | Conséquences : @@ -233,13 +234,13 @@ Le frontend reçoit uniquement la projection sûre de ce modèle. Les ressources ## 8. Matrice route / capability / Config / Worker -| Route V1 | Network | Required capability | Optional capability | Config evidence | Worker resource | Composable aujourd’hui ? | Missing contract | Live-testable ? | -|-------------------------------|------------------|----------------------------------------------------------------|-------------------------------------------------|-----------------------|-----------------------------------------------|---------------------------------------------------------|--------------------------------------------------|-----------------------------------------------| -| `yellowstone-hydrated` | réseau du profil | Yellowstone gRPC Subscribe + HTTP `getTransaction` même réseau | scan HTTP repair si rôle compatible | gRPC + HTTP role | `RawTransactionIngestYellowstoneSource` | oui sur profil complet et secrets résolus | aucun contrat essentiel | provider-gated selon profil | -| `standard-logs-hydrated` | réseau du profil | WS Solana standard `logsSubscribe` + HTTP `getTransaction` | scan HTTP repair si rôle compatible | WS + HTTP role | `RawTransactionIngestStandardLogsSource` | non prouvable strictement avant capability WS explicite | Transport + Config + enforcement Worker minimaux | oui, notamment Devnet keyless après extension | -| `standard-block-direct` | réseau du profil | WS Solana standard `blockSubscribe` explicitement déclaré | aucune hydration obligatoire | WS capability Block | `RawTransactionIngestStandardBlockSource` | non prouvable aujourd’hui | Transport + Config + enforcement Worker minimaux | seulement endpoint prouvé compatible | -| `helius-transaction-hydrated` | réseau du profil | WS Helius `transactionSubscribe` + HTTP `getTransaction` | scan HTTP repair si rôle compatible | Helius WS + HTTP role | `RawTransactionIngestHeliusTransactionSource` | non dans les profils committed actuels | Config data/composite + capability WS explicite | provider-gated Helius | -| `http-block-polling` | réseau du profil | HTTP `getSlot` + `getBlocksWithLimit` + `getBlock` | `getTransaction` pour known-reference hydration | HTTP role | `RawTransactionIngestHttpBlockPollingSource` | oui lorsque le rôle résolu annonce les trois méthodes | aucun contrat essentiel | oui sur endpoint public compatible | +| Route V1 | Network | Required capability | Optional capability | Config evidence | Worker resource | Composable aujourd’hui ? | Missing contract | Live-testable ? | +|-------------------------------|------------------|----------------------------------------------------------------|-------------------------------------------------|---------------------------------|-----------------------------------------------|-----------------------------------------------------------------------------------|------------------------------------------------|--------------------------------------| +| `yellowstone-hydrated` | réseau du profil | Yellowstone gRPC Subscribe + HTTP `getTransaction` même réseau | scan HTTP repair si rôle compatible | gRPC + HTTP role | `RawTransactionIngestYellowstoneSource` | oui sur profil complet et secrets résolus | aucun contrat essentiel | provider-gated selon profil | +| `standard-logs-hydrated` | réseau du profil | WS Solana standard `logsSubscribe` + HTTP `getTransaction` | scan HTTP repair si rôle compatible | `Logs` + HTTP role | `RawTransactionIngestStandardLogsSource` | oui côté Config sur profils déclarant `Logs` ; enforcement Worker en `pre.004` | enforcement Worker minimal | oui, notamment Devnet keyless | +| `standard-block-direct` | réseau du profil | WS Solana standard `blockSubscribe` explicitement déclaré | aucune hydration obligatoire | WS capability `Block` | `RawTransactionIngestStandardBlockSource` | non : aucun profil committed ne déclare `Block` | enforcement Worker minimal + endpoint qualifié | seulement endpoint prouvé compatible | +| `helius-transaction-hydrated` | réseau du profil | WS Helius `transactionSubscribe` + HTTP `getTransaction` | scan HTTP repair si rôle compatible | `HeliusTransaction` + HTTP role | `RawTransactionIngestHeliusTransactionSource` | oui côté Config sur `helius_*` si secret résolu ; enforcement Worker en `pre.004` | enforcement Worker minimal | provider-gated Helius | +| `http-block-polling` | réseau du profil | HTTP `getSlot` + `getBlocksWithLimit` + `getBlock` | `getTransaction` pour known-reference hydration | HTTP role | `RawTransactionIngestHttpBlockPollingSource` | oui lorsque le rôle résolu annonce les trois méthodes | aucun contrat essentiel | oui sur endpoint public compatible | ### 8.1 `yellowstone-hydrated` @@ -292,7 +293,7 @@ HTTP same-network avec getTransaction commitment confirmed ou finalized ``` -Le profil committed stable n'expose actuellement pas cette ressource ; les exemples Helius ne sont pas convertis en disponibilité implicite. +Les profils committed `helius_devnet` et `helius_mainnet` déclarent explicitement `HeliusTransaction` et restent conditionnels à la résolution de `KSP_SECRET_HELIUS_API_KEY`. Aucun profil Helius ne déclare `Block` ou `Vote`. Le provider name ne participe pas à cette preuve. ### 8.5 `http-block-polling` @@ -693,6 +694,8 @@ Budget cible : une tranche Transport. Étendre le schema/mapping Config pour porter les capabilities WS déclarées et préparer les composites/profils Raw Transaction Ingest Desk cohérents Transport+Store. Aucun frontend. +**État : implémenté.** Les profils WS committed déclarent désormais leurs capabilities explicitement, deux profils Helius sont committed, et le composite Raw Ingest Desk couple Transport+Store par réseau sans inclure le profil `mainnet_backfill_pool`. + Budget cible : une tranche Config. ### `pre.004` — enforcement Worker des capabilities WS diff --git a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md index 0ae3e19..ed22c4b 100644 --- a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md +++ b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md @@ -1,5 +1,5 @@ - + # Validation v0.3.15 — Raw Transaction Ingest Desk @@ -344,11 +344,11 @@ Le forecast durable est porté par la section 20 du plan `036` sous forme hiéra ### `pre.002` — Transport WS capability -Capability WS typed par subscription + tests, sans app. +**Statut : réalisé après `pre.002-fix.001`.** Capability WS typed par subscription + tests, sans app. Le gate opérateur du fix passe `cargo check`, Clippy `-D warnings` et la suite Transport complète. ### `pre.003` — Config capability/composite -Schema/mapping capabilities WS + composite/profils Raw Ingest Desk. +**Statut : réalisé côté assemblage ; gate Cargo opérateur requis.** Schema/mapping capabilities WS + composite/profils Raw Ingest Desk. Les profils standard committed déclarent la surface stable sans `Block`, les profils Helius déclarent explicitement `HeliusTransaction` sans `Block`/`Vote`, et les profils du composite Raw Ingest Desk couplent Transport+Store sur le même réseau. ### `pre.004` — Worker enforcement