Skip to main content
Saat menerima data transaksi dari Laserstream, ada dua hal penting yang perlu diperhatikan:
  • Pesan → Apa yang ingin dilakukan pengguna (usulan yang mereka tandatangani)
  • Meta → Apa yang sebenarnya terjadi (hasil eksekusi)
Tantangannya: Data transaksi mentah hadir sebagai array byte biner seperti <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 array accountInclude membatasi hasil pada aktivitas yang berinteraksi dengan ID program Jupiter.
Konsol Anda kini menampilkan pembungkus—filters, createdAt, serta cabang transaction yang menyembunyikan dua turunan:
  • transaction.transaction.transaction → pesan yang ditandatangani
  • transaction.transaction.meta → meta eksekusi
Semua yang terlihat seperti 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 biner Uint8Array 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.
Pendekatan ini memanfaatkan pendekodean bawaan sekaligus menangani bidang biner yang memerlukan konversi manual. Struktur transaksi sudah diurai—Anda hanya perlu mengonversi bidang 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)
Struktur dua bagian ini memberikan alur lengkap: apa yang diminta pengguna dibandingkan dengan apa yang sebenarnya terjadi. Mari kita periksa setiap bagian secara mendetail.

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

Setiap instruksi berisi tiga bagian utama:
  • ID Program (programIdIndex): Menunjuk ke alamat dalam array accountKeys (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
Karena fungsi 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

Jika 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.
Transaksi v1 menyertakan anggaran komputasinya di sini, bukan dalam instruksi program ComputeBudget, sehingga array 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.priorityFee jika 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-proto 12.6.0 adalah rilis pertama yang menyertakan bidang v1, sedangkan helius-laserstream 0.8.4 (JavaScript), 0.6.3 (Rust), dan 0.2.0 (Go) adalah rilis SDK pertama yang dibuat berdasarkan versi tersebut. Versi lama menghapus transactionConfig tanpa pemberitahuan.
Lihat Dukungan transaksi v1 untuk daftar lengkap perubahan.

Cara Semua Bagian Terhubung: Alurnya

Berikut yang terjadi berdasarkan prinsip dasar:
  1. Buat tabel pencarian: accountKeys mencantumkan semua alamat yang akan digunakan transaksi ini
  2. Tetapkan aturan: header menentukan jumlah tanda tangan yang diperlukan dan akun mana yang hanya-baca
  3. Buat perintah: Setiap instruction menunjuk ke:
    • Program (melalui programIdIndex → accountKeys[index])
    • Akun yang diperlukan (melalui accounts → beberapa posisi accountKeys[index])
    • Data instruksi (dikodekan dalam data)
  4. Tambahkan otorisasi: signatures membuktikan bahwa akun yang diperlukan telah menyetujui transaksi ini
  5. Tetapkan kedaluwarsa: recentBlockhash memastikan 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/Gagal
  • err: null = berhasil
  • err: {...} = gagal dengan detail kesalahan
  • fee = lamport yang dibebankan untuk transaksi ini
Perubahan Saldo
Array saldo berkaitan dengan array 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)
Penggunaan Komputasi
Menunjukkan jumlah anggaran komputasi yang digunakan (dari jumlah yang diminta).

Detail eksekusi lanjutan

Instruksi Internal
Instruksi internal adalah instruksi tambahan yang dipanggil program selama eksekusi. Instruksi ini bukan bagian dari transaksi asli, tetapi dipicu oleh instruksi utama. Pesan Log
Pesan log memberikan jejak kronologis eksekusi program yang menunjukkan program mana yang dipanggil dan setiap pesan log khusus yang dihasilkannya. Perubahan Saldo Token
Perubahan saldo token menunjukkan status sebelum dan sesudah untuk akun token SPL, termasuk jumlah yang dapat dibaca manusia dengan penanganan desimal yang tepat.

Pola 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:
Contoh ini menunjukkan cara menggabungkan pendekodean pesan dengan analisis meta untuk mengekstrak informasi yang relevan bagi bisnis dari transaksi DeFi yang kompleks.

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 preBalances dan postBalances untuk melihat perubahan yang terjadi
  • Transaksi v1: Baca anggaran komputasi dan biaya prioritas dari transactionConfig jika tersedia; transaksi v1 tidak memiliki instruksi ComputeBudget
Kunci untuk memahami transaksi Solana adalah mengenali bahwa transaksi tersebut dirancang demi efisiensi: alih-alih mengulangi alamat, transaksi menggunakan tabel pencarian dan indeks untuk meminimalkan ukuran transaksi sekaligus memaksimalkan kepadatan informasi.