Pipeline de transactions
Le pipeline de transactions gère le cycle de vie complet, de la création à la finalisation.
Vue d'ensemble
Utilisateur/SDK
│ construction + signature (Ed25519)
▼
JSON-RPC (savitri_sendRawTransaction)
│ décodage hex → bytes_to_raw_tx
▼
Admission au Mempool
│ gardes sans état → gardes avec état
▼
Notation par lot SIMD
│ fee * 0.7 + class_priority * 0.3
▼
Proposeur de bloc (drain_for_block_production)
│ top-N par score, ordonnés par nonce par expéditeur
▼
Production de bloc
│ calcul tx_root, state_root
▼
Diffusion Gossipsub (/savitri/block/1)
│
▼
Vote BFT (quorum 2f+1)
│ Certificat d'acceptation de bloc
▼
Validation RocksDB
│ CF_BLOCKS, CF_TRANSACTIONS, CF_ACCOUNTS
▼
Finalisé
Format de transaction
Message de signature canonique
from (octets hex) || to (octets hex) || amount (u64 LE) || nonce (u64 LE) || fee (u128 LE)
Ce message est haché avec SHA-256, puis signé avec Ed25519.
Format filaire (raw_tx_hex)
from_hex_bytes || to_hex_bytes || amount_le_u64 || nonce_le_u64 || fee_le_u128 || pubkey (32B) || signature (64B) || data (optionnel)
Soumis sous forme de chaîne encodée en hexadécimal à savitri_sendRawTransaction.
Admission au Mempool
Gardes sans état (sans accès au stockage)
- Validation du format de signature (ed25519 de 64 octets)
- Validation du format de clé publique (ed25519 de 32 octets)
- Vérification de la signature par rapport au hachage du message
- Limites de taille de transaction
Gardes avec état (accès au stockage requis)
- Vérification du nonce :
tx.nonce >= account.nonce(tolérance d'écart jusqu'à 5000) - Vérification du solde :
account.balance >= tx.amount + tx.fee - Vérification des quotas : Limites par classe et par expéditeur
Classes de transactions
| Classe | Priorité | Quota maximum |
|---|---|---|
| FederatedUpdate | 1,0 (la plus haute) | 50 000 |
| Financial | 0,8 | 50 000 |
| IoTData | 0,5 | 100 000 |
| Governance | 0,7 | 50 000 |
Système de quotas
- Limites par classe : Financial 50K, IoT 100K, Global 100K
- Plafond par expéditeur : 512 transactions en attente par expéditeur
- Extraction équitable :
drain_fair_batch()respecte les quotas et appellerecord_removal()
Notation SIMD
Le répartiteur note les transactions en utilisant un calcul par lot optimisé SIMD :
score = fee_normalized * fee_weight + class_priority * class_weight
Poids par défaut : fee_weight = 0.7, class_weight = 0.3.
Implémentation SIMD
| Architecture | Jeu d'instructions | Voies | Seuil |
|---|---|---|---|
| x86_64 | AVX2 + FMA | 4 doubles | 32 transactions |
| ARM (aarch64) | NEON | 2 doubles | 32 transactions |
| Repli | Scalaire | 1 | Toujours |
Pour les lots de moins de 32 transactions, le calcul scalaire est utilisé (la surcharge d'initialisation SIMD dépasse le bénéfice).
Cache de scores
Le cache LRU évite de recalculer les scores pour les transactions qui restent dans le mempool entre les blocs.
Poids adaptatifs
Avec l'indicateur de fonctionnalité adaptive_weights, les poids s'ajustent dynamiquement selon :
- La distribution des frais dans le mempool
- La diversité des classes
- Le débit historique
Production de blocs
Le proposeur élu :
- Appelle
drain_for_block_production(max_block_txs) - Obtient les top-N transactions ordonnées par score
- Exécute
final_validationavec suivi despending_nonces(évite le rejet par nonce périmé) - Calcule la racine de transaction : étiquette de feuille
"TXv1", accumulateur glissant - Calcule la racine d'état : graine
"STATEv1-LE", instantané lexicographique - Signe le bloc avec Ed25519
- Diffuse via gossipsub
Gestion des nonces
final_validationsuitpending_noncesHashMap pour les transactions extraites mais non validées- Correctif de démarrage à froid : Accepte le nonce disponible le plus bas lorsque
storage_nonce=0 ET pending_nonces=0 - Réinitialisation du nonce : Le générateur de transactions réinitialise lorsque le nonce local > storage_nonce + 200
Stockage
Les blocs validés sont stockés dans les familles de colonnes RocksDB :
| Famille de colonnes | Clé | Valeur |
|---|---|---|
CF_BLOCKS | hauteur (u64 LE) | Bloc (bincode) |
CF_TRANSACTIONS | tx_hash | Transaction (bincode) |
CF_ACCOUNTS | adresse (32 octets) | Compte (bincode) |
CF_METADATA | "chain_head" | Dernier bloc (bincode) |
Les comptes vides (solde=0, nonce=0) ne sont jamais persistés.