Aller au contenu principal

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)

  1. Validation du format de signature (ed25519 de 64 octets)
  2. Validation du format de clé publique (ed25519 de 32 octets)
  3. Vérification de la signature par rapport au hachage du message
  4. Limites de taille de transaction

Gardes avec état (accès au stockage requis)

  1. Vérification du nonce : tx.nonce >= account.nonce (tolérance d'écart jusqu'à 5000)
  2. Vérification du solde : account.balance >= tx.amount + tx.fee
  3. Vérification des quotas : Limites par classe et par expéditeur

Classes de transactions

ClassePrioritéQuota maximum
FederatedUpdate1,0 (la plus haute)50 000
Financial0,850 000
IoTData0,5100 000
Governance0,750 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 appelle record_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

ArchitectureJeu d'instructionsVoiesSeuil
x86_64AVX2 + FMA4 doubles32 transactions
ARM (aarch64)NEON2 doubles32 transactions
RepliScalaire1Toujours

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 :

  1. Appelle drain_for_block_production(max_block_txs)
  2. Obtient les top-N transactions ordonnées par score
  3. Exécute final_validation avec suivi des pending_nonces (évite le rejet par nonce périmé)
  4. Calcule la racine de transaction : étiquette de feuille "TXv1", accumulateur glissant
  5. Calcule la racine d'état : graine "STATEv1-LE", instantané lexicographique
  6. Signe le bloc avec Ed25519
  7. Diffuse via gossipsub

Gestion des nonces

  • final_validation suit pending_nonces HashMap 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 colonnesCléValeur
CF_BLOCKShauteur (u64 LE)Bloc (bincode)
CF_TRANSACTIONStx_hashTransaction (bincode)
CF_ACCOUNTSadresse (32 octets)Compte (bincode)
CF_METADATA"chain_head"Dernier bloc (bincode)

Les comptes vides (solde=0, nonce=0) ne sont jamais persistés.