Pipeline transaksi

Ringkasan

Transaksi melewati 8 tahap: receive, sigverify, sanitize, pemeriksaan budget/age, validasi fee payer, pemuatan akun, eksekusi instruksi, dan commit.

Pipeline pemrosesan transaksi

Ketika transaksi tiba di validator, transaksi melewati serangkaian tahap validasi dan eksekusi. Berikut ini menjelaskan pipeline lengkap dari penerimaan hingga commit, dengan referensi file sumber ke klien validator agave.

1. Receive dan deserialize

Validator menerima byte transaksi melalui UDP/QUIC. Byte mentah harus sesuai dalam satu paket (PACKET_DATA_SIZE = 1.232 byte). Byte tersebut dideserialisasi menjadi VersionedTransaction, yang berisi array signature dan VersionedMessage (baik legacy atau v0).

2. Verifikasi signature (sigverify)

Signature diverifikasi di tahap sigverify sebelum transaksi memasuki tahap banking. Untuk setiap signature pada indeks i, verifier memeriksa Ed25519(signatures[i], account_keys[i], message_bytes). Jika ada signature yang tidak valid, paket akan dibuang.

Verifikasi diparalelkan: validator membagi batch paket menjadi chunk sebesar VERIFY_PACKET_CHUNK_SIZE (128) dan memprosesnya secara paralel.

3. Sanitize

Transaksi yang dideserialisasi disanitasi untuk menghasilkan SanitizedTransaction (atau RuntimeTransaction). Sanitasi memvalidasi invarian struktural:

  • Jumlah signature sesuai dengan num_required_signatures di header
  • Semua program_id_index dan account_indices instruksi berada dalam batas
  • Fee payer (indeks akun 0) adalah signer yang dapat ditulis

Wrapper RuntimeTransaction menyimpan cache metadata yang telah dihitung sebelumnya dari TransactionMeta: hash message, flag transaksi vote, jumlah signature precompile (Ed25519/secp256k1/secp256r1), detail instruksi compute budget, dan total panjang data instruksi.

4. Periksa anggaran komputasi, usia, dan cache status

Metode check_transactions melakukan beberapa pemeriksaan per transaksi:

Anggaran komputasi: Instruksi anggaran komputasi transaksi diurai dan divalidasi terlebih dahulu. Detail biaya dihitung dari batas anggaran dan biaya prioritas. Jika anggaran komputasi tidak valid atau bertentangan, transaksi gagal dengan error parsing anggaran komputasi seperti DuplicateInstruction, InstructionError(..., InvalidInstructionData), atau InvalidLoadedAccountsDataSizeLimit.

Usia blockhash: recent_blockhash transaksi dicari di BlockhashQueue. Jika hash ditemukan dan usianya dalam MAX_PROCESSING_AGE (150 slot), transaksi dilanjutkan. Jika tidak ditemukan, validator memeriksa durable nonce yang valid.

Cache status: Hash pesan transaksi diperiksa terhadap cache status. Jika ditemukan, transaksi ditolak dengan AlreadyProcessed.

5. Validasi nonce dan pembayar biaya

Metode validate_transaction_nonce_and_fee_payer di SVM menangani dua validasi:

Validasi nonce (jika berlaku): Untuk transaksi nonce, validator memuat akun nonce dan memverifikasi:

  • Akun dimiliki oleh System Program
  • Dapat diurai sebagai State::Initialized
  • Durable nonce yang tersimpan cocok dengan recent_blockhash transaksi
  • Nonce dapat dimajukan (durable nonce saat ini berbeda dari durable nonce berikutnya, yaitu nonce belum digunakan dalam blok saat ini)
  • Otoritas nonce telah menandatangani transaksi

Jika valid, nonce dimajukan ke nilai durable nonce berikutnya. Lihat validate_transaction_nonce.

Validasi pembayar biaya: Akun pembayar biaya (selalu indeks 0) dimuat dan diperiksa oleh validate_fee_payer:

  • Akun harus ada (lamports > 0), jika tidak AccountNotFound
  • Akun harus berupa akun sistem atau akun nonce, jika tidak InvalidAccountForFee
  • Lamports harus mencakup min_balance + total_fee, di mana min_balance adalah 0 untuk akun sistem atau rent.minimum_balance(NonceState::size()) untuk akun nonce; jika tidak InsufficientFundsForFee
  • Setelah pengurangan biaya, akun harus tetap bebas sewa (tidak dapat bertransisi dari bebas sewa menjadi membayar sewa)

Biaya dipotong dari pembayar biaya pada tahap ini. Snapshot dari pembayar biaya yang telah dipotong (dan nonce lanjutan, jika berlaku) disimpan sebagai RollbackAccounts, yang merupakan akun yang di-commit bahkan jika eksekusi gagal.

6. Muat akun

load_transaction memuat semua akun yang direferensikan oleh transaksi. AccountLoader membungkus penyimpanan akun eksternal dan memelihara cache lokal batch sehingga akun yang dimodifikasi oleh transaksi sebelumnya dalam batch yang sama terlihat oleh transaksi berikutnya.

Untuk setiap akun non-pembayar biaya, loader:

  1. Mengambil akun dari cache atau accounts-db
  2. Memperbarui status bebas sewa jika diperlukan
  3. Mengakumulasi ukuran data akun terhadap loaded_accounts_data_size_limit (default 64 MiB). Setiap akun dikenakan overhead dasar sebesar TRANSACTION_ACCOUNT_BASE_SIZE (64 byte) ditambah panjang datanya

Untuk setiap program yang dipanggil oleh instruksi transaksi, loader memverifikasi bahwa program account ada dan dimiliki oleh loader yang valid (NativeLoader atau salah satu dari PROGRAM_OWNERS). Program yang tidak valid gagal dengan ProgramAccountNotFound atau InvalidProgramForExecution.

Program LoaderV3 (upgradeable) secara implisit memuat programdata account terkait, yang juga dihitung terhadap batas ukuran data yang dimuat.

Jika pemuatan akun gagal tetapi pembayar biaya berhasil divalidasi, transaksi menjadi hasil FeesOnly: biaya tetap dikumpulkan tetapi tidak ada instruksi yang dieksekusi.

7. Eksekusi instruksi

execute_loaded_transaction membuat TransactionContext dengan semua akun yang dimuat dan memanggil process_message. Instruksi dieksekusi secara berurutan sesuai urutan kemunculannya dalam pesan. Setiap pemanggilan instruksi membuat InvokeContext dan memanggil program target.

Detail pemrosesan instruksi

Fungsi process_message runtime melakukan iterasi melalui setiap instruksi dan memanggil program target:

  1. Untuk setiap instruksi, runtime memanggil prepare_next_top_level_instruction, yang membangun InstructionContext. Konteks ini berisi referensi ke akun instruksi (diselesaikan dari indeks yang dikompilasi), instruction data, dan indeks program account.
  2. Runtime memeriksa apakah program tersebut adalah precompile (Ed25519, Secp256k1, Secp256r1). Precompile diverifikasi secara langsung tanpa memanggil BPF VM.
  3. Untuk semua program lainnya, runtime memanggil process_instruction, yang memuat program dari cache dan mengeksekusinya di mesin virtual BPF.
  4. Setelah instruksi selesai, runtime memverifikasi bahwa total saldo lamport di semua akun instruksi tidak berubah (pemeriksaan UnbalancedInstruction).
  5. Jika ada instruksi yang gagal, seluruh transaksi akan di-rollback. Tidak ada perubahan state perantara yang di-commit.

Setiap instruksi menambah instruction trace. Trace mencakup instruksi tingkat atas dan semua CPI yang dipanggilnya. Total panjang trace (instruksi tingkat atas ditambah semua CPI bersarang) tidak boleh melebihi 64 (MAX_INSTRUCTION_TRACE_LENGTH). Melebihi batas ini akan mengembalikan InstructionError::MaxInstructionTraceLengthExceeded.

Setelah eksekusi, runtime memverifikasi bahwa:

  • Jumlah lamport di semua akun tidak berubah
  • Tidak ada akun yang bertransisi dari rent-exempt ke rent-paying

8. Commit atau rollback

Jika eksekusi berhasil, state akun yang dimodifikasi dari TransactionContext ditulis kembali ke cache lokal batch AccountLoader. Jika eksekusi gagal, hanya RollbackAccounts (fee payer dengan biaya yang dikurangi dan nonce yang dimajukan) yang ditulis kembali. Biaya tetap dikumpulkan, tetapi semua perubahan akun lainnya dibuang.

Ringkasan pipeline

Receive packet (UDP/QUIC)
--> Deserialize into VersionedTransaction
--> Sigverify (parallel Ed25519 verification)
--> Sanitize (structural validation, metadata extraction)
--> Parse compute budget, calculate fees
--> Check blockhash age (or verify nonce account)
--> Check status cache (dedup)
--> Validate nonce authority and advanceability (if nonce transaction)
--> Validate fee payer (load, check balance, deduct fee)
--> Load all accounts (with data size limits)
--> Load programs (verify loaders)
--> Execute instructions sequentially
--> Verify post-conditions (lamport balance, rent state)
--> Commit account changes (or rollback on failure)

Referensi error transaksi

Tabel berikut mencantumkan semua varian TransactionError dan pada tahap pipeline mana mereka terjadi:

ErrorTahapPenyebab
AccountInUsePenjadwalanAkun sudah dikunci oleh transaksi lain dalam batch yang sama
AccountLoadedTwicePenjadwalanSebuah pubkey muncul dua kali dalam account_keys transaksi
AccountNotFoundValidasi pembayar biayaAkun pembayar biaya tidak ada
ProgramAccountNotFoundPemuatan akunProgram yang dipanggil tidak ada
InsufficientFundsForFeeValidasi pembayar biayaPembayar biaya tidak dapat menutupi biaya + minimum bebas rent
InvalidAccountForFeeValidasi pembayar biayaPembayar biaya bukan akun sistem atau nonce
AlreadyProcessedCache statusTransaksi sudah diproses sebelumnya
BlockhashNotFoundPemeriksaan usiaBlockhash tidak ada dalam antrian dan bukan nonce yang valid
InstructionErrorEksekusiTerjadi error saat memproses instruksi (termasuk indeks instruksi dan InstructionError spesifik)
CallChainTooDeepPemuatan akunRantai pemanggilan loader terlalu dalam
MissingSignatureForFeeSanitasiTransaksi memerlukan biaya tetapi tidak memiliki tanda tangan
InvalidAccountIndexSanitasiTransaksi berisi referensi akun yang tidak valid
SignatureFailureSigverifyTanda tangan Ed25519 tidak terverifikasi (paket dibuang)
InvalidProgramForExecutionPemuatan akunProgram tidak dimiliki oleh loader yang valid
SanitizeFailureSanitasiTransaksi gagal melakukan sanitasi offset akun dengan benar
ClusterMaintenancePenjadwalanTransaksi saat ini dinonaktifkan karena pemeliharaan cluster
AccountBorrowOutstandingEksekusiPemrosesan transaksi meninggalkan akun dengan referensi pinjaman yang belum selesai
WouldExceedMaxBlockCostLimitPenjadwalanTransaksi akan melebihi batas biaya blok maksimum
UnsupportedVersionSanitasiVersi transaksi tidak didukung
InvalidWritableAccountPemuatan akunTransaksi memuat akun yang dapat ditulis tetapi tidak dapat ditulis
WouldExceedMaxAccountCostLimitPenjadwalanTransaksi akan melebihi batas biaya akun maksimum dalam blok
WouldExceedAccountDataBlockLimitPenjadwalanTransaksi akan melebihi batas data akun dalam blok
TooManyAccountLocksPenjadwalanTransaksi mengunci terlalu banyak akun
AddressLookupTableNotFoundPemuatan akunAkun tabel pencarian alamat tidak ada
InvalidAddressLookupTableOwnerPemuatan akunTabel pencarian alamat dimiliki oleh program yang salah
InvalidAddressLookupTableDataPemuatan akunTabel pencarian alamat berisi data yang tidak valid
InvalidAddressLookupTableIndexPemuatan akunPencarian tabel alamat menggunakan indeks yang tidak valid
InvalidRentPayingAccountPemeriksaan pasca-eksekusiAkun bertransisi dari bebas rent ke membayar rent
WouldExceedMaxVoteCostLimitPenjadwalanTransaksi akan melebihi batas biaya vote maksimum
WouldExceedAccountDataTotalLimitPenjadwalanTransaksi akan melebihi batas total data akun
DuplicateInstructionParsing compute budgetVarian instruksi compute budget duplikat dalam transaksi yang sama
InsufficientFundsForRentPemeriksaan pasca-eksekusiAkun tidak memiliki cukup lamport untuk menutupi rent untuk ukuran datanya
MaxLoadedAccountsDataSizeExceededPemuatan akunTotal data yang dimuat melebihi batas 64 MiB
InvalidLoadedAccountsDataSizeLimitParsing compute budgetSetLoadedAccountsDataSizeLimit diatur ke 0
ResanitizationNeededSanitasiTransaksi berbeda sebelum/sesudah aktivasi fitur dan memerlukan sanitasi ulang
ProgramExecutionTemporarilyRestrictedPemuatan akunEksekusi program dibatasi sementara pada akun yang direferensikan
UnbalancedTransactionPemeriksaan pasca-eksekusiTotal saldo lamport sebelum transaksi tidak sama dengan saldo setelahnya
ProgramCacheHitMaxLimitPemuatan akunCache program mencapai batas maksimum
CommitCancelledCommitCommit dibatalkan secara internal

Is this page helpful?

Dikelola oleh

© 2026 Yayasan Solana.
Semua hak dilindungi.
Terhubung