kb_execution_solana
kb_execution_solana transforme un ExApiPreparedExecutionPlan commun en message et transaction Solana, puis résout les signataires via l’interface Solana Signer et signe uniquement après une simulation autorisée par kb_execution_safety.
La crate est indépendante des exécuteurs concrets et des transports RPC. Elle assemble aussi bien les plans à recent blockhash que les transactions consommant réellement un durable nonce.
API publique
| Export | Usage |
|---|---|
build_legacy_transaction(...) |
Compile un plan Latest avec un recent blockhash explicite. |
build_durable_nonce_transaction(...) |
Compile un plan DurableNonce avec un état nonce validé et injecte l’avance en première instruction. |
durable_nonce_account_data_length() |
Fournit la longueur exacte à demander au RPC pour un compte nonce. |
parse_durable_nonce_account(...) |
Valide et décode un snapshot complet de compte nonce System. |
DurableNonceAccountState |
État validé exposant compte, autorité, nonce/blockhash et coût par signature. |
UnsignedSolanaTransaction |
Message compilé non signé, destiné aux frais, à la simulation exacte et à la signature contrôlée. |
SolanaSimulationEvidence |
Simulation liée au hash et au blockhash/nonce exacts du message. |
SignedSolanaTransaction |
Transaction signée, vérifiable localement et sérialisable pour sendTransaction. |
Méthodes des types
| Type | Méthodes publiques |
|---|---|
DurableNonceAccountState |
account(), authority(), blockhash(), lamports_per_signature(). |
UnsignedSolanaTransaction |
plan(), message_hash(), blockhash(), required_signer_pubkeys(), message_base64(), transaction_base64(), bind_simulation(...), sign_after_simulation(...). |
SolanaSimulationEvidence |
message_hash(), blockhash(), simulation(). |
SignedSolanaTransaction |
message_hash(), primary_signature(), signer_pubkeys(), wire_length(), transaction_base64(), verify_signatures(). |
Exemple de flux
let unsigned = kb_execution_solana::build_legacy_transaction(&plan, recent_blockhash)?;
let simulation = rpc_simulation.to_execution_result(
unsigned.message_hash(),
unsigned.blockhash(),
observed_cluster,
)?;
let evidence = unsigned.bind_simulation(simulation)?;
let signed = unsigned.sign_after_simulation(&evidence, signers.as_slice())?;
signed.verify_signatures()?;
Le transport RPC reste extérieur : cette crate ne récupère pas le blockhash, ne charge pas le compte nonce et n’envoie pas le payload signé.
Assemblage à recent blockhash
build_legacy_transaction(plan, recent_blockhash)
Construit une transaction legacy non signée à partir d’un blockhash base58 obtenu par getLatestBlockhash.
La fonction vérifie :
- la politique
ExecutionBlockhashKind::Latest; - les public keys et le blockhash ;
- la présence d’au moins une instruction ;
- l’égalité exacte entre signataires déclarés et signataires compilés ;
- la limite wire Solana de 1 232 octets.
Un plan DurableNonce est refusé et doit utiliser le chemin dédié.
Lecture et validation d’un compte nonce
durable_nonce_account_data_length()
Retourne la taille wire officielle d’un compte nonce, actuellement 80 octets. Cette valeur doit être utilisée comme limite exacte d’un appel getAccountInfo avec données complètes.
parse_durable_nonce_account(account, owner, executable, space, data)
Décode l’état officiel solana_nonce::versions::Versions avec wincode::deserialize_exact et produit un DurableNonceAccountState uniquement lorsque toutes les conditions suivantes sont satisfaites :
- adresse du compte valide ;
- owner égal au System Program ;
- compte non exécutable ;
spaceet longueur décodée égaux à la taille officielle ;- version
Current; - état
Initialized; - autorité et valeur nonce extraites sans approximation.
Les états Legacy, Uninitialized, tronqués, suffixés ou possédés par un autre programme sont refusés. DurableNonceAccountState expose uniquement l’adresse, l’autorité, la valeur nonce utilisée comme blockhash et le coût par signature stocké dans l’état.
Le chargement réseau reste extérieur à cette crate. Le contrat RPC prévu est :
let config = kb_rpc::GetAccountInfoConfig::confirmed_with_data(
kb_execution_solana::durable_nonce_account_data_length(),
)?;
Assemblage durable nonce
build_durable_nonce_transaction(plan, nonce_state)
Construit une transaction non signée qui consomme l’état nonce validé.
La fonction exige :
- une politique
ExecutionBlockhashKind::DurableNoncesans âge de blockhash récent ; - le même compte nonce dans la politique et dans l’état validé ;
- la même autorité dans la politique et dans l’état validé ;
- l’autorité nonce dans
required_signers; - au moins une instruction métier à exécuter après l’avance nonce.
L’assemblage utilise Message::new_with_nonce, place l’instruction officielle AdvanceNonceAccount en position zéro, puis remplace le champ recent_blockhash par la valeur nonce extraite de l’état. Le plan d’origine n’est pas muté : UnsignedSolanaTransaction::plan() expose un plan effectif cloné contenant l’instruction injectée.
Après compilation, la crate vérifie :
- la reconnaissance de la transaction par
solana_transaction::uses_durable_nonce; - l’égalité exacte entre signataires déclarés et signataires compilés ;
- la taille wire ;
- le hash du message et la valeur nonce effectivement compilée.
Les opérations de gestion du compte nonce elles-mêmes, telles que initialize, authorize, withdraw ou upgrade, restent des transactions ordinaires à recent blockhash. Elles ne passent pas par ce chemin.
Simulation et signature
UnsignedSolanaTransaction
Expose :
- le plan effectif ;
- le hash exact du message ;
- le recent blockhash ou la valeur nonce compilée ;
- l’ordre exact des signataires ;
- le message base64 pour
getFeeForMessage; - la transaction non signée base64 pour
simulateTransactionavecsigVerify = falseetreplaceRecentBlockhash = false.
bind_simulation(result)
Lie le résultat typé de simulation au hash du message et au blockhash/nonce compilé. Une simulation utilisant un autre message, une autre source de blockhash ou un blockhash de remplacement ne peut pas autoriser la signature.
sign_after_simulation(evidence, signers)
Réévalue kb_execution_safety, exige une décision Allow, résout exactement tous les signataires via &dyn solana_signer::Signer, signe puis vérifie que la transaction est complète.
Les signataires manquants, supplémentaires ou dupliqués sont refusés. La fonction ne contacte aucun endpoint RPC et n’envoie rien.
SignedSolanaTransaction
Expose uniquement des données non secrètes :
- hash du message ;
- signature primaire ;
- public keys des signataires ;
- taille wire ;
- payload base64 signé ;
- vérification locale des signatures.
Le payload signé reste côté backend. Il ne doit pas être transféré automatiquement à Tauri. kb_rpc::HttpClient::send_transaction et sa variante pool imposent le preflight et refusent une signature RPC différente de la signature primaire locale.