- Pesan → Apa yang ingin dilakukan pengguna (usulan yang mereka tandatangani)
- Meta → Apa yang sebenarnya terjadi (hasil eksekusi)
<Buffer 00 bf a0 e8...>, bukan alamat dan tanda tangan yang dapat dibaca.
Panduan ini menunjukkan cara: Mendekode data biner tersebut menjadi format yang dapat dibaca manusia, mengekstrak informasi penting, dan memahami keseluruhan alur transaksi dari usulan hingga eksekusi.
Stream langsung, tanpa pendekodean
Jalankan klien minimal di bawah ini. Flag filter menghapus transaksi voting dan transaksi yang gagal, sedangkan arrayaccountInclude membatasi hasil pada aktivitas yang berinteraksi dengan ID program Jupiter.
filters, createdAt, serta cabang transaction yang menyembunyikan dua turunan:
transaction.transaction.transaction→ pesan yang ditandatanganitransaction.transaction.meta→ meta eksekusi
Uint8Array tetap tidak dapat dibaca untuk sementara.
Saat menjalankan skrip dengan fungsi pendekodean, Anda akan melihat struktur bertingkat yang sebenarnya dengan alamat yang dapat dibaca:
Mendekode data biner
Mengapa perlu mendekode? Data mentah Laserstream berisi tanda tangan, kunci akun, dan hash sebagai objek binerUint8Array yang tidak dapat dibaca. Anda perlu mengonversinya menjadi string base58 agar dapat memahami transaksi.
Solusinya: Laserstream menggunakan Yellowstone gRPC, yang menyediakan utilitas pendekodean bawaan. Alih-alih menulis pendekode terpisah untuk setiap jenis bidang, kami menggunakan satu fungsi rekursif yang mengonversi semua data biner ke format yang dapat dibaca manusia.
Memahami struktur transaksi
Setelah data yang didekode dapat dilihat, mari kita pelajari dua bagian utama dari setiap pembaruan transaksi Laserstream. Ingat dari contoh awal bahwa setiap transaksi berisi dua objek utama:- Pesan (Usulan) →
transaction.transaction.transaction→ pesan yang ditandatangani (usulan pengguna) - Meta (Eksekusi) →
transaction.transaction.meta→ metadata eksekusi (respons validator)
Usulan: semua yang ada di dalam pesan
Pengguna membuat pesan yang menentukan apa, siapa, dan sampai kapan. Berikut cara mendekode setiap bagiannya:Header Transaksi
numRequiredSignatures memberi tahu validator jumlah tanda tangan yang harus diverifikasi, sedangkan dua nilai numReadonly* menandai akun yang dapat diperlakukan runtime sebagai hanya-baca sehingga memungkinkan eksekusi paralel.
Kamus Kunci Akun
accountKeys adalah daftar biasa berisi kunci publik yang berfungsi sebagai tabel pencarian. Setiap bilangan bulat berikutnya dalam transaksi—programIdIndex dan setiap elemen dalam array accounts milik instruksi—merujuk kembali ke daftar ini berdasarkan indeks sehingga menghemat lebih dari satu kilobyte per pesan.
Perlindungan terhadap Pemutaran Ulang
recentBlockhash kedaluwarsa setelah keluar dari 150 hash blok terakhir, kira-kira sembilan puluh detik di mainnet.
Instruksi: Perintah Sebenarnya
- ID Program (
programIdIndex): Menunjuk ke alamat dalam arrayaccountKeys(misalnya, indeks 10 =ComputeBudget111111111111111111111111111111) - Akun (
accounts): String yang dikodekan dengan base58 dan merepresentasikan indeks akun yang digunakan instruksi ini - Data (
data): Data instruksi sebenarnya yang dikodekan dengan base58
convertBuffers, akun muncul sebagai base58, tetapi sebenarnya berisi indeks akun (misalnya, "3vtmrQMafzDoG2CBz1iqgXPTnC" didekode menjadi indeks [21, 19, 12, 17, 2, 6, 1, 22])
Desain ini berarti bahwa alih-alih mengulangi alamat lengkap berukuran 32 byte, setiap instruksi cukup merujuk posisi dalam tabel pencarian.
Tanda Tangan: Bukti Otorisasi
signatures berisi tanda tangan kriptografis yang membuktikan bahwa akun yang diperlukan telah mengotorisasi transaksi ini. Jumlah tanda tangan harus sesuai dengan header.numRequiredSignatures.
Pencarian Tabel Alamat
versioned adalah true, addressTableLookups akan muncul bersama tabel on-chain dan dua daftar indeks. Tabel pencarian meningkatkan batas maksimum jumlah alamat menjadi puluhan sekaligus menjaga paket tetap di bawah MTU 1.232 byte.
Transaksi v1: Anggaran Komputasi dalam Header
Transaksi v1 (SIMD-0385, Agave 4.2) menambahkan satu bidang lagi ke pesan:transactionConfig.
instructions milik transaksi v1 tidak pernah memuat entri ComputeBudget111111111111111111111111111111. priorityFee adalah total biaya dalam lamport untuk seluruh transaksi, bukan mikro-lamport per unit komputasi. Bidang null berarti pengirim tidak menetapkannya. Pesan lama dan v0 tidak memiliki transactionConfig, sehingga keberadaannya mengidentifikasi transaksi v1.
Dua hal yang perlu diperiksa dalam pendekode Anda:
- Ekstraksi biaya prioritas. Baca
transactionConfig.priorityFeejika tersedia, dan gunakan pemindaian instruksi ComputeBudget sebagai cadangan hanya untuk transaksi lama dan v0. Kode yang hanya memindai instruksi akan membaca setiap transaksi v1 seolah-olah membayar biaya prioritas nol. - Versi proto.
yellowstone-grpc-proto12.6.0 adalah rilis pertama yang menyertakan bidang v1, sedangkanhelius-laserstream0.8.4 (JavaScript), 0.6.3 (Rust), dan 0.2.0 (Go) adalah rilis SDK pertama yang dibuat berdasarkan versi tersebut. Versi lama menghapustransactionConfigtanpa pemberitahuan.
Cara Semua Bagian Terhubung: Alurnya
Berikut yang terjadi berdasarkan prinsip dasar:- Buat tabel pencarian:
accountKeysmencantumkan semua alamat yang akan digunakan transaksi ini - Tetapkan aturan:
headermenentukan jumlah tanda tangan yang diperlukan dan akun mana yang hanya-baca - Buat perintah: Setiap
instructionmenunjuk ke:- Program (melalui
programIdIndex→accountKeys[index]) - Akun yang diperlukan (melalui
accounts→ beberapa posisiaccountKeys[index]) - Data instruksi (dikodekan dalam
data)
- Program (melalui
- Tambahkan otorisasi:
signaturesmembuktikan bahwa akun yang diperlukan telah menyetujui transaksi ini - Tetapkan kedaluwarsa:
recentBlockhashmemastikan transaksi ini tidak dapat diputar ulang nanti
Eksekusi: semua yang ada di dalam meta
Pesan menunjukkan apa yang ingin dilakukan pengguna, sedangkan meta menunjukkan apa yang sebenarnya terjadi saat validator mengeksekusi transaksi.Informasi eksekusi dasar
Berhasil/Gagalerr: null= berhasilerr: {...}= gagal dengan detail kesalahanfee= lamport yang dibebankan untuk transaksi ini
accountKeys berdasarkan indeks:
- Akun 0: Kehilangan 15000 lamport (pembayaran biaya)
- Akun 1: Mendapatkan 1461600 lamport (akun baru dibuat)
- Akun 3: Mendapatkan 2001231920 lamport (akun program)
Detail eksekusi lanjutan
Instruksi InternalPola pendekodean praktis
Berikut beberapa pola umum untuk mengekstrak informasi berguna dari transaksi yang telah didekode:Contoh lengkap: pendekode swap Jupiter
Berikut contoh lengkap yang mendekode transaksi swap Jupiter dan mengekstrak informasi penting:Poin-poin penting
- Struktur dua bagian: Setiap transaksi memiliki pesan (apa yang diminta) dan meta (apa yang sebenarnya terjadi)
- Pendekodean biner: Gunakan
bs58.encode()untuk mengonversi bidang biner menjadi string base58 yang dapat dibaca - Pencarian kunci akun: Instruksi merujuk akun berdasarkan indeks dalam array
accountKeys - Pelacakan saldo: Bandingkan
preBalancesdanpostBalancesuntuk melihat perubahan yang terjadi - Transaksi v1: Baca anggaran komputasi dan biaya prioritas dari
transactionConfigjika tersedia; transaksi v1 tidak memiliki instruksi ComputeBudget