v0.3.10-pre.008
This commit is contained in:
97
crates/ksp-raw-transaction-lib/README.md
Normal file
97
crates/ksp-raw-transaction-lib/README.md
Normal 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`.
|
||||
153
crates/ksp-raw-transaction-lib/USAGE.md
Normal file
153
crates/ksp-raw-transaction-lib/USAGE.md
Normal 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.
|
||||
Reference in New Issue
Block a user