323 lines
12 KiB
Markdown
323 lines
12 KiB
Markdown
<!-- file: deltas/0.3.13/pre.006.md -->
|
|
<!-- version: 1 -->
|
|
|
|
# Delta 0.3.13-pre.006 — HTTP live block polling run-local
|
|
|
|
## Base requise
|
|
|
|
```text
|
|
livraison précédente : 0.3.13-pre.005-fix.001
|
|
Cargo base : 0.3.13-pre.5.fix.1
|
|
delta base : deltas/0.3.13/pre.005-fix.001.md
|
|
archive delta base : ksp-general-0.3.13-pre.005-fix.001.zip
|
|
```
|
|
|
|
Le gate opérateur reçu le 10 septembre 2026 sur cette base est entièrement vert pour les commandes exécutées : `cargo fmt`, `cargo fmt --check`, audits Rust/Markdown, `cargo check --workspace`, Clippy strict et toutes les suites de `ksp-worker-raw-transaction-ingest-lib` (`84` unit, `4` cross-layer, `12` dependency-boundary, `19` hardening, `13` public-api, `4` release-completeness, `0` doc-test). Cette exécution ne contenait ni le test Transport ni les commandes `cargo tree`; ils ne sont donc pas déclarés PASS pour ce gate précis.
|
|
|
|
## Objectif
|
|
|
|
Ajouter la source HTTP live prévue par la tranche sans la transformer en Backfill :
|
|
|
|
```text
|
|
getSlot(commitment)
|
|
-> borne inférieure du run
|
|
getBlocksWithLimit(next_scan_slot, bounded_limit, commitment)
|
|
-> découverte des blocs disponibles
|
|
getBlock observed(slot, Full/Base64/maxV1/rewards=false)
|
|
-> Common RAW direct Legacy/V0/V1
|
|
-> admission centrale Worker
|
|
-> Store
|
|
```
|
|
|
|
Le polling ne remonte jamais avant la borne observée au démarrage et ne crée aucun checkpoint durable inter-run.
|
|
|
|
## Version
|
|
|
|
```text
|
|
livraison : 0.3.13-pre.006
|
|
workspace.package.version : 0.3.13-pre.6
|
|
archive : ksp-general-0.3.13-pre.006.zip
|
|
```
|
|
|
|
`Cargo.toml` passe également de la version de fichier `549` à `550`.
|
|
|
|
## Source HTTP Block Polling
|
|
|
|
Nouvelle surface publique Worker :
|
|
|
|
```text
|
|
RawTransactionIngestHttpBlockPollingSource
|
|
RawTransactionIngestRuntimeResources::from_http_block_polling_source
|
|
RawTransactionIngestRuntimeResources::try_push_http_block_polling_source
|
|
DEFAULT_RAW_TRANSACTION_INGEST_HTTP_POLL_INTERVAL
|
|
MIN_RAW_TRANSACTION_INGEST_HTTP_POLL_INTERVAL
|
|
MAX_RAW_TRANSACTION_INGEST_HTTP_POLL_INTERVAL
|
|
DEFAULT_RAW_TRANSACTION_INGEST_HTTP_POLL_MAX_BLOCKS_PER_CYCLE
|
|
MIN_RAW_TRANSACTION_INGEST_HTTP_POLL_MAX_BLOCKS_PER_CYCLE
|
|
MAX_RAW_TRANSACTION_INGEST_HTTP_POLL_MAX_BLOCKS_PER_CYCLE
|
|
```
|
|
|
|
La construction caller-owned reçoit un `HttpTransportPool`, un `HttpRoleName` et un commitment `Confirmed` ou `Finalized`. Elle est sans I/O et vérifie statiquement que le rôle possède des routes compatibles `getSlot`, `getBlocksWithLimit` et `getBlock` sur un même réseau.
|
|
|
|
Bornes publiques :
|
|
|
|
```text
|
|
poll interval : défaut 1 s ; min 100 ms ; max 30 s
|
|
max discovered blocks/cycle : défaut 128 ; min 1 ; max 1024
|
|
```
|
|
|
|
Les limitations physiques, la sélection d'endpoint, le rate-limit, les retries et le backoff HTTP restent possédés par `ksp-onchain-transport-lib`.
|
|
|
|
## Borne de run et progression
|
|
|
|
Au démarrage :
|
|
|
|
```text
|
|
start_slot = getSlot(commitment)
|
|
next_scan_slot = start_slot
|
|
```
|
|
|
|
Le Worker ne demande aucun slot inférieur à `start_slot`. Pour chaque cycle, il relit le tip courant, puis appelle `getBlocksWithLimit` depuis `next_scan_slot`. La réponse doit être strictement croissante et ne peut contenir aucun slot inférieur à la frontier de scan.
|
|
|
|
Chaque slot listé est matérialisé par `getBlock observed`. Si le résultat vaut `null` :
|
|
|
|
```text
|
|
next_scan_slot = slot
|
|
aucun settled
|
|
aucun Common RAW
|
|
reprise au cycle suivant
|
|
```
|
|
|
|
Le cas `null` n'est donc ni assimilé à un bloc vide ni converti en progression silencieuse.
|
|
|
|
Les slots non listés par `getBlocksWithLimit` sont traités comme non produits/skipped dans le run courant. Lorsque la liste reçue ne remplit pas le batch demandé et qu'aucun slot n'est bloqué par `null`, la frontier peut rejoindre le tip observé du cycle sans lancer de scan historique implicite.
|
|
|
|
## RAW-direct et version
|
|
|
|
Le poller demande exactement :
|
|
|
|
```text
|
|
encoding = Base64
|
|
transactionDetails = Full
|
|
maxSupportedTransactionVersion = 1
|
|
showRewards = false
|
|
commitment = Confirmed | Finalized
|
|
```
|
|
|
|
Chaque transaction qualifiée produit directement `RawTransactionMaterial` avec :
|
|
|
|
```text
|
|
signature embarquée dans le wire Base64
|
|
slot
|
|
blockTime
|
|
meta
|
|
version Legacy | 0 | 1
|
|
transactionIndex dérivé de la position dans le bloc
|
|
```
|
|
|
|
Les cas suivants sont fail-closed : transaction non Base64, transactions omises/nulles, version omise/nulle, version `>1`, signature invalide ou index non représentable en `u32`.
|
|
|
|
La voie HTTP Block Polling est RAW-direct et n'utilise pas le coordinateur d'hydration. Le slot n'est marqué `settled` qu'après l'envoi réussi de toutes les transactions du bloc vers l'admission centrale ; `hydration_pending` n'est jamais artificiellement incrémenté.
|
|
|
|
## Provenance observée
|
|
|
|
La provenance de chaque transaction reprend l'endpoint et le provider réellement gagnants de `getBlock observed` :
|
|
|
|
```text
|
|
origin = Live
|
|
protocol = solana_http
|
|
method = block_polling_get_block
|
|
endpoint = endpoint observé
|
|
provider = provider observé
|
|
commitment = source commitment
|
|
capture session = WorkerId
|
|
```
|
|
|
|
Aucun URL, header HTTP ou corps brut n'est exposé par `HttpObservedValue` ou les diagnostics Worker.
|
|
|
|
## Identité logique
|
|
|
|
Le `source_key` HTTP polling est dérivé de :
|
|
|
|
```text
|
|
domain KSP live-source v1
|
|
family = http_block_polling
|
|
network
|
|
polling role
|
|
commitment
|
|
private route-profile fingerprint
|
|
SHA-256 -> [u8; 32]
|
|
```
|
|
|
|
L'empreinte de profil est construite à partir des identités sûres cluster/provider/endpoint et des capacités pertinentes de chaque route active, après tri déterministe. La cadence et le batch de découverte n'entrent volontairement pas dans l'identité logique : modifier un réglage de timing ne crée pas une deuxième source conceptuelle.
|
|
|
|
Le bound global `1..32`, l'invariant réseau unique et le rejet transactionnel des doublons de `pre.002` s'appliquent à cette famille.
|
|
|
|
## Activation runtime
|
|
|
|
Le contrat reste volontairement mono-source avant `pre.007` :
|
|
|
|
```text
|
|
1 source Yellowstone : productif
|
|
1 source Standard Logs : productif
|
|
1 source Standard Block : productif
|
|
1 source Helius Transaction : productif
|
|
1 source HTTP Block Polling : productif
|
|
2..32 sources : composition validable
|
|
start 2..32 : runtime_resources.multi_source_activation_pending avant spawn
|
|
```
|
|
|
|
Aucune source configurée n'est ignorée silencieusement.
|
|
|
|
## Preuves ajoutées
|
|
|
|
Unit tests Worker :
|
|
|
|
```text
|
|
bornes cadence/batch et commitment
|
|
présence exacte des capacités HTTP requises
|
|
source_key stable malgré changement de timing et différent si route logique différente
|
|
redaction URL sensible dans Debug
|
|
validation stricte de la découverte croissante
|
|
qualification Legacy/V0/V1 et rejet version ambiguë/future
|
|
rejet transactionnel d'une identité HTTP polling dupliquée
|
|
```
|
|
|
|
Canaris externes :
|
|
|
|
```text
|
|
public_api : constructeurs/from/push et bornes publiques disponibles depuis crate root
|
|
dependency_boundary : Transport facade uniquement, aucun Config/Backfill/backend/direct HTTP client
|
|
hardening : run-local, timer borné, getBlock observed unique, aucun task par tick, aucun hydration_pending direct
|
|
release_completeness : exports et canaris pre.006 obligatoires
|
|
```
|
|
|
|
Les anciens canaris qui interdisaient globalement `get_block_observed` ou `tokio::time::sleep` sont resserrés sur le coordinateur d'hydration : ces primitives restent interdites dans l'hydration mais sont désormais légitimes, explicites et bornées dans la seule source HTTP polling.
|
|
|
|
## Documentation
|
|
|
|
`README.md`, le README du crate, `USAGE.md`, le plan et le journal de validation sont alignés sur la cinquième famille productive. `USAGE.md` reste version-neutral : il décrit la construction et le comportement sans journaliser le numéro de prerelease.
|
|
|
|
Une incohérence du README de crate, qui classait encore le live HTTP polling parmi les éléments hors périmètre, est corrigée dans cette tranche.
|
|
|
|
## Fichiers modifiés
|
|
|
|
```text
|
|
Cargo.toml
|
|
README.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/README.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
|
|
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.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
|
|
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs
|
|
docs/plans/034-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE_PLAN.md
|
|
docs/validation/030-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE.md
|
|
```
|
|
|
|
## Fichiers ajoutés
|
|
|
|
```text
|
|
deltas/0.3.13/pre.006.md
|
|
```
|
|
|
|
## Fichiers supprimés
|
|
|
|
```text
|
|
aucun
|
|
```
|
|
|
|
## Non-claims
|
|
|
|
`pre.006` ne prétend pas :
|
|
|
|
```text
|
|
supervision simultanée de plusieurs sources
|
|
checkpoint durable du polling
|
|
Backfill implicite
|
|
scan de slots antérieurs au start_slot du run
|
|
retry/backoff HTTP implémenté dans Worker
|
|
client reqwest direct dans Worker
|
|
Config lu dans Worker
|
|
getBlock=null assimilé à un bloc vide
|
|
transaction version >1 ou ambiguë acceptée
|
|
modification de ksp-onchain-transport-lib
|
|
nouvelle dépendance externe
|
|
```
|
|
|
|
## Validation dans l'environnement d'assemblage
|
|
|
|
Le toolchain Rust/Cargo/Rustfmt n'est pas disponible dans l'environnement d'assemblage. Les commandes Cargo post-`pre.006` restent donc `NON EXÉCUTÉ LOCAL`. Les audits statiques KSP, le scan normatif, le contrôle des versions de fichiers et le diff exhaustif sont exécutés avant packaging.
|
|
|
|
## Gate opérateur requis avant pre.007
|
|
|
|
```bash
|
|
cargo fmt --all
|
|
cargo fmt --all -- --check
|
|
python3 scripts/audit_rust_workspace_rules.py
|
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas
|
|
cargo check --workspace
|
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
cargo test -p ksp-onchain-transport-lib
|
|
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
|
|
```
|
|
|
|
`pre.007` ne doit pas commencer si ce gate révèle une anomalie.
|
|
|
|
## Résultats statiques finaux de l'assemblage
|
|
|
|
Les valeurs ci-dessous sont mises à jour après la dernière passe d'audits sur l'état exact livré.
|
|
|
|
```text
|
|
General Rust rule audit: clean
|
|
Rust export completeness audit: 0 candidate(s)
|
|
KSP workspace Rust rule audit: clean
|
|
Markdown table audit: clean (340 tables, 839 files)
|
|
Normative rule definitions: 489
|
|
Unique normative IDs: 489
|
|
Duplicates: 0
|
|
```
|
|
|
|
## Contrôle exhaustif avant packaging
|
|
|
|
Comparaison avec la base `0.3.13-pre.005-fix.001` :
|
|
|
|
```text
|
|
added : 1
|
|
deltas/0.3.13/pre.006.md
|
|
modified : 13
|
|
Cargo.toml
|
|
README.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/README.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md
|
|
crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
|
|
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.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
|
|
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs
|
|
docs/plans/034-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE_PLAN.md
|
|
docs/validation/030-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE.md
|
|
deleted : 0
|
|
```
|
|
|
|
Les `13/13` fichiers existants modifiés portent une version de fichier exactement `+1`. Le diff de `Cargo.toml` est limité au header `549 -> 550` et à `workspace.package.version = "0.3.13-pre.6"`; aucun membre workspace ni aucune dépendance n'est modifié.
|
|
|
|
La revue statique ciblée confirme dans le code Worker :
|
|
|
|
```text
|
|
get_block_observed( : 1 occurrence, source HTTP polling uniquement
|
|
get_blocks_with_limit( : 1 occurrence, source HTTP polling uniquement
|
|
tokio::time::sleep : 1 occurrence, cadence du poller uniquement
|
|
aucun reqwest/tokio-tungstenite/tonic/yellowstone-grpc-proto direct
|
|
aucun ksp-config-lib/ksp-job-backfill-lib/ksp-store-postgres-lib direct
|
|
aucun unbounded_channel
|
|
```
|