← Retour au fil
Agave 4.2 : la checklist de migration
Helius27 août, 17h · il y a 2j

Agave 4.2 : la checklist de migration

La migration vers Agave 4.2 ne renverra pas d'erreurs : les données seront simplement fausses ou manquantes. Vérifiez votre intégration avant l'activation.

Ce guide détaille les changements cassants d'Agave 4.2, la nouvelle version du client Solana, et comment vérifier son intégration avant l'activation des features. Point critique : le format Transaction v1 (SIMD-0296, SIMD-0385), qui porte la limite des transactions à 4 096 octets. Une seule transaction v1 dans un bloc fait échouer tout appel à getBlock ou getTransaction sans le paramètre maxSupportedTransactionVersion: 1.

Autres pièges : les frais de compute des transactions v1 se lisent désormais dans transactionConfig, plus d'événements pour les comptes inchangés (environ 80 % en moins sur LaserStream gRPC et WSS), nouveau rewardType DeactivatedStake pour les stake accounts désactivés, et parsing Token-2022 remanié. La plupart de ces changements renvoient des données fausses ou manquantes au lieu d'erreurs : rien n'apparaît dans les logs d'exceptions.

Solana

Détails

Source
Helius
Publication
27 août à 17h04

Contenu source (brut)

<p>We covered the Agave 4.2 feature set in our <a href="https://www.helius.dev/blog/agave-v4-2">release overview</a>. This post covers migration: what breaks and how to verify your integration before the feature gate activates. </p><p>Most of these changes return wrong or missing data instead of errors, so they won&#39;t show up in your exception logs.</p><h2>Activation Timeline</h2><span>unknown node</span><h2>Agave 4.2 breaking changes</h2><h3>Transaction v1 fails the whole call</h3><p><a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0296-larger-transactions.md">SIMD-0296</a> and <a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md">SIMD-0385</a> raise the Solana transaction size limit to 4,096 bytes through a new transaction format. </p><p>The extra room lets developers run bigger on-chain workloads, like ZK proofs or DEX routes with more legs. </p><p>The catch: one v1 transaction in a block breaks <code>getBlock</code> for the whole block if the call doesn&#39;t set <code>maxSupportedTransactionVersion: 1</code>. </p><p>The other transactions don&#39;t come back either; the entire call errors. <code>getTransaction</code> and <code>getTransactionsForAddress</code> (with <code>transactionDetails = full</code>) fail the same way on any v1 transaction. </p><h4>How to fix:</h4><ul class="list-bullet"><li value=1>Upgrade your SDK to a release that decodes v1. Support is landing across clients. If your SDK hasn&#39;t shipped transaction v1 support yet, watch its release notes for transaction v1 or SIMD-0385.</li><li class="nestedListItem" value=2><ul class="list-bullet"><li value=1>Popular JS clients: @solana/kit 8.0+, @solana/web3.js v3</li><li value=2>Popular Rust crates: solana-rpc-client-api 4.2+, solana-client 4.2+, solana-transaction 4.2+, solana-compute-budget 4.2+, <a href="https://crates.io/users/anza-team?sort=recent-updates">other Anza crates</a>.</li></ul></li><li value=2>Set <code>maxSupportedTransactionVersion: 1</code> on every <a href="https://www.helius.dev/docs/api-reference/rpc/http/getblock">getBlock</a>, <a href="https://www.helius.dev/docs/api-reference/rpc/http/gettransaction">getTransaction</a>, and <a href="https://www.helius.dev/docs/api-reference/rpc/http/gettransactionsforaddress">getTransactionsForAddress</a> call (with <code>transactionDetails = full</code>)</li><li value=3>Set <code>maxSupportedTransactionVersion: 1</code> on WebSocket <code>transactionSubscribe</code> call</li></ul><pre><code>{ "jsonrpc": "2.0", "id": "1", "method": "getTransactionsForAddress", "params": [ "Vote111111111111111111111111111111111111111", { "transactionDetails": "full", "sortOrder": "desc", "filters": { "status": "succeeded" }, "maxSupportedTransactionVersion": 1 } ] } </code></pre><p>The parameter declares the highest version your client handles. It is safe to set today and changes nothing about how legacy and v0 transactions come back.</p><h3>Transaction v1 compute budget failures</h3><p>A v1 transaction stores its compute limit and priority fee in the <code>transactionConfig</code> object instead of <code>ComputeBudget</code> instructions. Fee dashboards and priority fee estimators that detect fees by matching those instructions read every v1 transaction as paying zero, with no error.</p><h4>How to fix:</h4><p>Read the values from the new <code>priorityFee</code> field in the transaction config instead. Note the new <code>priorityFee</code> field states a total fee in lamports (not price per compute unit).</p><pre><code>"message": { "instructions": ["… no ComputeBudget instruction here …"], "recentBlockhash": "...", "transactionConfig": { "computeUnitLimit": 200000, "heapSize": null, "loadedAccountsDataSizeLimit": 200000, "priorityFee": 50000 } } </code></pre><h3>Unchanged accounts stop emitting updates</h3><p>Agave 4.2 only emits account events when an account is actually written. For <a href="[object Object]" rel="noopener noreferrer" target="_blank">LaserStream</a> gRPC and WSS account subscriptions, this means roughly 80% fewer events.</p><h4>How to fix:</h4><ol class="list-number"><li value=1>If you match transactions to account updates, stop waiting for an update from every writable account; treat a missing update as &quot;the account did not change&quot;. Only the fee payer is guaranteed to update, since it always pays the fee.</li><li value=2>If you use update frequency as a health signal, remove that check for accounts that are often locked but rarely changed. A quiet account is healthy; it stopped emitting because nothing changed.</li></ol><h3>A new rewardType value</h3><p>Stake accounts that finish deactivating now receive their final payout under a new <code>rewardType</code> value, <code>DeactivatedStake</code>, in <code>getBlock</code> and <code>blockSubscribe</code> reward arrays. The reward object shape is identical to Agave 4.1, so a parser that only accepts the reward types it already knows will skip <code>DeactivatedStake</code> payouts without an error.</p><p><code>getInflationReward</code> is unaffected; the risk only applies where you parse raw reward arrays yourself.</p><h4>How to fix:</h4><p>Add <code>DeactivatedStake</code> to the <code>rewardType</code> values your parser accepts, and log any value you don&#39;t recognize instead of dropping the record.</p><pre><code>{ "pubkey": "...", "lamports": 10000000, "postBalance": 50000000000, "rewardType": "DeactivatedStake", "commission": null, "commissionBps": 500 } </code></pre><h3>Token-2022: one field removed, parsing expanded</h3><p>In <code>jsonParsed</code> responses, <code>depositConfidentialTransfer</code> and <code>withdrawConfidentialTransfer</code> lose source and destination in favor of a single account field. The old labels were incorrect; each instruction touches one token account. </p><p>The fix is to update Token-2022 parsers to support the new field.</p><pre><code>{ "parsed": { "type": "depositConfidentialTransfer", "info": { "account": "6XVfUq9jZQtBfqcm1Rz8fBhViyoyzWiEUAaWnQ9AmXeR", "mint": "8fJ7bCZo2vZ3vAnyCBQgZuLYuTX1qPnKvsMKotk92B2J", "amount": 42, "decimals": 9, "owner": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn" } } } </code></pre><p>Permissioned burn, <code>unwrapLamports</code>, <code>confidentialBurn</code>, and batch operations now come back as parsed JSON instead of raw bytes. </p><pre><code>{ "parsed": { "type": "unwrapLamports", "info": { "source": "9rr9Xh6PXPKcVqbCB1qxGDWRUJJAdguqcUqVuUqEjqQK", "destination": "BhU2wDgmvvMNC1vTSU4aG7BvW26MoTMSDL63hcMqziGL", "amount": "1000000", "authority": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn" } } } </code></pre><p>Mints carrying previously unrecognized extensions used to return an empty <code>extensions</code> array; on Agave 4.2 the array is populated. </p><p>If your code treats an empty array as &quot;no extensions,&quot; expect values to start appearing there.</p><pre><code>"extensions": [ { "extension": "transferFeeConfig", "state": { "transferFeeConfigAuthority": "...", "withdrawWithheldAuthority": "...", "withheldAmount": 0, "olderTransferFee": {...}, "newerTransferFee": {...} } }, { "extension": "permissionedBurnConfig", "state": { "authority": "3nGhQzXCzoDDvW9pkg8fVLGDrJc23uwFz7qzW26MoTMS" } } ] </code></pre><h3>Slot timing constants are stale</h3><p>Mainnet runs 350ms slots as of epoch 1020. The next cut, to 300ms, is scheduled for epoch 1024 (expected on Aug 28), with 200ms as the target. Hardcoded 400ms constants in slot-to-time math are off by 12.5% today and will drift further with each step. </p><h4>How to fix:</h4><p>Derive timing from block timestamps or make it configurable, and make sure your indexer can keep up when