BARU: Helius mengakuisisi Light Protocol
daftar periksa migrasi solana agave 4.2
Blog/Pembaruan

Agave 4.2: Daftar Periksa Migrasi

Produk @ HeliusKiryl Miranovich di XKiryl Miranovich di LinkedIn
Bacaan 5 menit

Kami telah membahas rangkaian fitur Agave 4.2 dalam ringkasan rilis. Postingan ini membahas migrasi: apa yang akan rusak dan cara memverifikasi integrasi Anda sebelum gerbang fitur diaktifkan.

Sebagian besar perubahan ini menghasilkan data yang salah atau hilang, bukan error, sehingga tidak akan muncul di log pengecualian Anda.

Linimasa Aktivasi

WaktuPerubahanStatus
11 Agu 2026Anza merekomendasikan 4.2 untuk mainnet; upgrade validator dimulaiSedang berlangsung
Saat node di-upgradePenghentian update akun yang tidak berubah dan perubahan Token-2022 jsonParsed mulai berlakuSelesai
Batas epoch pertama setelah upgradeNilai DeactivatedStake rewardType muncul dalam rewardSelesai
Epoch 1020Durasi slot dipangkas dari 400 md menjadi 350 md, langkah pertama dari empat tahap menuju 200 mdSelesai
Epoch 1024Durasi slot dipangkas dari 350 md menjadi 300 mdDijadwalkan (diperkirakan pada 28 Agu)
Gerbang fitur, tanggal belum ditentukanTransaction v1 (transaksi 4.096 byte)Tertunda (belum ada tanggal yang diumumkan, jadi bersiaplah seolah-olah fitur ini akan aktif minggu depan)
Lima gerbang fitur, tanggal belum ditentukanPengurangan rent, dari 6.960 lamport/byte turun bertahap menjadi 696Tertunda
Agave 4.3, ditargetkan Okt 2026Konsensus AlpenglowRilis mendatang

Perubahan yang menyebabkan inkompatibilitas di Agave 4.2

Transaction v1 menggagalkan seluruh panggilan

SIMD-0296 dan SIMD-0385 meningkatkan batas ukuran transaksi Solana menjadi 4.096 byte melalui format transaksi baru.

Ruang tambahan ini memungkinkan developer menjalankan beban kerja on-chain yang lebih besar, seperti bukti ZK atau rute DEX dengan lebih banyak tahap. 

Namun, satu transaksi v1 dalam sebuah blok akan merusak getBlock untuk seluruh blok jika panggilan tidak menetapkan maxSupportedTransactionVersion: 1.

Transaksi lainnya juga tidak dikembalikan; seluruh panggilan menghasilkan error. getTransaction dan getTransactionsForAddress (dengan transactionDetails = full) gagal dengan cara yang sama pada transaksi v1 apa pun. 

Cara memperbaikinya:

  • Upgrade SDK Anda ke rilis yang dapat mendekode v1. Dukungan sedang ditambahkan di berbagai klien. Jika SDK Anda belum merilis dukungan transaction v1, pantau catatan rilisnya untuk transaction v1 atau SIMD-0385.
    • Klien JS populer: @solana/kit 8.0+, @solana/web3.js v3
    • Crate Rust populer: solana-rpc-client-api 4.2+, solana-client 4.2+, solana-transaction 4.2+, solana-compute-budget 4.2+, crate Anza lainnya.
  • Tetapkan maxSupportedTransactionVersion: 1 pada setiap panggilan getBlock, getTransaction, dan getTransactionsForAddress (dengan transactionDetails = full)
  • Tetapkan maxSupportedTransactionVersion: 1 dalam objek opsi setiap langganan Enhanced WebSockets transactionSubscribe (dengan transactionDetails ditetapkan ke full atau accounts). Langganan yang disalin dari contoh dokumentasi menetapkannya ke 0; naikkan ke 1
Kode
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransactionsForAddress",
  "params": [
    "Vote111111111111111111111111111111111111111",
    {
      "transactionDetails": "full",
      "sortOrder": "desc",
      "filters": {
        "status": "succeeded"
      },
      "maxSupportedTransactionVersion": 1
    }
  ]
}

Parameter tersebut menentukan versi tertinggi yang dapat ditangani klien Anda. Parameter ini aman ditetapkan sekarang dan tidak mengubah cara transaksi legacy dan v0 dikembalikan.

Kegagalan compute budget Transaction v1

Transaksi v1 menyimpan compute limit dan priority fee dalam objek transactionConfig, bukan dalam instruksi ComputeBudget. Dasbor fee dan pengestimasi priority fee yang mendeteksi fee dengan mencocokkan instruksi tersebut akan membaca setiap transaksi v1 seolah-olah membayar nol, tanpa error.

Cara memperbaikinya:

Sebagai gantinya, baca nilai dari kolom priorityFee baru dalam konfigurasi transaksi. Perhatikan bahwa kolom priorityFee baru menyatakan total fee dalam lamport (bukan harga per compute unit).

Kode
"message": {
  "instructions": ["… no ComputeBudget instruction here …"],
  "recentBlockhash": "...",
  "transactionConfig": {
    "computeUnitLimit": 200000,
    "heapSize": null,
    "loadedAccountsDataSizeLimit": 200000,
    "priorityFee": 50000
  }
}

Akun yang tidak berubah berhenti mengirimkan update

Agave 4.2 hanya mengirimkan peristiwa akun saat akun benar-benar ditulis. Untuk langganan akun gRPC dan WSS LaserStream, ini berarti jumlah peristiwa berkurang sekitar 80%.

Cara memperbaikinya:

  1. Jika Anda mencocokkan transaksi dengan update akun, jangan lagi menunggu update dari setiap akun writable; anggap update yang tidak ada sebagai "akun tidak berubah". Hanya pembayar fee yang dijamin mendapatkan update karena selalu membayar fee.
  2. Jika Anda menggunakan frekuensi update sebagai sinyal kesehatan, hapus pemeriksaan tersebut untuk akun yang sering dikunci tetapi jarang berubah. Akun yang tidak aktif tetap sehat; akun tersebut berhenti mengirimkan update karena tidak ada perubahan.

Nilai rewardType baru

Akun stake yang selesai dinonaktifkan kini menerima pembayaran terakhirnya dengan nilai rewardType baru, DeactivatedStake, dalam array reward getBlock dan blockSubscribe. Struktur objek reward sama seperti di Agave 4.1, sehingga parser yang hanya menerima jenis reward yang telah dikenalnya akan melewatkan pembayaran DeactivatedStake tanpa error.

getInflationReward tidak terpengaruh; risiko hanya berlaku saat Anda mengurai sendiri array reward mentah.

Cara memperbaikinya:

Tambahkan DeactivatedStake ke nilai rewardType yang diterima parser Anda, dan catat nilai apa pun yang tidak dikenali alih-alih membuang record.

Kode
{
  "pubkey": "...",
  "lamports": 10000000,
  "postBalance": 50000000000,
  "rewardType": "DeactivatedStake",
  "commission": null,
  "commissionBps": 500
}

Token-2022: satu kolom dihapus, parsing diperluas

Dalam respons jsonParsed, depositConfidentialTransfer dan withdrawConfidentialTransfer tidak lagi memiliki source dan destination, dan kini menggunakan satu kolom account. Label lama tidak tepat; setiap instruksi mengakses satu akun token.

Perbaikannya adalah memperbarui parser Token-2022 agar mendukung kolom baru tersebut.

Kode
{
  "parsed": {
    "type": "depositConfidentialTransfer",
    "info": {
      "account": "6XVfUq9jZQtBfqcm1Rz8fBhViyoyzWiEUAaWnQ9AmXeR",
      "mint": "8fJ7bCZo2vZ3vAnyCBQgZuLYuTX1qPnKvsMKotk92B2J",
      "amount": 42,
      "decimals": 9,
      "owner": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn"
    }
  }
}

Permissioned burn, unwrapLamports, confidentialBurn, dan operasi batch kini dikembalikan sebagai JSON yang telah diurai, bukan byte mentah. 

Kode
{
  "parsed": {
    "type": "unwrapLamports",
    "info": {
      "source": "9rr9Xh6PXPKcVqbCB1qxGDWRUJJAdguqcUqVuUqEjqQK",
      "destination": "BhU2wDgmvvMNC1vTSU4aG7BvW26MoTMSDL63hcMqziGL",
      "amount": "1000000",
      "authority": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn"
    }
  }
}

Mint dengan ekstensi yang sebelumnya tidak dikenali dahulu mengembalikan array extensions kosong; di Agave 4.2, array tersebut kini terisi.

Jika kode Anda menganggap array kosong sebagai "tidak ada ekstensi", bersiaplah melihat nilai mulai muncul di sana.

Kode
"extensions": [
  {
    "extension": "transferFeeConfig",
    "state": {
      "transferFeeConfigAuthority": "...",
      "withdrawWithheldAuthority": "...",
      "withheldAmount": 0,
      "olderTransferFee": {...},
      "newerTransferFee": {...}
    }
  },
  {
    "extension": "permissionedBurnConfig",
    "state": {
      "authority": "3nGhQzXCzoDDvW9pkg8fVLGDrJc23uwFz7qzW26MoTMS"
    }
  }
]

Konstanta waktu slot sudah usang

Mainnet menjalankan slot 350 md sejak epoch 1020. Pemangkasan berikutnya menjadi 300 md dijadwalkan untuk epoch 1024 (diperkirakan pada 28 Agu), dengan target akhir 200 md. Konstanta 400 md yang ditulis langsung dalam perhitungan slot ke waktu saat ini meleset 12,5% dan akan semakin menyimpang pada setiap tahap. 

Cara memperbaikinya:

Turunkan waktu dari timestamp blok atau jadikan nilainya dapat dikonfigurasi, dan pastikan indexer Anda mampu mengimbangi saat blok mulai tiba lebih cepat.

Verifikasi bahwa Anda telah selesai

Untuk memverifikasi bahwa Anda telah selesai, jalankan audit agen dan konfirmasikan dependensi Anda.

Jalankan audit agen

Salin skill di bawah ini ke agen coding Anda. 

Untuk Claude Code, simpan sebagai .claude/skills/agave-42-readiness/SKILL.md.

Untuk agen lain, tempelkan sebagai prompt tugas.

Prompt
---
name: agave-42-readiness
description: Audit this repository for Solana Agave 4.2 breaking changes. Use when asked to check Agave 4.2 readiness, migrate for transaction v1, or audit Solana RPC/streaming integration code.
---

# Agave 4.2 Readiness Audit

Audit the repository for the five Agave 4.2 breaking changes below. For each, locate the relevant code, judge whether it is affected, and report file:line with a verdict of PASS, FAIL, or NEEDS REVIEW. Do not modify code unless asked to fix findings.

## Check 1: Transaction v1 opt-in (highest priority)
Find every `getBlock`, `getTransaction`, and `getTransactionsForAddress` (with `transactionDetails = full`) call, plus every Enhanced WebSockets `transactionSubscribe` subscription. Search all languages, raw JSON-RPC request bodies (`"method": "getBlock"`, `"method": "transactionSubscribe"`), and SDK wrappers (`connection.getBlock`, `connection.getParsedTransaction`, `rpc_client.get_block`, `client.GetTransaction`, and similar).
- FAIL if `maxSupportedTransactionVersion` is absent or set to 0. Once the v1 feature gate activates, these calls fail on v1 transactions with JSON-RPC error code -32015: `"Transaction version (1) is not supported by the requesting client. Please use \"maxSupportedTransactionVersion\" in your request."` Also grep for `-32015` in logs and error handlers; hits mean the project has already been failing on versioned transactions.
- Also FAIL if the project deserializes raw transaction bytes (custom indexer, signer, relayer) and the decoder does not handle the v1 layout: version byte 0x81 (decimal 129, vs 0x80 for v0), signatures at the END of the transaction instead of the front, compute budget carried in a header config mask instead of instructions.
- Correct fix order: upgrade the Solana SDK to a v1-capable version (JS: @solana/kit 8.0+ or @solana/web3.js v3), then set `maxSupportedTransactionVersion: 1`. Flag if the parameter is set but the installed SDK version predates v1 support.
- Also FAIL if priority fee or compute budget extraction scans for ComputeBudget program instructions (`ComputeBudget111111111111111111111111111111`, `setComputeUnitPrice`, `setComputeUnitLimit`). A v1 transaction contains no such instructions; its values live in a `transactionConfig` object in the message. Scanning code reads every v1 transaction as paying zero priority fee.
- Units trap, FAIL even when the code reads `transactionConfig`: legacy/v0 `setComputeUnitPrice` is **micro-lamports per compute unit**; v1 `priorityFee` is a **total in lamports**. Code that ports the old `price × computeUnitLimit ÷ 1e6` math onto the new field misreports fees. `priorityFee` needs no multiplication. Null fields mean the sender did not set them.

Example v1 message:
```
"message": {
  "instructions": ["… no ComputeBudget instruction here …"],
  "recentBlockhash": "...",
  "transactionConfig": {
    "computeUnitLimit": 200000,
    "heapSize": null,
    "loadedAccountsDataSizeLimit": 200000,
    "priorityFee": 50000
  }
}
```
`"priorityFee": 50000` = this transaction pays 50,000 lamports total. Legacy and v0 messages omit `transactionConfig` entirely, so its presence (or `"version": 1` on the enclosing transaction) identifies v1.

## Check 2: rewardType parsed as a closed enum
Find code reading `rewardType` from `getBlock`, `blockSubscribe`, or Geyser/gRPC reward arrays. Search for the existing values too (`"Fee"`, `"Rent"`, `"Staking"`, `"Voting"` in JSON paths; `RewardType::` in Rust; reward-type enums in generated gRPC code).
- 4.2 adds the value `DeactivatedStake` — same capitalized casing as the existing JSON values (`"Staking"`, not `"staking"`). A reward entry looks like:
```
{
  "pubkey": "...",
  "lamports": 10000000,
  "postBalance": 50000000000,
  "rewardType": "DeactivatedStake",
  "commission": null
}
```
- FAIL if unknown values throw, or fall into a match/switch arm or if/else chain that drops the record without logging: a Rust `match` without a logging wildcard arm, a TS `switch` whose `default` is silent, a lookup table where a missing key skips the entry. Closed parsers lose every deactivating stake account's final payout with no error.
- FAIL if a deserialization enum (serde, protobuf mapping, Zod/io-ts schema) rejects unknown reward-type strings; the whole reward array or block record errors out, not just one entry.
- PASS requires unknown values to be preserved or logged. If the project aggregates staking yield by filtering `rewardType == "Staking"`, add a NEEDS REVIEW noting the team must decide whether `DeactivatedStake` payouts belong in totals; they are final payouts, not recurring yield.

## Check 3: Transaction-to-account-update matching
Find logic that correlates transactions with account update notifications. Search for `accountSubscribe`, Yellowstone/LaserStream `SubscribeRequest` account filters, and code that builds a pending set of a transaction's writable accounts and waits to check them off as updates arrive.
- FAIL if it assumes every writable account in a transaction produces an update. On 4.2, an account that was write-locked but not modified emits nothing; logic awaiting the full set hangs forever. Typical patterns: a countdown/completion latch over `message.accountKeys` writable entries, a timeout that treats a missing update as an error, a reconciler that re-fetches "late" accounts. The fee payer is the only account guaranteed to update.
- The correct interpretation of a missing update is "this account did not change"; its pre-transaction state is still current.
- Also FAIL liveness or health checks that treat update frequency as a signal, and flag alert thresholds calibrated to pre-4.2 volume; account-subscription event counts drop roughly 80% on 4.2.

## Check 4: Token-2022 jsonParsed changes
Find parsers reading Token-2022 `jsonParsed` output: instruction types `depositConfidentialTransfer` and `withdrawConfidentialTransfer`, and mint-account `extensions` arrays.
- FAIL if confidential-transfer parsers read `source` or `destination`; 4.2 replaces both with a single `account` field. New shape:
```
"info": {
  "account": "...",   // was source + destination
  "mint": "...",
  "amount": 42,
  "decimals": 9,
  "owner": "..."      // multisig: "multisigOwner" + "signers" array instead
}
```
- New instruction types now come back parsed instead of raw: `unwrapLamports`, `confidentialBurn`, permissioned burn, and batch operations. FAIL if code assumes these arrive as raw base64/base58 data, and flag `unwrapLamports` parsers that require `info.amount` or treat it as a number: it is a **string** and is **omitted entirely** when the instruction unwraps the full balance.
- Extensions array: on 4.1, one unrecognized extension type on a mint made the node return `"extensions": []`, hiding every extension including known ones. On 4.2 the full array returns, each entry as `{"extension": "<name>", "state": {...}}`, with still-undecodable ones as `{"extension": "unparseableExtension"}`. FAIL if code treats an empty array as proof of no extensions, or throws on extension names it does not recognize (`scaledUiAmountConfig`, `pausableConfig`, `permissionedBurnConfig`, `unparseableExtension`, and future values).

## Check 5: Slot timing and streaming dependencies
- FAIL on hardcoded slot-duration constants: `400`, `0.4`, `400_000` microseconds, `MS_PER_SLOT`, `SLOT_DURATION`, `DEFAULT_MS_PER_SLOT`, or slot-to-time math like `slots * 400`. Mainnet is 350ms, cutting to 300ms on Aug 28, 2026, stepping toward 200ms. Constants inherited from an SDK count as hardcoded. PASS requires timing derived from block timestamps (e.g. `getBlockTime` deltas over a few thousand slots) or a config value with a documented update path.
- Also flag capacity assumptions keyed to block rate: batch sizes, poll intervals, and queue depths sized for 400ms blocks fall behind as slots shorten.
- In Cargo.toml/Cargo.lock: FAIL if `yellowstone-grpc-client` < 13.3.0 or `yellowstone-grpc-proto` < 12.6.0 (first proto carrying transaction v1). Recommend client 13.3.0, proto 12.6.0, both declared.
- For Go gRPC clients: flag if generated protos predate transaction v1; regenerate from latest Yellowstone protos and solana-storage-proto.
- If the project uses the Helius LaserStream SDK (package names `helius-laserstream`, `laserstream` in dependencies): FAIL if below JS 0.8.4, Rust 0.6.3, or Go 0.2.0 (first releases with the v1-capable proto).

## Report format
Output a table: check, verdict, file:line references, one-line remediation. End with an overall verdict (READY / NOT READY) and the ordered fix list. Full migration guide: https://www.helius.dev/blog/agave-4-2-migration-checklist
PerluasCiutkan

Konfirmasikan dependensi stream

Rust: yellowstone-grpc-client 13.3.0 dan yellowstone-grpc-proto 12.6.0, keduanya dideklarasikan, lalu cargo update. 

Go: buat ulang dari proto Yellowstone terbaru dan solana-storage-proto. 

LaserStream SDK: JS 0.8.4, Rust 0.6.3, dan Go 0.2.0 atau versi lebih baru menyertakan proto yang mendukung v1. Langganan dan filter Anda tidak memerlukan perubahan di jalur mana pun.

Pertanyaan

Jika integrasi Anda berperilaku berbeda di 4.2 dan postingan ini tidak menjelaskannya, hubungi kami melalui Discord atau dukungan. Untuk rincian tingkat fitur, baca ringkasan 4.2.

Berlangganan Helius

Ikuti perkembangan terbaru dalam pengembangan Solana dan dapatkan pembaruan saat kami memublikasikan postingan