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_signaturesdi header - Semua
program_id_indexdanaccount_indicesinstruksi 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_blockhashtransaksi - 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 manamin_balanceadalah 0 untuk akun sistem ataurent.minimum_balance(NonceState::size())untuk akun nonce; jika tidakInsufficientFundsForFee - 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:
- Mengambil akun dari cache atau accounts-db
- Memperbarui status bebas sewa jika diperlukan
- Mengakumulasi ukuran data akun terhadap
loaded_accounts_data_size_limit(default 64 MiB). Setiap akun dikenakan overhead dasar sebesarTRANSACTION_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:
- Untuk setiap instruksi, runtime memanggil
prepare_next_top_level_instruction, yang membangunInstructionContext. Konteks ini berisi referensi ke akun instruksi (diselesaikan dari indeks yang dikompilasi), instruction data, dan indeks program account. - Runtime memeriksa apakah program tersebut adalah precompile (Ed25519, Secp256k1, Secp256r1). Precompile diverifikasi secara langsung tanpa memanggil BPF VM.
- Untuk semua program lainnya, runtime memanggil
process_instruction, yang memuat program dari cache dan mengeksekusinya di mesin virtual BPF. - Setelah instruksi selesai, runtime
memverifikasi
bahwa total saldo lamport di semua akun instruksi tidak berubah (pemeriksaan
UnbalancedInstruction). - 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:
| Error | Tahap | Penyebab |
|---|---|---|
AccountInUse | Penjadwalan | Akun sudah dikunci oleh transaksi lain dalam batch yang sama |
AccountLoadedTwice | Penjadwalan | Sebuah pubkey muncul dua kali dalam account_keys transaksi |
AccountNotFound | Validasi pembayar biaya | Akun pembayar biaya tidak ada |
ProgramAccountNotFound | Pemuatan akun | Program yang dipanggil tidak ada |
InsufficientFundsForFee | Validasi pembayar biaya | Pembayar biaya tidak dapat menutupi biaya + minimum bebas rent |
InvalidAccountForFee | Validasi pembayar biaya | Pembayar biaya bukan akun sistem atau nonce |
AlreadyProcessed | Cache status | Transaksi sudah diproses sebelumnya |
BlockhashNotFound | Pemeriksaan usia | Blockhash tidak ada dalam antrian dan bukan nonce yang valid |
InstructionError | Eksekusi | Terjadi error saat memproses instruksi (termasuk indeks instruksi dan InstructionError spesifik) |
CallChainTooDeep | Pemuatan akun | Rantai pemanggilan loader terlalu dalam |
MissingSignatureForFee | Sanitasi | Transaksi memerlukan biaya tetapi tidak memiliki tanda tangan |
InvalidAccountIndex | Sanitasi | Transaksi berisi referensi akun yang tidak valid |
SignatureFailure | Sigverify | Tanda tangan Ed25519 tidak terverifikasi (paket dibuang) |
InvalidProgramForExecution | Pemuatan akun | Program tidak dimiliki oleh loader yang valid |
SanitizeFailure | Sanitasi | Transaksi gagal melakukan sanitasi offset akun dengan benar |
ClusterMaintenance | Penjadwalan | Transaksi saat ini dinonaktifkan karena pemeliharaan cluster |
AccountBorrowOutstanding | Eksekusi | Pemrosesan transaksi meninggalkan akun dengan referensi pinjaman yang belum selesai |
WouldExceedMaxBlockCostLimit | Penjadwalan | Transaksi akan melebihi batas biaya blok maksimum |
UnsupportedVersion | Sanitasi | Versi transaksi tidak didukung |
InvalidWritableAccount | Pemuatan akun | Transaksi memuat akun yang dapat ditulis tetapi tidak dapat ditulis |
WouldExceedMaxAccountCostLimit | Penjadwalan | Transaksi akan melebihi batas biaya akun maksimum dalam blok |
WouldExceedAccountDataBlockLimit | Penjadwalan | Transaksi akan melebihi batas data akun dalam blok |
TooManyAccountLocks | Penjadwalan | Transaksi mengunci terlalu banyak akun |
AddressLookupTableNotFound | Pemuatan akun | Akun tabel pencarian alamat tidak ada |
InvalidAddressLookupTableOwner | Pemuatan akun | Tabel pencarian alamat dimiliki oleh program yang salah |
InvalidAddressLookupTableData | Pemuatan akun | Tabel pencarian alamat berisi data yang tidak valid |
InvalidAddressLookupTableIndex | Pemuatan akun | Pencarian tabel alamat menggunakan indeks yang tidak valid |
InvalidRentPayingAccount | Pemeriksaan pasca-eksekusi | Akun bertransisi dari bebas rent ke membayar rent |
WouldExceedMaxVoteCostLimit | Penjadwalan | Transaksi akan melebihi batas biaya vote maksimum |
WouldExceedAccountDataTotalLimit | Penjadwalan | Transaksi akan melebihi batas total data akun |
DuplicateInstruction | Parsing compute budget | Varian instruksi compute budget duplikat dalam transaksi yang sama |
InsufficientFundsForRent | Pemeriksaan pasca-eksekusi | Akun tidak memiliki cukup lamport untuk menutupi rent untuk ukuran datanya |
MaxLoadedAccountsDataSizeExceeded | Pemuatan akun | Total data yang dimuat melebihi batas 64 MiB |
InvalidLoadedAccountsDataSizeLimit | Parsing compute budget | SetLoadedAccountsDataSizeLimit diatur ke 0 |
ResanitizationNeeded | Sanitasi | Transaksi berbeda sebelum/sesudah aktivasi fitur dan memerlukan sanitasi ulang |
ProgramExecutionTemporarilyRestricted | Pemuatan akun | Eksekusi program dibatasi sementara pada akun yang direferensikan |
UnbalancedTransaction | Pemeriksaan pasca-eksekusi | Total saldo lamport sebelum transaksi tidak sama dengan saldo setelahnya |
ProgramCacheHitMaxLimit | Pemuatan akun | Cache program mencapai batas maksimum |
CommitCancelled | Commit | Commit dibatalkan secara internal |
Is this page helpful?