v0.3.10-pre.008

This commit is contained in:
2026-09-08 06:43:02 +02:00
parent ab87fd23cd
commit 510adcb49b
21 changed files with 790 additions and 195 deletions

View File

@@ -0,0 +1,97 @@
<!-- file: crates/ksp-raw-transaction-lib/README.md -->
<!-- version: 1 -->
# ksp-raw-transaction-lib
`ksp-raw-transaction-lib` fournit la lower-layer KSP source-neutral commune aux producteurs de `RawTransaction`.
La crate transforme un matériau transactionnel complet déjà acquis en représentation RAW canonique KSP, fournit les primitives de parsing de signature et de sérialisation wire Solana nécessaires aux voies qualifiées, puis permet d'associer la transaction canonique à une observation/provenance possédée par le producer.
Elle ne possède aucun Transport, Config, Job, Worker, runtime async, Store runtime ou backend physique.
## Responsabilités
La façade crate-root expose quatre familles de contrats.
### Canonicalisation RAW Transaction
- `RawTransactionMaterial` ;
- `RawTransactionWireField<T>` pour préserver distinctement omission, `null` explicite et valeur ;
- `RawTransactionVersion` ;
- `canonicalize_raw_transaction` ;
- `RAW_TRANSACTION_FORMAT_ID` et `RAW_TRANSACTION_FORMAT_VERSION`.
La canonicalisation produit un `ksp_store_api::RawTransaction` avec payload KSP déterministe et SHA-256 de contenu. Le producer reste responsable de fournir un matériau source-neutral complet ; la crate n'effectue aucune I/O réseau.
### Signature Solana
- `parse_raw_transaction_signature` valide et décode une signature Base58 bornée vers exactement 64 bytes ;
- `extract_raw_transaction_signature_from_binary_base64` extrait la première signature canonique d'un wire transactionnel Base64 complet ;
- les bornes textuelles publiques permettent l'admission avant décodage.
Les diagnostics ne recopient pas la signature hostile.
### Wire transactionnel source-neutral
La surface `RawSolana*` représente et sérialise les messages transactionnels Solana Legacy, V0 et V1 nécessaires à la common RAW :
- `RawSolanaMessageVersion` ;
- `RawSolanaMessageHeader` ;
- `RawSolanaCompiledInstruction` ;
- `RawSolanaAddressTableLookup` ;
- `RawSolanaTransactionConfig` ;
- `RawSolanaTransactionMessage` ;
- `RawSolanaTransactionWire` ;
- `serialize_solana_transaction_wire` et `serialize_solana_transaction_wire_base64`.
Cette surface est un contrat de wire commun, pas un decoder Program et pas une façade Transport.
### Acquisition canonique + observation
`assemble_raw_transaction_acquisition` associe une transaction canonique à :
- une `RawObservationKey` déterministe possédée par le producer ;
- une `RawAcquisitionProvenance` sûre possédée par le producer.
Le résultat `RawTransactionAcquisition` contient exactement une entité canonique et une observation liée. Il ne persiste rien lui-même.
## Frontières
```text
Transport / fixture / import / producer
|
v
matériau source-neutral
|
v
ksp-raw-transaction-lib
| |
| +-> exact Solana wire helpers
v
RawTransaction + RawTransactionObservation
|
v
producer runtime -> ksp-store-lib / capability Store appropriée
```
Interdictions structurelles :
```text
ksp-raw-transaction-lib -X-> ksp-onchain-transport-lib
ksp-raw-transaction-lib -X-> ksp-config-lib
ksp-raw-transaction-lib -X-> ksp-job-api / ksp-job-backfill-lib
ksp-raw-transaction-lib -X-> ksp-worker-api / worker concret
ksp-raw-transaction-lib -X-> ksp-store-lib / backend physique
```
Le graphe normal reste limité à `ksp-core-lib`, `ksp-store-api`, `base64`, `serde_json` et `sha2`.
## Relation avec STRUCTURAL
Cette crate appartient à **RAW**. Elle ne réalise pas la décomposition Store D2 `RAW -> STRUCTURAL`. La future couche STRUCTURAL consommera le RAW persistant et le décomposera en unités Solana génériques plus fines avant tout décodage Program.
## Documentation
- [`USAGE.md`](USAGE.md) — utilisation durable de la façade publique ;
- [`../../docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md`](../../docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md) — frontières RAW / STRUCTURAL / DECODED / DOMAIN ;
- [`../../docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md`](../../docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md) — qualification des sources `RawTransaction`.

View File

@@ -0,0 +1,153 @@
<!-- file: crates/ksp-raw-transaction-lib/USAGE.md -->
<!-- version: 1 -->
# Utilisation de ksp-raw-transaction-lib
Cette page décrit la façade publique durable de `ksp-raw-transaction-lib`. Les consumers utilisent uniquement les exports du crate-root.
## Parser une signature transactionnelle
Lorsqu'une source fournit une signature Base58 textuelle, la convertir avec le parser commun plutôt que de dupliquer le décodage :
```rust
fn parse_signature(value: &str) -> ksp_core_lib::Result<ksp_store_api::RawTransactionSignature> {
return ksp_raw_transaction_lib::parse_raw_transaction_signature(value);
}
```
Le résultat contient exactement 64 bytes canoniques. Les entrées vides, hors bornes, Base58 invalides ou de longueur décodée incorrecte sont rejetées sans recopier la valeur hostile dans l'erreur.
Lorsqu'un wire Base64 complet contient déjà son tableau de signatures, utiliser :
```rust
fn embedded_signature(value: &str) -> ksp_core_lib::Result<ksp_store_api::RawTransactionSignature> {
return ksp_raw_transaction_lib::extract_raw_transaction_signature_from_binary_base64(value);
}
```
## Construire et sérialiser un wire Solana source-neutral
Le producer peut projeter son DTO Transport/protobuf vers les types `RawSolana*`, puis utiliser le sérialiseur commun. Exemple V1 minimal :
```rust
fn serialize_v1() -> ksp_core_lib::Result<std::string::String> {
let message = ksp_raw_transaction_lib::RawSolanaTransactionMessage::new(
ksp_raw_transaction_lib::RawSolanaMessageVersion::V1,
ksp_raw_transaction_lib::RawSolanaMessageHeader::new(1, 0, 0),
vec![[1_u8; 32]],
[2_u8; 32],
vec![ksp_raw_transaction_lib::RawSolanaCompiledInstruction::new(0, vec![0], vec![3])],
vec![],
std::option::Option::Some(ksp_raw_transaction_lib::RawSolanaTransactionConfig::default()),
);
let wire = ksp_raw_transaction_lib::RawSolanaTransactionWire::new(vec![[4_u8; 64]], message);
return ksp_raw_transaction_lib::serialize_solana_transaction_wire_base64(&wire);
}
```
Pour Legacy ou V0, choisir `RawSolanaMessageVersion::Legacy` ou `V0` et fournir uniquement les éléments admis par cette version. Le sérialiseur valide les invariants structurels avant de produire les bytes.
`RawSolanaAddressTableLookup` représente les lookups V0. `RawSolanaTransactionConfig` représente la configuration inline V1 ; le cas explicite où toutes ses options valent `None` reste sémantiquement présent.
## Construire le matériau RAW canonique
Une fois le wire transactionnel Base64 et les métadonnées source-neutral disponibles, construire `RawTransactionMaterial`. Les états wire doivent conserver la différence entre champ absent, `null` explicite et valeur :
```rust
fn material(
network: ksp_store_api::RawNetworkId,
signature: ksp_store_api::RawTransactionSignature,
transaction_base64: std::string::String,
) -> ksp_raw_transaction_lib::RawTransactionMaterial {
return ksp_raw_transaction_lib::RawTransactionMaterial::binary_base64(
network,
signature,
42,
std::option::Option::None,
transaction_base64,
ksp_raw_transaction_lib::RawTransactionWireField::Omitted,
ksp_raw_transaction_lib::RawTransactionWireField::Value(ksp_raw_transaction_lib::RawTransactionVersion::Legacy),
ksp_raw_transaction_lib::RawTransactionWireField::Omitted,
);
}
```
Pour une source où la signature doit être extraite du wire lui-même, `RawTransactionMaterial::binary_base64_with_embedded_signature` évite un second parser producer-owned.
## Canonicaliser vers RawTransaction
La canonicalisation est déterministe pour un même matériau complet :
```rust
fn canonicalize(
material: ksp_raw_transaction_lib::RawTransactionMaterial,
) -> ksp_core_lib::Result<ksp_store_api::RawTransaction> {
return ksp_raw_transaction_lib::canonicalize_raw_transaction(material);
}
```
La crate :
- canonicalise les sous-arbres JSON significatifs ;
- conserve les états omission / `null` / valeur ;
- construit le payload au format KSP RAW Transaction ;
- calcule son SHA-256 ;
- applique les bornes communes avant construction du modèle Store.
Elle ne persiste pas la transaction et ne choisit aucune politique de retry, endpoint ou source.
## Associer l'observation du producer
Le producer construit sa provenance avec les types Store API, puis assemble l'entité et l'observation :
```rust
fn acquisition(
transaction: ksp_store_api::RawTransaction,
) -> ksp_core_lib::Result<ksp_raw_transaction_lib::RawTransactionAcquisition> {
let provider = match ksp_store_api::RawProvenanceCode::new("example") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let protocol = match ksp_store_api::RawProvenanceCode::new("solana.http") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let method = match ksp_store_api::RawProvenanceCode::new("get_transaction") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let received_at = match ksp_store_api::RawTimestamp::from_unix_millis(1_700_000_000_000) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let provenance = ksp_store_api::RawAcquisitionProvenance::new(
provider,
protocol,
method,
ksp_store_api::RawAcquisitionOrigin::Live,
received_at,
);
return std::result::Result::Ok(ksp_raw_transaction_lib::assemble_raw_transaction_acquisition(
transaction,
ksp_store_api::RawObservationKey::new([7_u8; 32]),
provenance,
));
}
```
La clé d'observation doit être déterministe selon la politique du producer. Plusieurs sources peuvent produire des observations différentes pour la même identité canonique `(network, signature)`.
## Persister depuis un Job ou un Worker
La common crate ne dépend pas du Store runtime. Le lifecycle host concret récupère les deux parties puis appelle la façade Store appropriée :
```rust
let (transaction, observation) = acquisition.into_parts();
// Le Job/Worker concret transmet ensuite transaction + observation à ksp-store-lib.
```
Ne pas introduire `ksp-store-lib`, Transport, Config, Job ou Worker dans `ksp-raw-transaction-lib` pour simplifier cet appel. La direction de dépendance reste du producer vers la common RAW, puis du producer vers le Store runtime.
## Frontière avec STRUCTURAL
Ne pas utiliser cette crate pour décoder des Programs ou pour produire directement des unités STRUCTURAL. Son résultat reste D1 RAW. La décomposition `RAW -> STRUCTURAL` appartient à une couche ultérieure et réutilise le RAW durable comme input.