v0.3.5-pre.002
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 383
|
# version: 384
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.3.5-pre.1"
|
version = "0.3.5-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,20 +1,21 @@
|
|||||||
// file: crates/ksp-interface-lib/src/lib.rs
|
// file: crates/ksp-interface-lib/src/lib.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
//! Passive wire contracts shared by KSP Program implementations.
|
//! Passive contracts shared across KSP component boundaries.
|
||||||
//!
|
//!
|
||||||
//! The foundation reuses the canonical Solana [`Pubkey`] owned by
|
//! The crate reuses canonical Solana primitives owned by `ksp-core-lib` and
|
||||||
//! `ksp-core-lib` and exposes only bounded, passive Program-facing structures.
|
//! exposes only bounded, passive Program-facing and provider-neutral
|
||||||
//! Runtime, transport, persistence and Program behavior remain outside this
|
//! acquisition structures. Runtime, transport, persistence and Program
|
||||||
//! crate.
|
//! behavior remain outside this crate.
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod program_account_meta;
|
mod program_account_meta;
|
||||||
mod program_instruction;
|
mod program_instruction;
|
||||||
|
mod slot_lifecycle;
|
||||||
|
|
||||||
/// Error code used when an Interface-owned Program instruction admission limit is exceeded.
|
/// Error code used when an Interface-owned Program instruction admission limit is exceeded.
|
||||||
pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;
|
pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;
|
||||||
@@ -26,5 +27,9 @@ pub use self::program_account_meta::ProgramAccountMeta;
|
|||||||
pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;
|
pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;
|
||||||
/// Passive, bounded Program instruction wire contract.
|
/// Passive, bounded Program instruction wire contract.
|
||||||
pub use self::program_instruction::ProgramInstruction;
|
pub use self::program_instruction::ProgramInstruction;
|
||||||
|
/// Passive provider-neutral occurrence of one slot lifecycle stage.
|
||||||
|
pub use self::slot_lifecycle::SlotLifecycleEvent;
|
||||||
|
/// Provider-neutral stage in the lifecycle of an observed Solana slot.
|
||||||
|
pub use self::slot_lifecycle::SlotLifecycleStage;
|
||||||
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
|
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
|
||||||
pub use ksp_core_lib::Pubkey;
|
pub use ksp_core_lib::Pubkey;
|
||||||
|
|||||||
53
crates/ksp-interface-lib/src/slot_lifecycle.rs
Normal file
53
crates/ksp-interface-lib/src/slot_lifecycle.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// file: crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
/// Provider-neutral stage in the lifecycle of an observed Solana slot.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum SlotLifecycleStage {
|
||||||
|
/// The slot has been processed.
|
||||||
|
Processed,
|
||||||
|
/// The first shred for the slot has been received.
|
||||||
|
FirstShredReceived,
|
||||||
|
/// Slot ingestion has completed.
|
||||||
|
Completed,
|
||||||
|
/// A bank has been created for the slot.
|
||||||
|
CreatedBank,
|
||||||
|
/// The slot has been marked dead.
|
||||||
|
Dead,
|
||||||
|
/// The slot has reached optimistic confirmation.
|
||||||
|
OptimisticallyConfirmed,
|
||||||
|
/// The slot has become rooted.
|
||||||
|
Rooted,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Passive provider-neutral occurrence of one slot lifecycle stage.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct SlotLifecycleEvent {
|
||||||
|
slot: u64,
|
||||||
|
stage: SlotLifecycleStage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlotLifecycleEvent {
|
||||||
|
/// Creates a lifecycle event for `slot` and `stage`.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(slot: u64, stage: SlotLifecycleStage) -> Self {
|
||||||
|
return Self { slot, stage };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the observed slot exactly as supplied.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn slot(&self) -> u64 {
|
||||||
|
return self.slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the provider-neutral lifecycle stage.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn stage(&self) -> SlotLifecycleStage {
|
||||||
|
return self.stage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "../unit_tests/slot_lifecycle.rs"]
|
||||||
|
mod tests;
|
||||||
@@ -1,75 +1,56 @@
|
|||||||
// file: crates/ksp-interface-lib/tests/release_completeness.rs
|
// file: crates/ksp-interface-lib/tests/release_completeness.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Release-level completeness canaries for the `0.2.13` Interface foundation.
|
fn crate_root_source() -> std::result::Result<std::string::String, std::io::Error> {
|
||||||
|
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/lib.rs");
|
||||||
#[test]
|
return std::fs::read_to_string(path);
|
||||||
fn pre_005_exact_crate_root_export_inventory_is_stable() {
|
|
||||||
let crate_root = include_str!("../src/lib.rs");
|
|
||||||
let mut actual = std::vec::Vec::new();
|
|
||||||
for line in crate_root.lines() {
|
|
||||||
let trimmed = line.trim();
|
|
||||||
if trimmed.starts_with("pub use ") {
|
|
||||||
actual.push(trimmed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actual.sort_unstable();
|
|
||||||
let mut expected = std::vec![
|
|
||||||
"pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;",
|
|
||||||
"pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;",
|
|
||||||
"pub use self::program_account_meta::ProgramAccountMeta;",
|
|
||||||
"pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;",
|
|
||||||
"pub use self::program_instruction::ProgramInstruction;",
|
|
||||||
"pub use ksp_core_lib::Pubkey;",
|
|
||||||
];
|
|
||||||
expected.sort_unstable();
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
assert!(!crate_root.contains("pub mod "));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_005_production_module_inventory_contains_no_second_wire_domain() -> std::io::Result<()> {
|
fn v0_3_5_pre_002_foundation_keeps_one_error_code_and_adds_one_passive_acquisition_family() {
|
||||||
let source_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
|
|
||||||
let entries = match std::fs::read_dir(source_root) {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
|
||||||
let mut names = std::vec::Vec::new();
|
|
||||||
for entry in entries {
|
|
||||||
let entry = match entry {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
|
||||||
let file_type = match entry.file_type() {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
||||||
};
|
|
||||||
if !file_type.is_file() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let name = match entry.file_name().into_string() {
|
|
||||||
std::result::Result::Ok(value) => value,
|
|
||||||
std::result::Result::Err(_) => continue,
|
|
||||||
};
|
|
||||||
if name.ends_with(".rs") {
|
|
||||||
names.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
names.sort_unstable();
|
|
||||||
assert_eq!(names, std::vec!["error.rs", "lib.rs", "program_account_meta.rs", "program_instruction.rs"]);
|
|
||||||
return std::result::Result::Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn pre_005_foundation_has_one_error_code_and_two_bounded_passive_types() {
|
|
||||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
||||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(), "program_instruction_limit_exceeded");
|
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(), "program_instruction_limit_exceeded");
|
||||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||||
|
|
||||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xB1_u8; 32]);
|
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xB1_u8; 32]);
|
||||||
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xB2_u8; 32]), false);
|
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xB2_u8; 32]), false);
|
||||||
let instruction = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xB3_u8]);
|
let instruction_result = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xB3_u8]);
|
||||||
assert!(instruction.is_ok());
|
assert!(instruction_result.is_ok());
|
||||||
return;
|
|
||||||
|
let lifecycle = ksp_interface_lib::SlotLifecycleEvent::new(u64::MAX, ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||||
|
assert_eq!(lifecycle.slot(), u64::MAX);
|
||||||
|
assert_eq!(lifecycle.stage(), ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn v0_3_5_pre_002_exact_crate_root_export_inventory_includes_slot_lifecycle() -> std::result::Result<(), std::io::Error> {
|
||||||
|
let source = crate_root_source()?;
|
||||||
|
let public_use_count = source.lines().filter(|line| line.starts_with("pub use ")).count();
|
||||||
|
|
||||||
|
assert_eq!(public_use_count, 8);
|
||||||
|
assert!(source.contains("pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;"));
|
||||||
|
assert!(source.contains("pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;"));
|
||||||
|
assert!(source.contains("pub use self::program_account_meta::ProgramAccountMeta;"));
|
||||||
|
assert!(source.contains("pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;"));
|
||||||
|
assert!(source.contains("pub use self::program_instruction::ProgramInstruction;"));
|
||||||
|
assert!(source.contains("pub use self::slot_lifecycle::SlotLifecycleEvent;"));
|
||||||
|
assert!(source.contains("pub use self::slot_lifecycle::SlotLifecycleStage;"));
|
||||||
|
assert!(source.contains("pub use ksp_core_lib::Pubkey;"));
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn v0_3_5_pre_002_production_module_inventory_adds_only_slot_lifecycle() -> std::result::Result<(), std::io::Error> {
|
||||||
|
let source = crate_root_source()?;
|
||||||
|
let modules = source.lines().filter_map(|line| line.strip_prefix("mod ").and_then(|module| module.strip_suffix(';'))).collect::<std::vec::Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(modules, std::vec!["error", "program_account_meta", "program_instruction", "slot_lifecycle"]);
|
||||||
|
assert!(!source.contains("serde"));
|
||||||
|
assert!(!source.contains("tracing"));
|
||||||
|
assert!(!source.contains("ksp_onchain_transport"));
|
||||||
|
assert!(!source.contains("ksp_store"));
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
29
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
Normal file
29
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// file: crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn public_v0_3_5_pre_002_slot_lifecycle_contract_is_available_from_crate_root() {
|
||||||
|
let event = ksp_interface_lib::SlotLifecycleEvent::new(u64::MAX, ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||||
|
|
||||||
|
assert_eq!(event.slot(), u64::MAX);
|
||||||
|
assert_eq!(event.stage(), ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn public_v0_3_5_pre_002_slot_lifecycle_stage_remains_downstream_evolvable() {
|
||||||
|
fn stage_label(stage: ksp_interface_lib::SlotLifecycleStage) -> &'static str {
|
||||||
|
return match stage {
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::Processed => "processed",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::FirstShredReceived => "first_shred_received",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::Completed => "completed",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::CreatedBank => "created_bank",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::Dead => "dead",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::OptimisticallyConfirmed => "optimistically_confirmed",
|
||||||
|
ksp_interface_lib::SlotLifecycleStage::Rooted => "rooted",
|
||||||
|
_ => "future",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(stage_label(ksp_interface_lib::SlotLifecycleStage::Processed), "processed");
|
||||||
|
assert_eq!(stage_label(ksp_interface_lib::SlotLifecycleStage::Rooted), "rooted");
|
||||||
|
}
|
||||||
52
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
Normal file
52
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// file: crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slot_lifecycle_stages_are_distinct_copy_and_complete_for_the_admitted_family() {
|
||||||
|
fn assert_copy<T: Copy>() {}
|
||||||
|
|
||||||
|
assert_copy::<crate::SlotLifecycleStage>();
|
||||||
|
|
||||||
|
let stages = [
|
||||||
|
crate::SlotLifecycleStage::Processed,
|
||||||
|
crate::SlotLifecycleStage::FirstShredReceived,
|
||||||
|
crate::SlotLifecycleStage::Completed,
|
||||||
|
crate::SlotLifecycleStage::CreatedBank,
|
||||||
|
crate::SlotLifecycleStage::Dead,
|
||||||
|
crate::SlotLifecycleStage::OptimisticallyConfirmed,
|
||||||
|
crate::SlotLifecycleStage::Rooted,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (index, stage) in stages.iter().enumerate() {
|
||||||
|
for other in stages.iter().skip(index + 1) {
|
||||||
|
assert_ne!(stage, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slot_lifecycle_event_preserves_full_u64_slot_and_stage() {
|
||||||
|
fn assert_copy<T: Copy>() {}
|
||||||
|
|
||||||
|
assert_copy::<crate::SlotLifecycleEvent>();
|
||||||
|
|
||||||
|
let event = crate::SlotLifecycleEvent::new(u64::MAX, crate::SlotLifecycleStage::Rooted);
|
||||||
|
|
||||||
|
assert_eq!(event.slot(), u64::MAX);
|
||||||
|
assert_eq!(event.stage(), crate::SlotLifecycleStage::Rooted);
|
||||||
|
let copied = event;
|
||||||
|
assert_eq!(event, copied);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slot_lifecycle_debug_is_bounded_and_contains_only_shared_fields() {
|
||||||
|
let event = crate::SlotLifecycleEvent::new(42, crate::SlotLifecycleStage::OptimisticallyConfirmed);
|
||||||
|
let debug = std::format!("{event:?}");
|
||||||
|
|
||||||
|
assert!(debug.len() <= 128);
|
||||||
|
assert!(debug.contains("slot: 42"));
|
||||||
|
assert!(debug.contains("OptimisticallyConfirmed"));
|
||||||
|
assert!(!debug.contains("provider"));
|
||||||
|
assert!(!debug.contains("yellowstone"));
|
||||||
|
assert!(!debug.contains("websocket"));
|
||||||
|
}
|
||||||
180
deltas/0.3.5/pre.002.md
Normal file
180
deltas/0.3.5/pre.002.md
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<!-- file: deltas/0.3.5/pre.002.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.3.5-pre.002` — `SlotLifecycleEvent`
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.3.5-pre.001-fix.001
|
||||||
|
workspace.package.version = 0.3.5-pre.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Gate d'entrée opérateur reçu après le fix :
|
||||||
|
|
||||||
|
```text
|
||||||
|
General Rust rule audit: clean
|
||||||
|
Rust export completeness audit: 0 candidate(s)
|
||||||
|
KSP workspace Rust rule audit: clean
|
||||||
|
Markdown table audit: clean (240 table(s), 138 file(s))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Matérialiser uniquement la famille passive provider-neutral `SlotLifecycleEvent` admise par le gate corrigé de `pre.001`, sans ouvrir la famille candidate `TransactionExecutionEvent` et sans déplacer les DTOs protocol/provider hors de Transport.
|
||||||
|
|
||||||
|
## Version
|
||||||
|
|
||||||
|
Cette tranche est une nouvelle prerelease non-fix. La version workspace devient :
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.3.5-pre.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Le manifest `crates/ksp-interface-lib/Cargo.toml` reste inchangé et continue d'hériter de la version workspace.
|
||||||
|
|
||||||
|
## Implémentation
|
||||||
|
|
||||||
|
Nouvelle surface crate-root :
|
||||||
|
|
||||||
|
```text
|
||||||
|
SlotLifecycleStage
|
||||||
|
SlotLifecycleEvent
|
||||||
|
```
|
||||||
|
|
||||||
|
`SlotLifecycleStage` est `#[non_exhaustive]` et contient exactement :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Processed
|
||||||
|
FirstShredReceived
|
||||||
|
Completed
|
||||||
|
CreatedBank
|
||||||
|
Dead
|
||||||
|
OptimisticallyConfirmed
|
||||||
|
Rooted
|
||||||
|
```
|
||||||
|
|
||||||
|
`SlotLifecycleEvent` reste volontairement minimal :
|
||||||
|
|
||||||
|
```text
|
||||||
|
slot: u64
|
||||||
|
stage: SlotLifecycleStage
|
||||||
|
```
|
||||||
|
|
||||||
|
avec uniquement :
|
||||||
|
|
||||||
|
```text
|
||||||
|
SlotLifecycleEvent::new(slot, stage)
|
||||||
|
SlotLifecycleEvent::slot()
|
||||||
|
SlotLifecycleEvent::stage()
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucune validation faillible n'est ajoutée : tout `u64` est un slot admissible au niveau de ce contrat passif.
|
||||||
|
|
||||||
|
## Ownership et dépendances
|
||||||
|
|
||||||
|
Préservé :
|
||||||
|
|
||||||
|
```text
|
||||||
|
ksp-interface-lib -> ksp-core-lib
|
||||||
|
```
|
||||||
|
|
||||||
|
Absent :
|
||||||
|
|
||||||
|
```text
|
||||||
|
serde
|
||||||
|
codec wire
|
||||||
|
tracing/logging runtime
|
||||||
|
tokio/channel/event bus
|
||||||
|
ksp-onchain-transport-lib
|
||||||
|
ksp-store-api
|
||||||
|
ksp-store-lib
|
||||||
|
ksp-store-postgres-lib
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun converter depuis les DTOs Solana WS, Yellowstone ou Helius n'est ajouté dans Interface. Les conversions appartiennent à la future composition/consumer.
|
||||||
|
|
||||||
|
## Canaris
|
||||||
|
|
||||||
|
Ajoutés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||||
|
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Le premier verrouille les 7 stages, le domaine `u64`, les traits passifs retenus et un `Debug` borné/provider-neutral. Le second vérifie la consommation depuis crate root et la capacité d'évolution downstream de l'enum non-exhaustive.
|
||||||
|
|
||||||
|
Le canari historique `tests/release_completeness.rs` est ajusté afin que son inventaire exact accepte la seule extension prévue de cette tranche : `slot_lifecycle` et ses deux reexports publics.
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-interface-lib/src/lib.rs
|
||||||
|
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||||
|
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers ajoutés
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||||
|
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||||
|
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||||
|
deltas/0.3.5/pre.002.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers explicitement hors scope
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-interface-lib/Cargo.toml
|
||||||
|
crates/ksp-onchain-transport-lib/**
|
||||||
|
crates/ksp-store-api/**
|
||||||
|
crates/ksp-store-lib/**
|
||||||
|
crates/ksp-store-postgres-lib/**
|
||||||
|
README.md
|
||||||
|
ROADMAP.md
|
||||||
|
CHANGELOG.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validations exécutées dans l'environnement d'assemblage
|
||||||
|
|
||||||
|
Validations statiques de l'overlay :
|
||||||
|
|
||||||
|
```text
|
||||||
|
version workspace = 0.3.5-pre.2
|
||||||
|
nouvelle source Interface sans serde/tracing/tokio/Transport/Store
|
||||||
|
crate-root = 4 modules privés / 8 reexports publics attendus
|
||||||
|
SlotLifecycleStage = 7 variantes prévues
|
||||||
|
aucun TransactionExecutionEvent introduit
|
||||||
|
archive = fichiers modifiés/ajoutés uniquement
|
||||||
|
```
|
||||||
|
|
||||||
|
L'environnement d'assemblage ne fournit pas le workspace Cargo complet exécutable ; aucun `cargo check`, Clippy ou test Rust de cette tranche n'est donc déclaré réussi ici.
|
||||||
|
|
||||||
|
## Gate opérateur demandé
|
||||||
|
|
||||||
|
```text
|
||||||
|
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/0.3.5
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
cargo test -p ksp-interface-lib
|
||||||
|
cargo test -p ksp-program-api
|
||||||
|
```
|
||||||
|
|
||||||
|
`ksp-program-api` est inclus car il est le consumer actuel direct de `ksp-interface-lib`, même si `pre.002` ne modifie aucun contrat Program existant.
|
||||||
|
|
||||||
|
## Questions ouvertes
|
||||||
|
|
||||||
|
Aucune question ne bloque `SlotLifecycleEvent`.
|
||||||
|
|
||||||
|
Le seul gate fonctionnel suivant reste `TransactionExecutionEvent` : représentation de signature, convergence exacte Solana/Yellowstone/Helius, anti-duplication Store et consumer concret doivent être prouvés en `pre.003` avant toute implémentation.
|
||||||
|
|
||||||
|
## Suite
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.3.5-pre.003 — gate TransactionExecutionEvent ; implémentation uniquement si le gate est complet
|
||||||
|
```
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<!-- file: docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md -->
|
<!-- file: docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md -->
|
||||||
<!-- version: 2 -->
|
<!-- version: 3 -->
|
||||||
|
|
||||||
# Validation `0.3.5` — Interface passive acquisition events
|
# Validation `0.3.5` — Interface passive acquisition events
|
||||||
|
|
||||||
## 1. Portée
|
## 1. Portée
|
||||||
|
|
||||||
Ce document est ouvert par `0.3.5-pre.001` et corrigé par `0.3.5-pre.001-fix.001`. Le fix enregistre les corrections sémantiques du gate ainsi que le gate Cargo réellement rejoué par l'opérateur sur `0.3.5-pre.1`.
|
Ce document est ouvert par `0.3.5-pre.001`, corrigé par `0.3.5-pre.001-fix.001` puis enrichi par `0.3.5-pre.002`. `pre.002` matérialise uniquement la famille `SlotLifecycleEvent` admise par le gate corrigé, sans avancer `TransactionExecutionEvent`.
|
||||||
|
|
||||||
Base :
|
Base :
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ workspace.package.version = 0.3.4
|
|||||||
Version de travail :
|
Version de travail :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
0.3.5-pre.1
|
0.3.5-pre.2
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. Gate d'entrée `v0.3.4`
|
## 2. Gate d'entrée `v0.3.4`
|
||||||
@@ -161,22 +161,22 @@ Yellowstone gRPC -------------+
|
|||||||
|
|
||||||
## 10. Threat gates
|
## 10. Threat gates
|
||||||
|
|
||||||
| Gate | Attendu `0.3.5` | Statut `pre.001` |
|
| Gate | Attendu `0.3.5` | Statut courant |
|
||||||
| ------------------------------------ | ------------------------------------------------- | ---------------- |
|
| ------------------------------------ | ------------------------------------------------- | ------------------ |
|
||||||
| mega enum | absent | PLAN PASS |
|
| mega enum | absent | PLAN PASS |
|
||||||
| protocol/provider enum leakage | absent | PLAN PASS |
|
| protocol/provider enum leakage | absent | PLAN PASS |
|
||||||
| timestamp semantics conflated | absent | PLAN PASS |
|
| timestamp semantics conflated | absent | PLAN PASS |
|
||||||
| root/finalized label confusion | évitée par le stage KSP `Rooted` | PLAN PASS |
|
| root/finalized label confusion | évitée par le stage KSP `Rooted` | PLAN PASS |
|
||||||
| optimistic/confirmed label confusion | évitée par le stage KSP `OptimisticallyConfirmed` | PLAN PASS |
|
| optimistic/confirmed label confusion | évitée par le stage KSP `OptimisticallyConfirmed` | PLAN PASS |
|
||||||
| dead diagnostic in shared API | absent | PLAN PASS |
|
| dead diagnostic in shared API | absent | PLAN PASS |
|
||||||
| RAW Store duplication | absent | PLAN PASS |
|
| RAW Store duplication | absent | PLAN PASS |
|
||||||
| event persistence | absent | PLAN PASS |
|
| event persistence | absent | PLAN PASS |
|
||||||
| event bus/runtime | absent | PLAN PASS |
|
| event bus/runtime | absent | PLAN PASS |
|
||||||
| network id duplicated from Store | absent | PLAN PASS |
|
| network id duplicated from Store | absent | PLAN PASS |
|
||||||
| cross-network use | composition doit conserver son scope réseau | À CANARIER |
|
| cross-network use | composition doit conserver son scope réseau | À CANARIER |
|
||||||
| public enum evolution | `SlotLifecycleStage` doit être non-exhaustive | À IMPLÉMENTER |
|
| public enum evolution | `SlotLifecycleStage` doit être non-exhaustive | IMPLÉMENTÉ pre.002 |
|
||||||
| Core-only graph | aucune dependency nouvelle | PASS opérateur |
|
| Core-only graph | aucune dependency nouvelle | PASS opérateur |
|
||||||
| external consumer | type consommable depuis crate externe | À IMPLÉMENTER |
|
| external consumer | type consommable depuis crate externe | CANARI pre.002 |
|
||||||
|
|
||||||
## 11. Fichiers de `pre.001`
|
## 11. Fichiers de `pre.001`
|
||||||
|
|
||||||
@@ -260,3 +260,129 @@ Helius transactionSubscribe et Yellowstone Entry restent des DTOs Transport
|
|||||||
un futur fait provider-neutral produit par une extension provider peut appartenir à Interface après gate
|
un futur fait provider-neutral produit par une extension provider peut appartenir à Interface après gate
|
||||||
aucun fichier Rust/Transport/Store/Cargo n'est modifié par le fix
|
aucun fichier Rust/Transport/Store/Cargo n'est modifié par le fix
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 15. Gate opérateur post-`pre.001-fix.001`
|
||||||
|
|
||||||
|
Avant l'ouverture de `pre.002`, l'opérateur a rejoué les audits demandés sur l'état corrigé :
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.5
|
||||||
|
```
|
||||||
|
|
||||||
|
Résultat fourni : **PASS**.
|
||||||
|
|
||||||
|
```text
|
||||||
|
General Rust rule audit: clean
|
||||||
|
Rust export completeness audit: 0 candidate(s)
|
||||||
|
KSP workspace Rust rule audit: clean
|
||||||
|
Markdown table audit: clean (240 table(s), 138 file(s))
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce résultat constitue le gate d'entrée immédiat de `0.3.5-pre.002`.
|
||||||
|
|
||||||
|
## 16. Implémentation `0.3.5-pre.002`
|
||||||
|
|
||||||
|
`pre.002` ajoute exactement une famille passive provider-neutral à `ksp-interface-lib` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
SlotLifecycleStage
|
||||||
|
Processed
|
||||||
|
FirstShredReceived
|
||||||
|
Completed
|
||||||
|
CreatedBank
|
||||||
|
Dead
|
||||||
|
OptimisticallyConfirmed
|
||||||
|
Rooted
|
||||||
|
|
||||||
|
SlotLifecycleEvent
|
||||||
|
new(slot, stage)
|
||||||
|
slot()
|
||||||
|
stage()
|
||||||
|
```
|
||||||
|
|
||||||
|
Propriétés de représentation matérialisées :
|
||||||
|
|
||||||
|
```text
|
||||||
|
SlotLifecycleStage -> #[non_exhaustive] + Clone + Copy + Debug + Eq + PartialEq
|
||||||
|
SlotLifecycleEvent -> champs privés + Clone + Copy + Debug + Eq + PartialEq
|
||||||
|
slot -> u64 conservé exactement, y compris u64::MAX
|
||||||
|
validation -> aucune admission faillible
|
||||||
|
error code -> aucun nouvel error code
|
||||||
|
serde/codec -> absent
|
||||||
|
runtime/logging -> absent
|
||||||
|
Transport/Store -> aucune dépendance ni conversion
|
||||||
|
```
|
||||||
|
|
||||||
|
Le graphe Cargo reste inchangé pour `ksp-interface-lib` : son manifest n'est pas modifié et sa seule dépendance normale demeure `ksp-core-lib`.
|
||||||
|
|
||||||
|
Canaris ajoutés/ajustés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
unit_tests/slot_lifecycle.rs
|
||||||
|
-> 7 stages distincts
|
||||||
|
-> traits Copy/Eq attendus
|
||||||
|
-> domaine u64 complet
|
||||||
|
-> Debug borné et provider-neutral
|
||||||
|
|
||||||
|
tests/slot_lifecycle_public_api.rs
|
||||||
|
-> construction et getters depuis crate root
|
||||||
|
-> match downstream avec wildcard imposé par #[non_exhaustive]
|
||||||
|
|
||||||
|
tests/release_completeness.rs
|
||||||
|
-> inventaire crate-root mis à jour à 8 reexports
|
||||||
|
-> inventaire de modules mis à jour avec slot_lifecycle uniquement
|
||||||
|
-> absence de serde/tracing/Transport/Store dans la racine Interface
|
||||||
|
```
|
||||||
|
|
||||||
|
`TransactionExecutionEvent` reste **non implémenté** et réservé au gate `pre.003`.
|
||||||
|
|
||||||
|
## 17. Fichiers de `pre.002`
|
||||||
|
|
||||||
|
Modifiés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-interface-lib/src/lib.rs
|
||||||
|
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||||
|
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajoutés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||||
|
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||||
|
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||||
|
deltas/0.3.5/pre.002.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Explicitement inchangés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-interface-lib/Cargo.toml
|
||||||
|
crates/ksp-onchain-transport-lib/**
|
||||||
|
crates/ksp-store-api/**
|
||||||
|
crates/ksp-store-lib/**
|
||||||
|
crates/ksp-store-postgres-lib/**
|
||||||
|
README.md
|
||||||
|
ROADMAP.md
|
||||||
|
CHANGELOG.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 18. Gate opérateur demandé pour `pre.002`
|
||||||
|
|
||||||
|
Après application de l'overlay :
|
||||||
|
|
||||||
|
```text
|
||||||
|
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/0.3.5
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
cargo test -p ksp-interface-lib
|
||||||
|
cargo test -p ksp-program-api
|
||||||
|
```
|
||||||
|
|
||||||
|
Les validations Cargo de `pre.002` restent **à exécuter par l'opérateur** ; elles ne sont pas déclarées réussies par l'environnement d'assemblage.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user