v0.3.12-pre.002
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 519
|
# version: 520
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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"]
|
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]
|
[workspace.package]
|
||||||
version = "0.3.12-pre.1"
|
version = "0.3.12-pre.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: crates/ksp-worker-raw-transaction-ingest-lib/Cargo.toml
|
# file: crates/ksp-worker-raw-transaction-ingest-lib/Cargo.toml
|
||||||
# version: 1
|
# version: 2
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "ksp-worker-raw-transaction-ingest-lib"
|
name = "ksp-worker-raw-transaction-ingest-lib"
|
||||||
@@ -10,6 +10,7 @@ repository.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||||
ksp-logging-lib = { path = "../ksp-logging-lib" }
|
ksp-logging-lib = { path = "../ksp-logging-lib" }
|
||||||
|
ksp-onchain-transport-lib = { path = "../ksp-onchain-transport-lib" }
|
||||||
ksp-raw-transaction-lib = { path = "../ksp-raw-transaction-lib" }
|
ksp-raw-transaction-lib = { path = "../ksp-raw-transaction-lib" }
|
||||||
ksp-store-lib = { path = "../ksp-store-lib", default-features = false }
|
ksp-store-lib = { path = "../ksp-store-lib", default-features = false }
|
||||||
ksp-worker-api = { path = "../ksp-worker-api" }
|
ksp-worker-api = { path = "../ksp-worker-api" }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
@@ -11,13 +11,14 @@
|
|||||||
//! and the caller-runtime-owned lifecycle with private child-task supervision. This tranche also
|
//! and the caller-runtime-owned lifecycle with private child-task supervision. This tranche also
|
||||||
//! owns bounded source-neutral admission, common RAW canonicalization/assembly and backend-neutral
|
//! owns bounded source-neutral admission, common RAW canonicalization/assembly and backend-neutral
|
||||||
//! Store persistence in normal mode plus concrete latest-value snapshots projected onto Worker API;
|
//! Store persistence in normal mode plus concrete latest-value snapshots projected onto Worker API;
|
||||||
//! no live source or Transport dependency exists.
|
//! the first validated Yellowstone/HTTP runtime-resource contract exists, but no live stream is opened yet.
|
||||||
|
|
||||||
mod admission;
|
mod admission;
|
||||||
mod error;
|
mod error;
|
||||||
mod identity;
|
mod identity;
|
||||||
mod persistence;
|
mod persistence;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
|
mod runtime_resources;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod snapshot;
|
mod snapshot;
|
||||||
|
|
||||||
@@ -43,6 +44,10 @@ pub use self::runtime::RawTransactionIngestHandle;
|
|||||||
pub use self::runtime::RawTransactionIngestTerminalFuture;
|
pub use self::runtime::RawTransactionIngestTerminalFuture;
|
||||||
/// Entry point owning synchronous validation and task launch for one RAW transaction ingest Worker run.
|
/// Entry point owning synchronous validation and task launch for one RAW transaction ingest Worker run.
|
||||||
pub use self::runtime::RawTransactionIngestWorker;
|
pub use self::runtime::RawTransactionIngestWorker;
|
||||||
|
/// Caller-composed runtime resources for the first Yellowstone + HTTP source family.
|
||||||
|
pub use self::runtime_resources::RawTransactionIngestRuntimeResources;
|
||||||
|
/// Validated Yellowstone + HTTP source contract owned by the continuous RAW transaction ingest Worker.
|
||||||
|
pub use self::runtime_resources::RawTransactionIngestYellowstoneSource;
|
||||||
/// Default bounded admission queue capacity for one RAW transaction ingest Worker.
|
/// Default bounded admission queue capacity for one RAW transaction ingest Worker.
|
||||||
pub use self::settings::DEFAULT_RAW_TRANSACTION_INGEST_ADMISSION_QUEUE_CAPACITY;
|
pub use self::settings::DEFAULT_RAW_TRANSACTION_INGEST_ADMISSION_QUEUE_CAPACITY;
|
||||||
/// Default number of concurrent Store persistence operations for one RAW transaction ingest Worker.
|
/// Default number of concurrent Store persistence operations for one RAW transaction ingest Worker.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
type PersistencePort = std::sync::Arc<dyn crate::RawTransactionIngestPersistencePort + 'static>;
|
type PersistencePort = std::sync::Arc<dyn crate::RawTransactionIngestPersistencePort + 'static>;
|
||||||
type PersistenceTasks = tokio::task::JoinSet<ksp_core_lib::Result<crate::RawTransactionIngestPersistenceOutcome>>;
|
type PersistenceTasks = tokio::task::JoinSet<ksp_core_lib::Result<crate::RawTransactionIngestPersistenceOutcome>>;
|
||||||
@@ -95,6 +95,26 @@ impl crate::RawTransactionIngestWorker {
|
|||||||
}
|
}
|
||||||
return start_foundation(settings, runtime, std::option::Option::Some(store));
|
return start_foundation(settings, runtime, std::option::Option::Some(store));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts one Worker with caller-composed runtime resources after synchronous network validation, without opening the live source before its dedicated tranche.
|
||||||
|
pub fn start_with_runtime_resources(
|
||||||
|
settings: crate::RawTransactionIngestSettings,
|
||||||
|
store: std::sync::Arc<ksp_store_lib::Store>,
|
||||||
|
runtime_resources: crate::RawTransactionIngestRuntimeResources,
|
||||||
|
) -> ksp_core_lib::Result<crate::RawTransactionIngestHandle> {
|
||||||
|
let runtime = match current_runtime_handle() {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let store_snapshot = store.runtime_snapshot();
|
||||||
|
if let std::result::Result::Err(error) = validate_store_network(&settings, store_snapshot.network()) {
|
||||||
|
return std::result::Result::Err(error);
|
||||||
|
}
|
||||||
|
if let std::result::Result::Err(error) = runtime_resources.validate_network(settings.network()) {
|
||||||
|
return std::result::Result::Err(error);
|
||||||
|
}
|
||||||
|
return start_foundation(settings, runtime, std::option::Option::Some(store));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_stopping(
|
fn begin_stopping(
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
/// Validated Yellowstone plus HTTP runtime source owned by the continuous RAW transaction ingest Worker.
|
||||||
|
///
|
||||||
|
/// The Transport-owned channel, subscribe request, HTTP pool and hydration role remain private. Construction validates only deterministic source-composition
|
||||||
|
/// invariants and performs no network I/O.
|
||||||
|
pub struct RawTransactionIngestYellowstoneSource {
|
||||||
|
yellowstone_channel: ksp_onchain_transport_lib::YellowstoneGrpcChannel,
|
||||||
|
subscribe_request: ksp_onchain_transport_lib::YellowstoneSubscribeRequest,
|
||||||
|
http_pool: ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
hydration_role: ksp_onchain_transport_lib::HttpRoleName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::RawTransactionIngestYellowstoneSource {
|
||||||
|
/// Creates one validated Yellowstone source contract without opening a stream or issuing HTTP requests.
|
||||||
|
pub fn new(
|
||||||
|
yellowstone_channel: ksp_onchain_transport_lib::YellowstoneGrpcChannel,
|
||||||
|
subscribe_request: ksp_onchain_transport_lib::YellowstoneSubscribeRequest,
|
||||||
|
http_pool: ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
hydration_role: ksp_onchain_transport_lib::HttpRoleName,
|
||||||
|
) -> ksp_core_lib::Result<Self> {
|
||||||
|
if subscribe_request.validate().is_err() {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.yellowstone_request_invalid"));
|
||||||
|
}
|
||||||
|
if ingestion_filter_count(&subscribe_request) == 0 {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.ingestion_filter_missing"));
|
||||||
|
}
|
||||||
|
match subscribe_request.commitment() {
|
||||||
|
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)
|
||||||
|
| std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized) => {},
|
||||||
|
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed) | std::option::Option::None => {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.hydration_commitment_invalid"));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
let method = match ksp_onchain_transport_lib::find_http_rpc_method("getTransaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return std::result::Result::Err(crate::runtime_error("runtime_resources.hydration_method_missing")),
|
||||||
|
};
|
||||||
|
let compatible_http_routes = compatible_http_route_count(&http_pool, &hydration_role, method.request_kind(), yellowstone_channel.cluster().as_str());
|
||||||
|
let compatible_http_routes = match compatible_http_routes {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
if compatible_http_routes == 0 {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.hydration_role_unsupported"));
|
||||||
|
}
|
||||||
|
return std::result::Result::Ok(Self { yellowstone_channel, subscribe_request, http_pool, hydration_role });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for crate::RawTransactionIngestYellowstoneSource {
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let http_snapshot = self.http_pool.snapshot();
|
||||||
|
return formatter
|
||||||
|
.debug_struct("RawTransactionIngestYellowstoneSource")
|
||||||
|
.field("yellowstone_endpoint_name", &self.yellowstone_channel.endpoint_name())
|
||||||
|
.field("yellowstone_provider", &self.yellowstone_channel.provider().as_str())
|
||||||
|
.field("network", &self.yellowstone_channel.cluster().as_str())
|
||||||
|
.field("transaction_filter_count", &self.subscribe_request.transaction_filter_count())
|
||||||
|
.field("transaction_status_filter_count", &self.subscribe_request.transaction_status_filter_count())
|
||||||
|
.field("block_filter_count", &self.subscribe_request.block_filter_count())
|
||||||
|
.field("commitment", &self.subscribe_request.commitment())
|
||||||
|
.field("has_from_slot", &self.subscribe_request.from_slot().is_some())
|
||||||
|
.field("hydration_role", &self.hydration_role.as_str())
|
||||||
|
.field("http_endpoint_count", &http_snapshot.endpoint_count())
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Caller-composed runtime resources accepted by the continuous RAW transaction ingest Worker.
|
||||||
|
///
|
||||||
|
/// This first runtime-resource contract owns exactly one Yellowstone source. It deliberately does not expose a provider enum, source collection, callback,
|
||||||
|
/// enqueue surface or lower-layer client escape hatch.
|
||||||
|
pub struct RawTransactionIngestRuntimeResources {
|
||||||
|
yellowstone_source: crate::RawTransactionIngestYellowstoneSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::RawTransactionIngestRuntimeResources {
|
||||||
|
/// Owns the first validated productive-source contract for a future runtime start.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(yellowstone_source: crate::RawTransactionIngestYellowstoneSource) -> Self {
|
||||||
|
return Self { yellowstone_source };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates that caller-owned Worker settings target the same logical network as the composed Yellowstone/HTTP source.
|
||||||
|
pub(crate) fn validate_network(&self, network: &ksp_store_lib::RawNetworkId) -> ksp_core_lib::Result<()> {
|
||||||
|
if self.yellowstone_source.yellowstone_channel.cluster().as_str() != network.as_str() {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.worker_network_mismatch"));
|
||||||
|
}
|
||||||
|
return std::result::Result::Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for crate::RawTransactionIngestRuntimeResources {
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
return formatter.debug_struct("RawTransactionIngestRuntimeResources").field("yellowstone_source", &self.yellowstone_source).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible_http_route_count(
|
||||||
|
pool: &ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
hydration_role: &ksp_onchain_transport_lib::HttpRoleName,
|
||||||
|
request_kind: &str,
|
||||||
|
expected_cluster: &str,
|
||||||
|
) -> ksp_core_lib::Result<usize> {
|
||||||
|
let snapshot = pool.snapshot();
|
||||||
|
let mut compatible = 0_usize;
|
||||||
|
for endpoint in snapshot.endpoints() {
|
||||||
|
if !endpoint.enabled() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for role in endpoint.roles() {
|
||||||
|
if !role.enabled() || role.role() != hydration_role.as_str() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let supports_request = role.request_kinds().iter().any(|kind| return kind.as_str() == "*" || kind.as_str() == request_kind);
|
||||||
|
if !supports_request {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if endpoint.cluster() != expected_cluster {
|
||||||
|
return std::result::Result::Err(crate::runtime_error("runtime_resources.transport_network_mismatch"));
|
||||||
|
}
|
||||||
|
compatible = compatible.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::result::Result::Ok(compatible);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ingestion_filter_count(request: &ksp_onchain_transport_lib::YellowstoneSubscribeRequest) -> usize {
|
||||||
|
return request.transaction_filter_count().saturating_add(request.transaction_status_filter_count()).saturating_add(request.block_filter_count());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "../unit_tests/runtime_resources.rs"]
|
||||||
|
mod tests;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/dependency_boundary.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/dependency_boundary.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
//! Dependency firewall canaries for the RAW transaction ingest Worker foundation.
|
//! Dependency firewall canaries for the RAW transaction ingest Worker foundation.
|
||||||
|
|
||||||
@@ -8,10 +8,23 @@ fn pre_002_manifest_dependency_surface_is_exact() {
|
|||||||
let manifest = include_str!("../Cargo.toml");
|
let manifest = include_str!("../Cargo.toml");
|
||||||
let dependencies = dependency_section(manifest);
|
let dependencies = dependency_section(manifest);
|
||||||
let names = manifest_dependency_names(dependencies);
|
let names = manifest_dependency_names(dependencies);
|
||||||
assert_eq!(names, vec!["ksp-core-lib", "ksp-logging-lib", "ksp-raw-transaction-lib", "ksp-store-lib", "ksp-worker-api", "sha2", "tokio",],);
|
assert_eq!(
|
||||||
|
names,
|
||||||
|
vec![
|
||||||
|
"ksp-core-lib",
|
||||||
|
"ksp-logging-lib",
|
||||||
|
"ksp-onchain-transport-lib",
|
||||||
|
"ksp-raw-transaction-lib",
|
||||||
|
"ksp-store-lib",
|
||||||
|
"ksp-worker-api",
|
||||||
|
"sha2",
|
||||||
|
"tokio",
|
||||||
|
],
|
||||||
|
);
|
||||||
for required in [
|
for required in [
|
||||||
"ksp-core-lib = { path = \"../ksp-core-lib\" }",
|
"ksp-core-lib = { path = \"../ksp-core-lib\" }",
|
||||||
"ksp-logging-lib = { path = \"../ksp-logging-lib\" }",
|
"ksp-logging-lib = { path = \"../ksp-logging-lib\" }",
|
||||||
|
"ksp-onchain-transport-lib = { path = \"../ksp-onchain-transport-lib\" }",
|
||||||
"ksp-raw-transaction-lib = { path = \"../ksp-raw-transaction-lib\" }",
|
"ksp-raw-transaction-lib = { path = \"../ksp-raw-transaction-lib\" }",
|
||||||
"ksp-store-lib = { path = \"../ksp-store-lib\", default-features = false }",
|
"ksp-store-lib = { path = \"../ksp-store-lib\", default-features = false }",
|
||||||
"ksp-worker-api = { path = \"../ksp-worker-api\" }",
|
"ksp-worker-api = { path = \"../ksp-worker-api\" }",
|
||||||
@@ -24,7 +37,7 @@ fn pre_002_manifest_dependency_surface_is_exact() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_002_manifest_keeps_forbidden_layers_and_live_sources_out() {
|
fn v0_3_12_pre_002_manifest_opens_only_the_onchain_transport_live_source_edge() {
|
||||||
let manifest = include_str!("../Cargo.toml");
|
let manifest = include_str!("../Cargo.toml");
|
||||||
let dependencies = dependency_section(manifest);
|
let dependencies = dependency_section(manifest);
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
@@ -33,7 +46,6 @@ fn pre_002_manifest_keeps_forbidden_layers_and_live_sources_out() {
|
|||||||
"ksp-interface-lib",
|
"ksp-interface-lib",
|
||||||
"ksp-job-api",
|
"ksp-job-api",
|
||||||
"ksp-job-backfill-lib",
|
"ksp-job-backfill-lib",
|
||||||
"ksp-onchain-transport-lib",
|
|
||||||
"ksp-program-api",
|
"ksp-program-api",
|
||||||
"ksp-store-api",
|
"ksp-store-api",
|
||||||
"ksp-store-postgres-lib",
|
"ksp-store-postgres-lib",
|
||||||
@@ -52,12 +64,13 @@ fn pre_002_manifest_keeps_forbidden_layers_and_live_sources_out() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_009_source_surface_hardens_shutdown_and_faults_without_backend_or_live_source() {
|
fn v0_3_12_pre_002_source_surface_hardens_shutdown_and_faults_without_backend_or_premature_live_io() {
|
||||||
let root = include_str!("../src/lib.rs");
|
let root = include_str!("../src/lib.rs");
|
||||||
let runtime = include_str!("../src/runtime.rs");
|
let runtime = include_str!("../src/runtime.rs");
|
||||||
let admission = include_str!("../src/admission.rs");
|
let admission = include_str!("../src/admission.rs");
|
||||||
let persistence = include_str!("../src/persistence.rs");
|
let persistence = include_str!("../src/persistence.rs");
|
||||||
let snapshot = include_str!("../src/snapshot.rs");
|
let snapshot = include_str!("../src/snapshot.rs");
|
||||||
|
let runtime_resources = include_str!("../src/runtime_resources.rs");
|
||||||
for required in [
|
for required in [
|
||||||
"tokio::sync::mpsc::channel",
|
"tokio::sync::mpsc::channel",
|
||||||
"canonicalize_raw_transaction",
|
"canonicalize_raw_transaction",
|
||||||
@@ -81,7 +94,8 @@ fn pre_009_source_surface_hardens_shutdown_and_faults_without_backend_or_live_so
|
|||||||
|| runtime.contains(required)
|
|| runtime.contains(required)
|
||||||
|| admission.contains(required)
|
|| admission.contains(required)
|
||||||
|| persistence.contains(required)
|
|| persistence.contains(required)
|
||||||
|| snapshot.contains(required),
|
|| snapshot.contains(required)
|
||||||
|
|| runtime_resources.contains(required),
|
||||||
"required pre.009 hardening contract missing: {required}"
|
"required pre.009 hardening contract missing: {required}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -91,7 +105,6 @@ fn pre_009_source_surface_hardens_shutdown_and_faults_without_backend_or_live_so
|
|||||||
"pub use self::persistence::RawTransactionIngestPersistencePort",
|
"pub use self::persistence::RawTransactionIngestPersistencePort",
|
||||||
"unbounded_channel",
|
"unbounded_channel",
|
||||||
"ksp_store_postgres_lib::",
|
"ksp_store_postgres_lib::",
|
||||||
"ksp_onchain_transport_lib::",
|
|
||||||
"ForceRehydrate",
|
"ForceRehydrate",
|
||||||
"ksp_config_lib::",
|
"ksp_config_lib::",
|
||||||
"reqwest::",
|
"reqwest::",
|
||||||
@@ -101,7 +114,8 @@ fn pre_009_source_surface_hardens_shutdown_and_faults_without_backend_or_live_so
|
|||||||
&& !runtime.contains(forbidden)
|
&& !runtime.contains(forbidden)
|
||||||
&& !admission.contains(forbidden)
|
&& !admission.contains(forbidden)
|
||||||
&& !persistence.contains(forbidden)
|
&& !persistence.contains(forbidden)
|
||||||
&& !snapshot.contains(forbidden),
|
&& !snapshot.contains(forbidden)
|
||||||
|
&& !runtime_resources.contains(forbidden),
|
||||||
"pre.009 crossed a forbidden runtime boundary: {forbidden}"
|
"pre.009 crossed a forbidden runtime boundary: {forbidden}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! External public, security, redaction and release-boundary hardening canaries for `pre.010`.
|
//! External public, security, redaction and release-boundary hardening canaries for `pre.010`.
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ fn pre_010_debug_and_settings_errors_redact_worker_identity_and_invalid_values()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_010_manifest_dependency_surface_remains_exact_source_neutral_and_backend_neutral() {
|
fn v0_3_12_pre_002_manifest_dependency_surface_opens_only_transport_and_remains_backend_neutral() {
|
||||||
let manifest = include_str!("../Cargo.toml");
|
let manifest = include_str!("../Cargo.toml");
|
||||||
let mut section = "";
|
let mut section = "";
|
||||||
let mut normal = std::collections::BTreeSet::new();
|
let mut normal = std::collections::BTreeSet::new();
|
||||||
@@ -121,7 +121,16 @@ fn pre_010_manifest_dependency_surface_remains_exact_source_neutral_and_backend_
|
|||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
normal,
|
normal,
|
||||||
std::collections::BTreeSet::from(["ksp-core-lib", "ksp-logging-lib", "ksp-raw-transaction-lib", "ksp-store-lib", "ksp-worker-api", "sha2", "tokio",])
|
std::collections::BTreeSet::from([
|
||||||
|
"ksp-core-lib",
|
||||||
|
"ksp-logging-lib",
|
||||||
|
"ksp-onchain-transport-lib",
|
||||||
|
"ksp-raw-transaction-lib",
|
||||||
|
"ksp-store-lib",
|
||||||
|
"ksp-worker-api",
|
||||||
|
"sha2",
|
||||||
|
"tokio",
|
||||||
|
])
|
||||||
);
|
);
|
||||||
assert!(dev.is_empty());
|
assert!(dev.is_empty());
|
||||||
assert!(build.is_empty());
|
assert!(build.is_empty());
|
||||||
@@ -131,7 +140,6 @@ fn pre_010_manifest_dependency_surface_remains_exact_source_neutral_and_backend_
|
|||||||
"ksp-config-lib",
|
"ksp-config-lib",
|
||||||
"ksp-job-api",
|
"ksp-job-api",
|
||||||
"ksp-job-backfill-lib",
|
"ksp-job-backfill-lib",
|
||||||
"ksp-onchain-transport-lib",
|
|
||||||
"ksp-store-api",
|
"ksp-store-api",
|
||||||
"ksp-store-postgres-lib",
|
"ksp-store-postgres-lib",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -146,11 +154,12 @@ fn pre_010_manifest_dependency_surface_remains_exact_source_neutral_and_backend_
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_010_source_visibility_contract_uses_crate_root_for_shared_items() {
|
fn pre_010_source_visibility_contract_uses_crate_root_for_shared_items() {
|
||||||
let source_contracts: [(&str, &[&str]); 4] = [
|
let source_contracts: [(&str, &[&str]); 5] = [
|
||||||
(include_str!("../src/settings.rs"), &["RawTransactionIngestSettings"]),
|
(include_str!("../src/settings.rs"), &["RawTransactionIngestSettings"]),
|
||||||
(include_str!("../src/runtime.rs"), &["RawTransactionIngestHandle", "RawTransactionIngestWorker"]),
|
(include_str!("../src/runtime.rs"), &["RawTransactionIngestHandle", "RawTransactionIngestWorker"]),
|
||||||
(include_str!("../src/snapshot.rs"), &["RawTransactionIngestSnapshot", "RawTransactionIngestSnapshotSource"]),
|
(include_str!("../src/snapshot.rs"), &["RawTransactionIngestSnapshot", "RawTransactionIngestSnapshotSource"]),
|
||||||
(include_str!("../src/persistence.rs"), &["RawTransactionIngestPersistenceOutcome", "RawTransactionIngestPersistencePort"]),
|
(include_str!("../src/persistence.rs"), &["RawTransactionIngestPersistenceOutcome", "RawTransactionIngestPersistencePort"]),
|
||||||
|
(include_str!("../src/runtime_resources.rs"), &["RawTransactionIngestYellowstoneSource", "RawTransactionIngestRuntimeResources"]),
|
||||||
];
|
];
|
||||||
for (source, symbols) in source_contracts {
|
for (source, symbols) in source_contracts {
|
||||||
for symbol in symbols {
|
for symbol in symbols {
|
||||||
@@ -166,6 +175,7 @@ fn pre_010_source_visibility_contract_uses_crate_root_for_shared_items() {
|
|||||||
("identity", include_str!("../src/identity.rs")),
|
("identity", include_str!("../src/identity.rs")),
|
||||||
("persistence", include_str!("../src/persistence.rs")),
|
("persistence", include_str!("../src/persistence.rs")),
|
||||||
("runtime", include_str!("../src/runtime.rs")),
|
("runtime", include_str!("../src/runtime.rs")),
|
||||||
|
("runtime_resources", include_str!("../src/runtime_resources.rs")),
|
||||||
("settings", include_str!("../src/settings.rs")),
|
("settings", include_str!("../src/settings.rs")),
|
||||||
("snapshot", include_str!("../src/snapshot.rs")),
|
("snapshot", include_str!("../src/snapshot.rs")),
|
||||||
] {
|
] {
|
||||||
@@ -184,6 +194,7 @@ fn pre_010_production_surface_has_no_historical_backfill_or_retriever_contract()
|
|||||||
include_str!("../src/lib.rs"),
|
include_str!("../src/lib.rs"),
|
||||||
include_str!("../src/persistence.rs"),
|
include_str!("../src/persistence.rs"),
|
||||||
include_str!("../src/runtime.rs"),
|
include_str!("../src/runtime.rs"),
|
||||||
|
include_str!("../src/runtime_resources.rs"),
|
||||||
include_str!("../src/settings.rs"),
|
include_str!("../src/settings.rs"),
|
||||||
include_str!("../src/snapshot.rs"),
|
include_str!("../src/snapshot.rs"),
|
||||||
];
|
];
|
||||||
@@ -198,8 +209,6 @@ fn pre_010_production_surface_has_no_historical_backfill_or_retriever_contract()
|
|||||||
"checkpoint",
|
"checkpoint",
|
||||||
"Discovery",
|
"Discovery",
|
||||||
"discovery",
|
"discovery",
|
||||||
"Hydration",
|
|
||||||
"hydration",
|
|
||||||
"historical",
|
"historical",
|
||||||
] {
|
] {
|
||||||
assert!(!source.contains(forbidden), "historical/retriever surface leaked into Worker production source: {forbidden}");
|
assert!(!source.contains(forbidden), "historical/retriever surface leaked into Worker production source: {forbidden}");
|
||||||
@@ -209,8 +218,39 @@ fn pre_010_production_surface_has_no_historical_backfill_or_retriever_contract()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_010_production_sources_scan_clean_for_config_secrets_backend_and_transport() {
|
fn v0_3_12_pre_002_production_sources_keep_transport_confined_to_runtime_resources() {
|
||||||
let sources = [
|
for source in [
|
||||||
|
include_str!("../src/admission.rs"),
|
||||||
|
include_str!("../src/error.rs"),
|
||||||
|
include_str!("../src/identity.rs"),
|
||||||
|
include_str!("../src/lib.rs"),
|
||||||
|
include_str!("../src/persistence.rs"),
|
||||||
|
include_str!("../src/runtime.rs"),
|
||||||
|
include_str!("../src/runtime_resources.rs"),
|
||||||
|
include_str!("../src/settings.rs"),
|
||||||
|
include_str!("../src/snapshot.rs"),
|
||||||
|
] {
|
||||||
|
let lower = source.to_ascii_lowercase();
|
||||||
|
for forbidden in ["api_key", "api-key", "authorization", "bearer ", "password", "credential", "secret"] {
|
||||||
|
assert!(!lower.contains(forbidden), "secret-like material leaked into Worker production source: {forbidden}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let transport_source = include_str!("../src/runtime_resources.rs");
|
||||||
|
assert!(transport_source.contains("ksp_onchain_transport_lib::"));
|
||||||
|
for forbidden in [
|
||||||
|
"ksp_config_lib::",
|
||||||
|
"ksp_store_postgres_lib::",
|
||||||
|
"ksp_offchain_transport_lib::",
|
||||||
|
"reqwest::",
|
||||||
|
"tokio_tungstenite::",
|
||||||
|
"tonic::",
|
||||||
|
"yellowstone_grpc_proto::",
|
||||||
|
"postgresql://",
|
||||||
|
"postgres://",
|
||||||
|
] {
|
||||||
|
assert!(!transport_source.contains(forbidden), "forbidden implementation detail leaked into runtime resources: {forbidden}");
|
||||||
|
}
|
||||||
|
for source in [
|
||||||
include_str!("../src/admission.rs"),
|
include_str!("../src/admission.rs"),
|
||||||
include_str!("../src/error.rs"),
|
include_str!("../src/error.rs"),
|
||||||
include_str!("../src/identity.rs"),
|
include_str!("../src/identity.rs"),
|
||||||
@@ -219,16 +259,11 @@ fn pre_010_production_sources_scan_clean_for_config_secrets_backend_and_transpor
|
|||||||
include_str!("../src/runtime.rs"),
|
include_str!("../src/runtime.rs"),
|
||||||
include_str!("../src/settings.rs"),
|
include_str!("../src/settings.rs"),
|
||||||
include_str!("../src/snapshot.rs"),
|
include_str!("../src/snapshot.rs"),
|
||||||
];
|
] {
|
||||||
for source in sources {
|
assert!(!source.contains("ksp_onchain_transport_lib::"), "Transport dependency escaped runtime_resources.rs");
|
||||||
let lower = source.to_ascii_lowercase();
|
|
||||||
for forbidden in ["api_key", "api-key", "authorization", "bearer ", "password", "credential", "secret"] {
|
|
||||||
assert!(!lower.contains(forbidden), "secret-like material leaked into Worker production source: {forbidden}");
|
|
||||||
}
|
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"ksp_config_lib::",
|
"ksp_config_lib::",
|
||||||
"ksp_store_postgres_lib::",
|
"ksp_store_postgres_lib::",
|
||||||
"ksp_onchain_transport_lib::",
|
|
||||||
"ksp_offchain_transport_lib::",
|
"ksp_offchain_transport_lib::",
|
||||||
"reqwest::",
|
"reqwest::",
|
||||||
"tokio_tungstenite::",
|
"tokio_tungstenite::",
|
||||||
@@ -237,12 +272,26 @@ fn pre_010_production_sources_scan_clean_for_config_secrets_backend_and_transpor
|
|||||||
"postgresql://",
|
"postgresql://",
|
||||||
"postgres://",
|
"postgres://",
|
||||||
] {
|
] {
|
||||||
assert!(!source.contains(forbidden), "Config/backend/Transport implementation leaked into Worker production source: {forbidden}");
|
assert!(!source.contains(forbidden), "forbidden implementation detail leaked into Worker production source: {forbidden}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn v0_3_12_pre_002_runtime_resource_contract_performs_no_live_io_or_source_spawn() {
|
||||||
|
let resources = include_str!("../src/runtime_resources.rs");
|
||||||
|
let runtime = include_str!("../src/runtime.rs");
|
||||||
|
for forbidden in ["open_standard_subscribe", "next_update", "get_transaction_observed", "get_block_observed", "tokio::spawn", "JoinSet"] {
|
||||||
|
assert!(!resources.contains(forbidden), "pre.002 runtime-resource contract opened premature live behavior: {forbidden}");
|
||||||
|
}
|
||||||
|
assert!(runtime.contains("start_with_runtime_resources"));
|
||||||
|
for forbidden in ["open_standard_subscribe", "next_update", "get_transaction_observed", "get_block_observed"] {
|
||||||
|
assert!(!runtime.contains(forbidden), "pre.002 runtime start opened premature live behavior: {forbidden}");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_010_lower_layers_have_no_dependency_return_to_concrete_worker() {
|
fn pre_010_lower_layers_have_no_dependency_return_to_concrete_worker() {
|
||||||
for manifest in [
|
for manifest in [
|
||||||
@@ -260,7 +309,7 @@ fn pre_010_lower_layers_have_no_dependency_return_to_concrete_worker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_010_public_root_exposes_no_runtime_backend_or_live_source_implementation_types() {
|
fn v0_3_12_pre_002_public_root_exposes_contract_types_without_transport_implementation_paths() {
|
||||||
let root = include_str!("../src/lib.rs");
|
let root = include_str!("../src/lib.rs");
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"pub mod ",
|
"pub mod ",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/public_api.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/public_api.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
//! External public-surface proofs for the RAW transaction ingest Worker foundation.
|
//! External public-surface proofs for the RAW transaction ingest Worker foundation.
|
||||||
|
|
||||||
@@ -135,3 +135,37 @@ fn pre_009_source_and_drain_timeout_error_codes_are_public_and_stable() {
|
|||||||
assert_eq!(ksp_worker_raw_transaction_ingest_lib::ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED.code(), "source_failed");
|
assert_eq!(ksp_worker_raw_transaction_ingest_lib::ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED.code(), "source_failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn v0_3_12_pre_002_runtime_resource_types_are_consumable_without_client_escape_hatch() {
|
||||||
|
let _source_new: fn(
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcChannel,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneSubscribeRequest,
|
||||||
|
ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
ksp_onchain_transport_lib::HttpRoleName,
|
||||||
|
) -> ksp_core_lib::Result<ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestYellowstoneSource> =
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestYellowstoneSource::new;
|
||||||
|
let _resources_new: fn(
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestYellowstoneSource,
|
||||||
|
) -> ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestRuntimeResources =
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestRuntimeResources::new;
|
||||||
|
let _start_with_resources: fn(
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings,
|
||||||
|
std::sync::Arc<ksp_store_lib::Store>,
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestRuntimeResources,
|
||||||
|
) -> ksp_core_lib::Result<ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestHandle> =
|
||||||
|
ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start_with_runtime_resources;
|
||||||
|
let source = include_str!("../src/runtime_resources.rs");
|
||||||
|
for forbidden in [
|
||||||
|
"pub fn channel(",
|
||||||
|
"pub fn http_pool(",
|
||||||
|
"pub fn subscribe_request(",
|
||||||
|
"pub fn hydration_role(",
|
||||||
|
"pub fn enqueue(",
|
||||||
|
"pub fn send(",
|
||||||
|
"pub fn inner(",
|
||||||
|
] {
|
||||||
|
assert!(!source.contains(forbidden), "runtime-resource implementation escape hatch present: {forbidden}");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Release-completeness canaries through the `pre.010` public/release/security hardening tranche.
|
//! Release-completeness canaries through the `pre.010` public/release/security hardening tranche.
|
||||||
|
|
||||||
@@ -32,7 +32,10 @@ fn pre_010_production_module_inventory_is_exact() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
names.sort_unstable();
|
names.sort_unstable();
|
||||||
assert_eq!(names, std::vec!["admission.rs", "error.rs", "identity.rs", "lib.rs", "persistence.rs", "runtime.rs", "settings.rs", "snapshot.rs",]);
|
assert_eq!(
|
||||||
|
names,
|
||||||
|
std::vec!["admission.rs", "error.rs", "identity.rs", "lib.rs", "persistence.rs", "runtime.rs", "runtime_resources.rs", "settings.rs", "snapshot.rs",]
|
||||||
|
);
|
||||||
return std::result::Result::Ok(());
|
return std::result::Result::Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,12 +77,14 @@ fn pre_010_public_root_export_inventory_is_exact() {
|
|||||||
"MIN_RAW_TRANSACTION_INGEST_SHUTDOWN_DRAIN_TIMEOUT",
|
"MIN_RAW_TRANSACTION_INGEST_SHUTDOWN_DRAIN_TIMEOUT",
|
||||||
"RAW_TRANSACTION_INGEST_WORKER_KIND_CODE",
|
"RAW_TRANSACTION_INGEST_WORKER_KIND_CODE",
|
||||||
"RawTransactionIngestHandle",
|
"RawTransactionIngestHandle",
|
||||||
|
"RawTransactionIngestRuntimeResources",
|
||||||
"RawTransactionIngestSettings",
|
"RawTransactionIngestSettings",
|
||||||
"RawTransactionIngestSnapshot",
|
"RawTransactionIngestSnapshot",
|
||||||
"RawTransactionIngestSnapshotFuture",
|
"RawTransactionIngestSnapshotFuture",
|
||||||
"RawTransactionIngestSnapshotSource",
|
"RawTransactionIngestSnapshotSource",
|
||||||
"RawTransactionIngestTerminalFuture",
|
"RawTransactionIngestTerminalFuture",
|
||||||
"RawTransactionIngestWorker",
|
"RawTransactionIngestWorker",
|
||||||
|
"RawTransactionIngestYellowstoneSource",
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert!(!root.contains("pub mod "));
|
assert!(!root.contains("pub mod "));
|
||||||
@@ -92,22 +97,25 @@ fn pre_010_external_hardening_suite_is_present_and_scoped() {
|
|||||||
for required in [
|
for required in [
|
||||||
"pre_010_external_error_codes_are_stable_unique_and_domain_scoped",
|
"pre_010_external_error_codes_are_stable_unique_and_domain_scoped",
|
||||||
"pre_010_debug_and_settings_errors_redact_worker_identity_and_invalid_values",
|
"pre_010_debug_and_settings_errors_redact_worker_identity_and_invalid_values",
|
||||||
"pre_010_manifest_dependency_surface_remains_exact_source_neutral_and_backend_neutral",
|
"v0_3_12_pre_002_manifest_dependency_surface_opens_only_transport_and_remains_backend_neutral",
|
||||||
"pre_010_source_visibility_contract_uses_crate_root_for_shared_items",
|
"pre_010_source_visibility_contract_uses_crate_root_for_shared_items",
|
||||||
"pre_010_production_surface_has_no_historical_backfill_or_retriever_contract",
|
"pre_010_production_surface_has_no_historical_backfill_or_retriever_contract",
|
||||||
"pre_010_production_sources_scan_clean_for_config_secrets_backend_and_transport",
|
"v0_3_12_pre_002_production_sources_keep_transport_confined_to_runtime_resources",
|
||||||
|
"v0_3_12_pre_002_runtime_resource_contract_performs_no_live_io_or_source_spawn",
|
||||||
"pre_010_lower_layers_have_no_dependency_return_to_concrete_worker",
|
"pre_010_lower_layers_have_no_dependency_return_to_concrete_worker",
|
||||||
"pre_010_public_root_exposes_no_runtime_backend_or_live_source_implementation_types",
|
"v0_3_12_pre_002_public_root_exposes_contract_types_without_transport_implementation_paths",
|
||||||
] {
|
] {
|
||||||
assert!(hardening.contains(required), "required pre.010 hardening canary missing: {required}");
|
assert!(hardening.contains(required), "required pre.010 hardening canary missing: {required}");
|
||||||
}
|
}
|
||||||
let dependency_boundary = include_str!("dependency_boundary.rs");
|
let dependency_boundary = include_str!("dependency_boundary.rs");
|
||||||
assert!(dependency_boundary.contains("pre_002_manifest_dependency_surface_is_exact"));
|
assert!(dependency_boundary.contains("pre_002_manifest_dependency_surface_is_exact"));
|
||||||
assert!(dependency_boundary.contains("pre_009_source_surface_hardens_shutdown_and_faults_without_backend_or_live_source"));
|
assert!(dependency_boundary.contains("v0_3_12_pre_002_source_surface_hardens_shutdown_and_faults_without_backend_or_premature_live_io"));
|
||||||
|
assert!(dependency_boundary.contains("v0_3_12_pre_002_manifest_opens_only_the_onchain_transport_live_source_edge"));
|
||||||
let public_api = include_str!("public_api.rs");
|
let public_api = include_str!("public_api.rs");
|
||||||
assert!(public_api.contains("pre_003_kind_code_and_settings_are_consumable_from_crate_root"));
|
assert!(public_api.contains("pre_003_kind_code_and_settings_are_consumable_from_crate_root"));
|
||||||
assert!(public_api.contains("pre_004_start_handle_and_terminal_future_are_consumable_without_public_join_handle"));
|
assert!(public_api.contains("pre_004_start_handle_and_terminal_future_are_consumable_without_public_join_handle"));
|
||||||
assert!(public_api.contains("pre_008_snapshot_surface_and_common_projection_are_public_and_stable"));
|
assert!(public_api.contains("pre_008_snapshot_surface_and_common_projection_are_public_and_stable"));
|
||||||
assert!(public_api.contains("pre_009_source_and_drain_timeout_error_codes_are_public_and_stable"));
|
assert!(public_api.contains("pre_009_source_and_drain_timeout_error_codes_are_public_and_stable"));
|
||||||
|
assert!(public_api.contains("v0_3_12_pre_002_runtime_resource_types_are_consumable_without_client_escape_hatch"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
// file: crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
fn grpc_endpoint(cluster: &str) -> std::option::Option<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings> {
|
||||||
|
let url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse("http://127.0.0.1:10000/GRPC-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::YellowstoneGrpcEndpointSettings::new(
|
||||||
|
"yellowstone-fixture",
|
||||||
|
true,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new("fixture-provider"),
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new(cluster),
|
||||||
|
url,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn http_pool(cluster: &str, role_name: &str, request_kind: &str) -> std::option::Option<ksp_onchain_transport_lib::HttpTransportPool> {
|
||||||
|
let url = match ksp_onchain_transport_lib::HttpEndpointUrl::parse("https://fixture.invalid/rpc?token=HTTP-SECRET-CANARY") {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return std::option::Option::None,
|
||||||
|
};
|
||||||
|
let role = ksp_onchain_transport_lib::HttpEndpointRoleSettings::new(
|
||||||
|
ksp_onchain_transport_lib::HttpRoleName::new(role_name),
|
||||||
|
true,
|
||||||
|
std::vec![ksp_onchain_transport_lib::HttpRequestKind::new(request_kind)],
|
||||||
|
10,
|
||||||
|
ksp_onchain_transport_lib::HttpRoleLimits::new(
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let endpoint = ksp_onchain_transport_lib::HttpEndpointSettings::new(
|
||||||
|
"http-fixture",
|
||||||
|
true,
|
||||||
|
ksp_onchain_transport_lib::HttpProviderName::new("fixture-provider"),
|
||||||
|
ksp_onchain_transport_lib::HttpClusterName::new(cluster),
|
||||||
|
url,
|
||||||
|
std::time::Duration::from_secs(1),
|
||||||
|
std::time::Duration::from_secs(2),
|
||||||
|
std::option::Option::Some(4),
|
||||||
|
std::vec![role],
|
||||||
|
);
|
||||||
|
let settings = ksp_onchain_transport_lib::HttpTransportSettings::new(
|
||||||
|
std::vec![endpoint],
|
||||||
|
ksp_onchain_transport_lib::HttpRetrySettings::new(1, std::time::Duration::from_millis(10), std::time::Duration::from_millis(20)),
|
||||||
|
);
|
||||||
|
return match ksp_onchain_transport_lib::HttpTransportPool::new(settings) {
|
||||||
|
std::result::Result::Ok(value) => std::option::Option::Some(value),
|
||||||
|
std::result::Result::Err(_) => std::option::Option::None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction_request(
|
||||||
|
commitment: std::option::Option<ksp_onchain_transport_lib::SolanaCommitment>,
|
||||||
|
) -> std::option::Option<ksp_onchain_transport_lib::YellowstoneSubscribeRequest> {
|
||||||
|
let name = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new("tx-fixture") {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return std::option::Option::None,
|
||||||
|
};
|
||||||
|
let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new();
|
||||||
|
if request.insert_transaction_filter(name, ksp_onchain_transport_lib::YellowstoneSubscribeTransactionFilter::new()).is_err() {
|
||||||
|
return std::option::Option::None;
|
||||||
|
}
|
||||||
|
request.set_commitment(commitment);
|
||||||
|
return std::option::Option::Some(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_source_accepts_matching_confirmed_transaction_and_get_transaction_route_without_io() {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let pool = match http_pool("devnet", "hydration", "get_transaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration"));
|
||||||
|
assert!(source.is_ok());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_source_rejects_processed_and_implicit_commitment() {
|
||||||
|
for commitment in [std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed), std::option::Option::None] {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let request = match transaction_request(commitment) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let pool = match http_pool("devnet", "hydration", "get_transaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration"));
|
||||||
|
let error = match source {
|
||||||
|
std::result::Result::Ok(_) => return,
|
||||||
|
std::result::Result::Err(error) => error,
|
||||||
|
};
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||||
|
assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.hydration_commitment_invalid"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_source_requires_ingestion_bearing_filter_family() {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new();
|
||||||
|
request.set_commitment(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized));
|
||||||
|
let pool = match http_pool("devnet", "hydration", "get_transaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration"));
|
||||||
|
let error = match source {
|
||||||
|
std::result::Result::Ok(_) => return,
|
||||||
|
std::result::Result::Err(error) => error,
|
||||||
|
};
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||||
|
assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.ingestion_filter_missing"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_source_rejects_missing_hydration_capability_and_cross_transport_network() {
|
||||||
|
for (http_cluster, request_kind, expected_condition) in [
|
||||||
|
("devnet", "get_balance", "runtime_resources.hydration_role_unsupported"),
|
||||||
|
("mainnet", "get_transaction", "runtime_resources.transport_network_mismatch"),
|
||||||
|
] {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let pool = match http_pool(http_cluster, "hydration", request_kind) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration"));
|
||||||
|
let error = match source {
|
||||||
|
std::result::Result::Ok(_) => return,
|
||||||
|
std::result::Result::Err(error) => error,
|
||||||
|
};
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||||
|
assert!(error.context().iter().any(|context| return context.value() == expected_condition));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_runtime_resource_debug_is_safe_and_exposes_no_client_inner() {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let pool = match http_pool("devnet", "hydration", "get_transaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = match crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let resources = crate::RawTransactionIngestRuntimeResources::new(source);
|
||||||
|
let debug = std::format!("{resources:?}");
|
||||||
|
assert!(debug.contains("RawTransactionIngestRuntimeResources"));
|
||||||
|
assert!(debug.contains("devnet"));
|
||||||
|
assert!(!debug.contains("GRPC-SECRET-CANARY"));
|
||||||
|
assert!(!debug.contains("HTTP-SECRET-CANARY"));
|
||||||
|
assert!(!debug.contains("127.0.0.1"));
|
||||||
|
assert!(!debug.contains("fixture.invalid"));
|
||||||
|
assert!(!debug.contains("tx-fixture"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
async fn pre_002_runtime_resources_reject_worker_network_mismatch_without_starting_source() {
|
||||||
|
let endpoint = match grpc_endpoint("devnet") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let pool = match http_pool("devnet", "hydration", "get_transaction") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let source = match crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")) {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let resources = crate::RawTransactionIngestRuntimeResources::new(source);
|
||||||
|
let network = match ksp_store_lib::RawNetworkId::new("mainnet") {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let error = match resources.validate_network(&network) {
|
||||||
|
std::result::Result::Ok(()) => return,
|
||||||
|
std::result::Result::Err(error) => error,
|
||||||
|
};
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||||
|
assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.worker_network_mismatch"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
261
deltas/0.3.12/pre.002.md
Normal file
261
deltas/0.3.12/pre.002.md
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
<!-- file: deltas/0.3.12/pre.002.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.3.12-pre.002` — edge Transport + contrats runtime/source Yellowstone
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.3.12-pre.001
|
||||||
|
workspace.package.version = 0.3.12-pre.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Le gate opérateur communiqué pour `pre.001` est vert sur :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all
|
||||||
|
Rust rule audit
|
||||||
|
Markdown table audit
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
|
```
|
||||||
|
|
||||||
|
Le journal ne contient pas de `cargo test` ni de `cargo tree` ; ces commandes ne sont pas inventées comme PASS.
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Ouvrir uniquement le nouvel edge de production décidé en `pre.001` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
ksp-worker-raw-transaction-ingest-lib -> ksp-onchain-transport-lib
|
||||||
|
```
|
||||||
|
|
||||||
|
et matérialiser les contrats Worker-owned nécessaires à la future source Yellowstone + hydration HTTP, sans ouvrir de stream ni exécuter de requête réseau.
|
||||||
|
|
||||||
|
## Version
|
||||||
|
|
||||||
|
Cette tranche est une prerelease non-fix :
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = 0.3.12-pre.2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Graphe Worker normal attendu
|
||||||
|
|
||||||
|
```text
|
||||||
|
ksp-core-lib
|
||||||
|
ksp-logging-lib
|
||||||
|
ksp-onchain-transport-lib
|
||||||
|
ksp-raw-transaction-lib
|
||||||
|
ksp-store-lib default-features=false
|
||||||
|
ksp-worker-api
|
||||||
|
sha2
|
||||||
|
tokio macros,rt,sync,time
|
||||||
|
```
|
||||||
|
|
||||||
|
Toujours interdits directement au Worker :
|
||||||
|
|
||||||
|
```text
|
||||||
|
ksp-config-lib
|
||||||
|
ksp-job-api
|
||||||
|
ksp-job-backfill-lib
|
||||||
|
ksp-store-api
|
||||||
|
ksp-store-postgres-lib
|
||||||
|
reqwest
|
||||||
|
tokio-tungstenite
|
||||||
|
tonic
|
||||||
|
yellowstone-grpc-proto
|
||||||
|
SDK provider
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nouveau contrat `RawTransactionIngestYellowstoneSource`
|
||||||
|
|
||||||
|
Le type public à champs privés possède :
|
||||||
|
|
||||||
|
```text
|
||||||
|
YellowstoneGrpcChannel
|
||||||
|
YellowstoneSubscribeRequest
|
||||||
|
HttpTransportPool
|
||||||
|
HttpRoleName d'hydration
|
||||||
|
```
|
||||||
|
|
||||||
|
`RawTransactionIngestYellowstoneSource::new(...)` valide sans I/O :
|
||||||
|
|
||||||
|
```text
|
||||||
|
request Yellowstone valide
|
||||||
|
au moins une famille transactions / transactions_status / blocks
|
||||||
|
commitment explicite confirmed ou finalized
|
||||||
|
présence d'une route HTTP configurée compatible get_transaction
|
||||||
|
cohérence cluster entre Yellowstone et toutes les routes HTTP compatibles
|
||||||
|
```
|
||||||
|
|
||||||
|
Les erreurs de composition sont projetées sur `worker_raw_transaction_ingest.runtime_invalid` avec uniquement une condition stable et sûre.
|
||||||
|
|
||||||
|
## Nouveau contrat `RawTransactionIngestRuntimeResources`
|
||||||
|
|
||||||
|
`RawTransactionIngestRuntimeResources::new(yellowstone_source)` possède exactement cette première famille runtime.
|
||||||
|
|
||||||
|
Aucune collection multi-source, enum provider, closure source, callback public, `enqueue`, `send`, getter de client interne ou backend n'est exposé.
|
||||||
|
|
||||||
|
La ressource valide également la cohérence entre le réseau du source composé et `RawTransactionIngestSettings.network` avant le démarrage.
|
||||||
|
|
||||||
|
## Nouveau start de composition
|
||||||
|
|
||||||
|
Ajout :
|
||||||
|
|
||||||
|
```text
|
||||||
|
RawTransactionIngestWorker::start_with_runtime_resources(
|
||||||
|
settings,
|
||||||
|
Arc<Store>,
|
||||||
|
RawTransactionIngestRuntimeResources,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
La méthode conserve :
|
||||||
|
|
||||||
|
```text
|
||||||
|
runtime Tokio caller-owned
|
||||||
|
validation réseau Store/settings
|
||||||
|
validation réseau Worker/source
|
||||||
|
handle/snapshot/shutdown existants
|
||||||
|
```
|
||||||
|
|
||||||
|
En `pre.002`, les ressources sont volontairement validées mais ne sont pas activées avant délégation au runtime source-neutral existant. Cela ferme l'API de composition sans anticiper `pre.006`.
|
||||||
|
|
||||||
|
## Absence volontaire de comportement live
|
||||||
|
|
||||||
|
Les canaris interdisent dans cette tranche :
|
||||||
|
|
||||||
|
```text
|
||||||
|
open_standard_subscribe
|
||||||
|
next_update
|
||||||
|
get_transaction_observed
|
||||||
|
get_block_observed
|
||||||
|
source task spawn spécifique
|
||||||
|
nouveau JoinSet
|
||||||
|
HTTP hydration
|
||||||
|
persistence issue du réseau
|
||||||
|
```
|
||||||
|
|
||||||
|
`pre.003` reste donc libre d'introduire uniquement les adapters déterministes `Transaction`/`TransactionStatus`, tandis que l'activation productive de la source reste réservée à `pre.006`.
|
||||||
|
|
||||||
|
## Sécurité et redaction
|
||||||
|
|
||||||
|
Le `Debug` des ressources expose uniquement des métadonnées sûres :
|
||||||
|
|
||||||
|
```text
|
||||||
|
logical Yellowstone endpoint name
|
||||||
|
provider
|
||||||
|
network
|
||||||
|
filter counts
|
||||||
|
commitment
|
||||||
|
presence from_slot
|
||||||
|
hydration role
|
||||||
|
HTTP endpoint count
|
||||||
|
```
|
||||||
|
|
||||||
|
Il n'expose ni URL, token, header, filter name ni client interne.
|
||||||
|
|
||||||
|
Tests déterministes ajoutés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
acceptation confirmed + transaction + get_transaction
|
||||||
|
rejet processed
|
||||||
|
rejet commitment implicite
|
||||||
|
rejet absence de famille ingestion-bearing
|
||||||
|
rejet rôle HTTP non compatible
|
||||||
|
rejet mismatch Yellowstone/HTTP cluster
|
||||||
|
rejet mismatch Worker/source network
|
||||||
|
Debug redaction
|
||||||
|
public API/root contract
|
||||||
|
manifest/dependency firewall
|
||||||
|
Transport confiné à runtime_resources.rs
|
||||||
|
absence de live I/O en pre.002
|
||||||
|
```
|
||||||
|
|
||||||
|
## Décisions prises
|
||||||
|
|
||||||
|
```text
|
||||||
|
un seul nouvel edge productif Worker -> Onchain Transport
|
||||||
|
composition fournie par l'appelant, sans dépendance Worker -> Config
|
||||||
|
ressources Transport encapsulées par des types Worker-owned à champs privés
|
||||||
|
commitment de la future hydration limité à confirmed/finalized dès la composition
|
||||||
|
aucune activation réseau avant la tranche productive prévue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Questions ouvertes
|
||||||
|
|
||||||
|
Aucune question ouverte n'est bloquante pour `pre.002`. Les choix volontairement reportés restent ceux du plan actif : forme exacte du signal privé `Transaction`/`TransactionStatus` en `pre.003`, provenance Yellowstone + hydration en `pre.004`, puis continuité/replay dans les tranches dédiées.
|
||||||
|
|
||||||
|
## Fichiers ajoutés
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs
|
||||||
|
deltas/0.3.12/pre.002.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/Cargo.toml
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/tests/dependency_boundary.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/tests/public_api.rs
|
||||||
|
crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
|
||||||
|
docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers supprimés
|
||||||
|
|
||||||
|
Aucun.
|
||||||
|
|
||||||
|
## Validations exécutées dans l'environnement d'assemblage
|
||||||
|
|
||||||
|
```text
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
General Rust rule audit: clean
|
||||||
|
Rust export completeness audit: 0 candidate(s)
|
||||||
|
KSP workspace Rust rule audit: clean
|
||||||
|
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas
|
||||||
|
Markdown table audit: clean (340 table(s), 802 file(s))
|
||||||
|
```
|
||||||
|
|
||||||
|
`cargo`, `rustc` et `rustfmt` ne sont pas installés dans l'environnement d'assemblage. Aucun gate Cargo local n'est déclaré PASS.
|
||||||
|
|
||||||
|
## Gate opérateur demandé
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
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
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
|
cargo test -p ksp-worker-raw-transaction-ingest-lib
|
||||||
|
cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal
|
||||||
|
cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
|
||||||
|
cargo tree --duplicates
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non-claims
|
||||||
|
|
||||||
|
Cette tranche ne revendique pas :
|
||||||
|
|
||||||
|
```text
|
||||||
|
session Yellowstone ouverte
|
||||||
|
signal Transaction/TransactionStatus produit
|
||||||
|
hydration HTTP exécutée
|
||||||
|
provenance composite assemblée
|
||||||
|
coalescence d'hydration
|
||||||
|
frontier/replay/repair
|
||||||
|
smoke live Worker
|
||||||
|
réconciliation documentaire finale README/USAGE/architecture
|
||||||
|
```
|
||||||
|
|
||||||
|
## Suite
|
||||||
|
|
||||||
|
Après gate opérateur vert, `pre.003` adapte uniquement `YellowstoneTransactionUpdate` et `YellowstoneTransactionStatusUpdate` vers le signal Worker privé prévu par le plan, sans HTTP ni persistence réseau.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md -->
|
<!-- file: docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
|
|
||||||
# Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction
|
# Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction
|
||||||
|
|
||||||
@@ -531,3 +531,120 @@ maintien/split décidé
|
|||||||
plan + validation + delta créés
|
plan + validation + delta créés
|
||||||
audits statiques post-modification verts
|
audits statiques post-modification verts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 22. Gate opérateur reçu pour `pre.001`
|
||||||
|
|
||||||
|
L'opérateur a exécuté après application de `pre.001` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all : sans erreur visible
|
||||||
|
audit Rust : clean
|
||||||
|
Rust export completeness : 0 candidate
|
||||||
|
KSP workspace Rust rule audit : clean
|
||||||
|
audit Markdown : clean (340 tables, 801 fichiers)
|
||||||
|
cargo check --workspace : PASS visible
|
||||||
|
cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS visible
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun `cargo test` ou `cargo tree` n'est présent dans ce journal ; ils ne sont donc pas revendiqués pour ce gate.
|
||||||
|
|
||||||
|
Résultat : `pre.001` est accepté comme base technique de `pre.002`.
|
||||||
|
|
||||||
|
## 23. Gate `pre.002` — edge Transport + contrats runtime/source
|
||||||
|
|
||||||
|
La tranche matérialise exactement :
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = 0.3.12-pre.2
|
||||||
|
Worker -> ksp-onchain-transport-lib
|
||||||
|
RawTransactionIngestYellowstoneSource
|
||||||
|
RawTransactionIngestRuntimeResources
|
||||||
|
RawTransactionIngestWorker::start_with_runtime_resources(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Le constructeur `RawTransactionIngestYellowstoneSource::new` effectue uniquement des validations déterministes sans I/O :
|
||||||
|
|
||||||
|
```text
|
||||||
|
YellowstoneSubscribeRequest::validate
|
||||||
|
au moins une famille transactions / transactions_status / blocks
|
||||||
|
commitment explicite confirmed ou finalized
|
||||||
|
rôle HTTP configuré compatible avec le request kind get_transaction
|
||||||
|
cluster identique entre Yellowstone et toutes les routes HTTP compatibles
|
||||||
|
```
|
||||||
|
|
||||||
|
`RawTransactionIngestRuntimeResources` conserve un seul source Yellowstone à champs privés et vérifie la cohérence avec `RawTransactionIngestSettings.network` avant le démarrage.
|
||||||
|
|
||||||
|
`start_with_runtime_resources` préserve également le gate Store/settings existant. En `pre.002`, il ne démarre volontairement encore aucun source live : les ressources sont validées mais ne sont pas activées, puis le démarrage délègue au runtime source-neutral existant. L'activation du stream reste réservée à `pre.006` conformément au plan.
|
||||||
|
|
||||||
|
## 24. Canaris déterministes ajoutés en `pre.002`
|
||||||
|
|
||||||
|
Les preuves statiques/unitaires ajoutées couvrent :
|
||||||
|
|
||||||
|
```text
|
||||||
|
manifest Worker exact avec un seul nouvel edge Transport
|
||||||
|
aucun Config / Job / backend Store / tonic / reqwest / yellowstone-grpc-proto direct
|
||||||
|
source confirmed + transaction + getTransaction route accepté
|
||||||
|
processed et commitment implicite rejetés
|
||||||
|
absence de famille d'ingestion rejetée
|
||||||
|
rôle HTTP sans get_transaction rejeté
|
||||||
|
mismatch cluster Yellowstone/HTTP rejeté
|
||||||
|
mismatch réseau Worker/source rejeté
|
||||||
|
Debug sans URL, token, filter name ou client inner
|
||||||
|
API publique des deux resource types disponible depuis crate root
|
||||||
|
start_with_runtime_resources disponible depuis crate root
|
||||||
|
aucun enqueue/send/inner/client getter public
|
||||||
|
aucun open_standard_subscribe / next_update / get_transaction_observed dans la tranche
|
||||||
|
Transport confiné à runtime_resources.rs dans les sources Worker
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun nouveau code Config, Store backend, Backfill ou provider n'est introduit.
|
||||||
|
|
||||||
|
## 25. Validation locale après modification de `pre.002`
|
||||||
|
|
||||||
|
Exécuté dans l'environnement d'assemblage :
|
||||||
|
|
||||||
|
```text
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
General Rust rule audit: clean
|
||||||
|
Rust export completeness audit: 0 candidate(s)
|
||||||
|
KSP workspace Rust rule audit: clean
|
||||||
|
```
|
||||||
|
|
||||||
|
L'audit Markdown est rejoué après création du delta final afin d'inclure le nouveau fichier `deltas/0.3.12/pre.002.md`.
|
||||||
|
|
||||||
|
`cargo`, `rustc` et `rustfmt` ne sont pas installés dans cet environnement ; aucun gate Cargo local n'est revendiqué.
|
||||||
|
|
||||||
|
Gate opérateur demandé après application du delta :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
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
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
|
cargo test -p ksp-worker-raw-transaction-ingest-lib
|
||||||
|
cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal
|
||||||
|
cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
|
||||||
|
cargo tree --duplicates
|
||||||
|
```
|
||||||
|
|
||||||
|
## 26. Non-claims `pre.002`
|
||||||
|
|
||||||
|
`pre.002` ne prétend pas avoir :
|
||||||
|
|
||||||
|
```text
|
||||||
|
ouvert une session Yellowstone
|
||||||
|
lu une update Transaction/TransactionStatus/Block
|
||||||
|
émis un signal Worker privé
|
||||||
|
appelé getTransaction pour hydration
|
||||||
|
assemblé une provenance composite
|
||||||
|
persisté une transaction issue du réseau
|
||||||
|
coalescé des hydrations
|
||||||
|
modifié la processing frontier
|
||||||
|
branché from_slot/replay info
|
||||||
|
exécuté un smoke live Worker
|
||||||
|
réconcilié README/USAGE/architecture pour la surface finale 0.3.12
|
||||||
|
```
|
||||||
|
|
||||||
|
La tranche suivante reste `pre.003` : adaptation déterministe `Transaction` + `TransactionStatus` vers le signal Worker privé, sans HTTP ni persistence réseau.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user