sbpf2rv mengambil program Solana yang telah dikompil (ELF sBPF, iaitu .so yang dihasilkan oleh cargo build-sbf) dan menukarkannya kepada program Rand. Ia menulis C, dan rand-guest build mengompil C itu menjadi imej RV32IM. Imej tersebut menerbitkan lapan perkataan output yang sama seperti guest penterjemah sBPF Rand, sbpf.bin, bagi ELF dan arahan yang sama. Halaman ini menunjukkan keseluruhan laluan tersebut pada program SPL Token yang sebenar.
Apakah itu
| input | ELF sBPF v1 |
| output | crate shim C; rand-guest build menjadikannya bekas imej |
| tempat ia dijalankan | di luar rantaian, pada mesin pembangun; rantaian hanya melihat imej |
| apa yang mesti dipadankan | lapan perkataan output sbpf.bin, pada dua pita input yang sama |
| repositori | sbpf2rv/ dalam repositori circuits |
| rantaian alat yang dikunci | Rust 1.98.1, clang 23.1.1, crate cc 1.4.6 |
Program yang diterjemahkan mengekalkan ABI penterjemah. Ia membaca pita yang sama: ELF pada pita awam dan arahan bersiri (akaun, kemudian data arahan) pada pita persendirian. Ia menjalankan harness sbpf-core yang sama di sekeliling program: ia menyahkod input, memuatkan ELF, menyemak rantau akaun serta mencincang input dan output. Hanya pelaksanaan sBPF itu sendiri yang digantikan dengan kod natif. Itulah sebabnya outputnya sama dengan output penterjemah perkataan demi perkataan.
Model kepercayaan
Tiga perkara mengikat bukti bagi program yang diterjemahkan.
hcmengikat kod yang diterjemahkan. C itu dikompil ke dalam imej, makahcimej meliputinya.- Pengawal ELF mengikat
hckepada satu program. Shim memuatkan program daripada ELF pada pita, jadi tanpa semakan, satu imej boleh menjalankan ELF lain pilihan pemanggil di bawahhcyang sama. Oleh ituprogram.cyang dijana diakhiri dengan digest program termuat yang daripadanya ia diterjemahkan: teks, data baca sahaja, alamatnya dan titik masuk. Sebelum menjalankan apa-apa, shim mencincang program termuat pada pita dengan cara yang sama (Poseidon2) dan membandingkannya. Mana-mana program lain dihentikan denganBadElf, status 2, ke atas keadaan pra. Maka bukti yang disahkan terhadaphcini ialah larian program tersebut. H_PUBmengikat bait ELF. ELF dibawa pada pita awam, dan digest input awam bagi bukti itu meliputinya perkataan demi perkataan.
Sama ada hc ialah terjemahan yang setia bagi sesuatu ELF disemak melalui pembinaan semula. Jalankan sbpf2rv yang dikunci pada ELF itu, bina dengan rantaian alat yang dikunci, dan bandingkan hc. Binaan ini boleh dihasilkan semula atas sebab ini.
Rantaian tidak merekodkan ELF sumber atau cincangnya. Ia menyimpan imej dan id programnya. Pembangun yang mahu ELF itu diketahui umum menerbitkannya bersama program.
Pengawal mengikat program termuat, bukan fail. Dua ELF yang berbeza hanya di tempat yang tidak dilihat oleh pemuat (pelapik pengepala, jadual simbol) dimuatkan menjadi program yang sama dan berjalan secara serupa pada kedua-dua belah. ELF dengan satu bait .rodata yang diubah, walaupun bait yang tidak pernah dibaca oleh pemindahan, ditolak oleh terjemahan dan dijalankan oleh penterjemah.
Apa yang memerangkap dan apa yang ditolak
Tiada apa-apa yang ditolak semasa penterjemahan. ELF yang cacat ditolak dengan mesej pemuat sendiri, tetapi tiada arahan dalam ELF yang sempurna bentuknya ditolak. Pengimbas melaporkan apa yang boleh dicapai oleh sesebuah program sebagai amaran, dan program yang diterjemahkan memerangkap semasa larian tepat di tempat penterjemah akan berbuat demikian:
| amaran | apakah itu | semasa larian |
|---|---|---|
UnknownSyscall | cincang syscall yang tidak dilaksanakan oleh runtime | perangkap UnknownSyscall |
Cpi | pemanggilan merentas program (sol_invoke_signed*) | perangkap UnknownSyscall yang sama; CPI tidak dilaksanakan |
RegisterOutOfRange | register r11..r15, atau register callx melebihi r10 | perangkap BadInsn |
UnknownOpcode | opcode tanpa kelas v1, termasuk keluarga sdiv/srem khusus v2 dan hor64 | perangkap BadInsn |
JumpOutOfText | lompatan, panggilan atau lalu terus di luar teks fungsi | perangkap BadJump |
BadCallImmSrc | call imm dengan src dalam 2..=10 (hanya dalam ELF yang dibina secara manual) | perangkap BadInsn |
Penterjemah yang menolak kod yang tidak dicapai akan menolak program yang dijalankan oleh penterjemah hari ini. SPL Token ialah program sedemikian: ia memanggil sol_set_return_data dan sol_get_sysvar, yang tidak pernah dicapai oleh laluan Transfer.
Tiga percanggahan diterima. Setiap satunya hanya menyebabkan terjemahan berhenti di tempat penterjemah mungkin tidak berhenti; terjemahan tidak pernah melengkapkan larian yang dihentikan oleh penterjemah.
callxdi luar set yang diimbas memerangkapBadJump, sedangkan penterjemah mungkin menjalankan kod sebenar pada alamat itu.- Semakan bajet boleh ditangguhkan satu blok asas. Untuk memuatkan SPL Token di bawah had 65,535 perkataan, 1,505 daripada 3,546 bloknya melangkau semakan had arahan masing-masing. Jenis penghentian boleh berbeza dalam satu blok yang melintasi had itu. Status dan lapan perkataan adalah sama.
- Hanya program sumber yang dijalankan. ELF lain ditolak (pengawal, di atas).
Ed25519 dan secp256k1. Pelaksanaan perisian bagi sol_ed25519_verify dan sol_secp256k1_recover wujud dalam sbpf-rt/ tetapi tidak dipautkan. Penterjemah memerangkap pada kedua-duanya, maka demi kesamaan, terjemahan juga memerangkap. Setiap panggilan memakan kira-kira 14.3M dan 15.7M kitaran masing-masing, jauh melebihi peringkat terbesar (2²⁰). Ia memerlukan jadual koprosesor.
Angka-angkanya
Diukur pada SPL Token (guests-compiled/sbpf/programs/spl_token.so, fixture ujian penterjemah sendiri), dengan pengawal ELF disertakan.
| imej | perkataan program | had | hc |
|---|---|---|---|
| SPL Token, diterjemahkan | 65,096 | 65,535 (439 berbaki) | 8ca905ae…758b |
sbpf.bin, penterjemah | 8,317 | 65,535 | 059a7086…f476 |
| vektor | status | arahan sBPF | kitaran diterjemahkan | kitaran sbpf.bin | peringkat (kedua-duanya) |
|---|---|---|---|---|---|
Transfer 250 | 1 | 143 | 765,851 | 694,498 | 20 |
Transfer melebihi baki | 0 | 133 | 748,836 | 679,814 | 20 |
MintTo 250 | 1 | 120 | 708,648 | 634,423 | 20 |
MintTo oleh pihak berkuasa yang salah | 0 | 134 | 696,694 | 627,241 | 20 |
Burn 250 | 1 | 131 | 710,245 | 637,038 | 20 |
Burn melebihi baki | 0 | 121 | 695,434 | 624,781 | 20 |
Transfer dengan dua akaun | 0 | 69 | 645,015 | 569,656 | 20 |
| terlalu banyak akaun (harness menolak) | 2 | 0 | 303,933 | 304,616 | 20 |
Ke mana perginya kitaran pada Transfer:
| peringkat | diterjemahkan | sbpf.bin |
|---|---|---|
| baca kedua-dua pita | 302,881 | 302,880 |
| muatkan ELF | 177,012 | 173,859 |
| semak rantau akaun | 103,829 | 103,824 |
| sifarkan tindanan dan heap sBPF | 49,181 | 49,181 |
| cincang output dan input, perkataan awam, glue | 51,091 | 42,723 |
| pengawal ELF | 72,949 | — |
| program sBPF itu sendiri | 8,908 | 22,031 |
| jumlah | 765,851 | 694,498 |
Pelaksanaan program yang diterjemahkan itu sendiri kira-kira 2.4 hingga 2.5 kali lebih murah bagi setiap arahan sBPF (kira-kira 62 kitaran berbanding 154). Tetapi kira-kira 98% daripada setiap larian ialah harness tetap, dan pengawal menambah 73k kitaran. Maka bagi SPL Token, imej yang diterjemahkan lebih mahal sebanyak 69k hingga 75k kitaran, dan kedua-duanya kekal pada peringkat 20.
Penterjemahan hanya berbaloi untuk program yang berat dari segi pengiraan. Pada kira-kira 90 kitaran yang dijimatkan bagi setiap arahan, panggilan yang melaksanakan 10,000 arahan sBPF menjimatkan kira-kira 0.9M kitaran. SPL Token melaksanakan 120 hingga 143.
Panduan langkah demi langkah: SPL Token, diterjemahkan dan dipadankan
Setiap arahan dijalankan dari akar checkout circuits pada 7ef3220, dengan rantaian alat daripada Deploy a Rust program dan clang 23.1.1 daripada Deploy a RISC-V program. Output yang panjang dipotong di tempat bertanda ….
0. Bina alat
(cd sbpf2rv && cargo +1.98.1 build --release)
(cd rand-guest && cargo +1.98.1 build --release)
1. Terjemah
--out mestilah direktori di dalam checkout circuits.
$ sbpf2rv/target/release/sbpf2rv guests-compiled/sbpf/programs/spl_token.so --out sbpf2rv/target/spl-token --name spl-token
entry pc 225: 30 function(s), 3546 block(s), 12061 instruction(s), 30 callx target(s), 0 refusal(s), 4 warning(s)
fn 225: 2065 block(s)
… (30 functions in all)
warning: UnknownSyscall { pc: 7803, hash: 2720453611 }
warning: UnknownSyscall { pc: 9530, hash: 2720453611 }
warning: UnknownSyscall { pc: 8698, hash: 2720453611 }
warning: UnknownSyscall { pc: 11547, hash: 331461893 }
wrote sbpf2rv/target/spl-token/program.c (521757 bytes of C) and the spl-token shim crate: rand-guest build sbpf2rv/target/spl-token
0 refusal(s). Empat amaran itu ialah syscall sebenar yang tidak pernah dicapai oleh Transfer: cincang 2720453611 ialah sol_set_return_data (tiga tapak panggilan) dan 331461893 ialah sol_get_sysvar.
2. Bina imej
Imej ini melebihi had lalai 4,096 perkataan, maka berikan --max-words 65535.
$ rand-guest/target/release/rand-guest build sbpf2rv/target/spl-token --max-words 65535
…
65096 words against a cap of 65535 (fits); 2 ecall(s) with a non-static a7
OK
wrote sbpf2rv/target/spl-token/image.bin and its .sha256 (65096 words, hc 8ca905ae3c62f503de7de86829040f323e098b53dba5fffe09b42f1aad16758b, program id 65d234ce9ca4d082f487c038abfa76e67f41a0d91e10b9ac388f1e1541d59184)
$ rand-guest/target/release/rand-guest info sbpf2rv/target/spl-token/image.bin
form: image container
text 64819 words at 0x10000; data 102 words (101 non-zero) at 0x4f4cc; prologue 277 words; program 65096 words from base_pc 0xfbac
hc 8ca905ae3c62f503de7de86829040f323e098b53dba5fffe09b42f1aad16758b
program id 65d234ce9ca4d082f487c038abfa76e67f41a0d91e10b9ac388f1e1541d59184
65096 words against a cap of 4096: does not fit
Sesiapa yang menjalankan kedua-dua langkah ini dengan rantaian alat yang sama akan memperoleh hc ini.
3. Jalankan kedua-duanya, dan bandingkan
Transfer sebanyak 250 mengambil dua senarai perkataan, yang dibina oleh tests/parity.rs daripada pengekodan panggilan penterjemah sendiri: 27,151 perkataan awam (ELF, dikodkan sebagai perkataan) dan 10,458 perkataan persendirian (akaun, kemudian diskriminan Transfer dan jumlah). rand-guest run menerimanya sebagai --public dan --input. Dipendekkan kepada beberapa perkataan pertama bagi setiap senarai:
$ rand-guest run sbpf2rv/target/spl-token/image.bin \
--public 108600 1179403647 65794 0 0 17235971 1 2088 … (27 151 words)
--input 41825 4 0 65791 0 50529027 50529027 50529027 … (10 458 words)
out[0] = 1
out[1] = 2892832079
out[2] = 376091303
out[3] = 1311040261
out[4] = 2015764099
out[5] = 3682593600
out[6] = 3311553006
out[7] = 141115266
cycles 765851
tier 20
Dua senarai yang sama terhadap guest penterjemah:
$ rand-guest run guests-compiled/bin/sbpf.bin \
--public 108600 1179403647 65794 0 0 17235971 1 2088 … (27 151 words)
--input 41825 4 0 65791 0 50529027 50529027 50529027 … (10 458 words)
out[0] = 1
out[1] = 2892832079
out[2] = 376091303
out[3] = 1311040261
out[4] = 2015764099
out[5] = 3682593600
out[6] = 3311553006
out[7] = 141115266
cycles 694498
tier 20
Kesemua lapan perkataan adalah serupa. out[0] = 1 ialah status (berjaya). out[1..8] ialah digest yang ditakrifkan oleh ABI penterjemah ke atas input dan output.
4. Semak kesemua lapan vektor dalam satu arahan
Ujian kesamaan membina imej yang diterjemahkan, menjalankan setiap vektor melalui rand-guest run pada kedua-dua imej, dan gagal pada sebarang perbezaan dalam lapan perkataan itu:
$ cd sbpf2rv && cargo +1.98.1 test --test parity the_spl_token -- --nocapture
…
translated SPL Token: 65096 program words (cap 65 535), hc 8ca905ae3c62f503de7de86829040f323e098b53dba5fffe09b42f1aad16758b
transfer 250: Ok(0), status 1; cycles translated 765851, interpreter guest 694498
transfer too much: Ok(1), status 0; cycles translated 748836, interpreter guest 679814
MintTo 250: Ok(0), status 1; cycles translated 708648, interpreter guest 634423
MintTo 250 signed by someone else: Ok(4), status 0; cycles translated 696694, interpreter guest 627241
Burn 250: Ok(0), status 1; cycles translated 710245, interpreter guest 637038
Burn 1 000 001 (balance 1 000 000): Ok(1), status 0; cycles translated 695434, interpreter guest 624781
transfer with two accounts: Ok(47244640256), status 0; cycles translated 645015, interpreter guest 569656
an account count above MAX_ACCOUNTS: Err(BadElf), status 2; cycles translated 303933, interpreter guest 304616
…
test the_spl_token_transfer_translates_and_matches_the_interpreter_word_for_word ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 27.84s
5. Deploy
rand program deploy sbpf2rv/target/spl-token/image.bin --public spl_token.so
Imej ini membaca ELF daripada pita awam, jadi ELF ialah input awam program yang ditetapkan semasa penempatan. --public menerima fail .so itu sendiri; dompet mengekod perkataannya kepada 27,151 perkataan yang sama seperti langkah 4.
Ini memerlukan rantaian yang genesisnya menetapkan max_program_words sekurang-kurangnya 65,096 dan max_program_public_words sekurang-kurangnya 27,151. Chain 12 mengehadkan penempatan kepada 4,096 perkataan dan tidak menerima input awam, maka dompet menolak imej ini di sana sebelum sebarang pembuktian. Chain 13, rantaian v0.4, menetapkan 65,535 dan 32,768, dan setiap rantaian sejak itu mengekalkan kedua-dua nilai tersebut. Chain 20, rantaian yang sedang beroperasi (genesis 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135), turut mengekalkan had blok dan had sampul panggilan Chain 13, dan mengurangkan separuh had bukti kepada 4 MiB (4,194,304 bait, sejak chain 17; chain 13 hingga 16 menetapkan 8 MiB). Had saiz bukan lagi satu-satunya syarat. Genesis Chain 20 menetapkan hardening_v6, dan di bawahnya penempatan dengan perkataan program yang lebih banyak daripada yang dapat dimuatkan oleh satu panggilan pada had panggilan tier-14 adalah tidak sah (ProgramUncallable): paling banyak 8,180 perkataan tanpa input awam, dan lebih sedikit jika disertai input awam. Imej ini ialah 65,096 perkataan bersama input awam 27,151 perkataan, maka chain 20 menolak penempatan tersebut, dan akan menolak panggilan juga: setiap vektor SPL dijalankan pada tier 20, melebihi had panggilan tier-14 (Had). Pengagregatan blok dimatikan pada chain 20 (genesisnya tiada bahagian aggregation); nod bootstrapnya disenaraikan dalam Menjalankan validator. Yuran penempatan mengira perkataan awam bersama perkataan kod: 0.001 + 0.0001 × (65,096 + 27,151) = 9.2257 RAND, iaitu yuran yang dibayar oleh penempatan chain 13 di bawah.
Penempatan ini dijalankan pada chain 13 pada 2026-09-19, ketika chain 13 ialah rantaian yang sedang beroperasi (profil FRI pengeluaran, genesis 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3), daripada dompet genesis shielded-1. Setiap rantaian sejak itu (14 hingga 19) dibina sebagai rantaian baharu tanpa program chain 13, dan imej ini belum ditempatkan semula pada mana-mana daripadanya, maka transaksi dan ketinggian di bawah adalah milik chain 13 dan tidak lagi dapat dicari di penjelajah. ID program ialah cincangan base_pc, perkataan dan perkataan awam sahaja, maka imej dan ELF yang sama mendapat ID yang sama pada mana-mana rantaian yang menerima penempatan tersebut. Output dompet, dengan baris kemajuannya dipendekkan (…):
$ rand program deploy <image.bin> --public spl_token.so
program id: 740236918310f8e52bb0c1ef49b2b0e0c018762e289666660685b0694c8dd00a (65096 words, hc ae05a98c03f5623c68e87dde320f0429538b093efeffa5db1a2fb4098b7516ad, public input 27151 words, digest ec57b10ed6f3a3d5fe87ec072f691322ad747377ba2f0a1788bcfe3e7334d67e)
…
proved in 94.3s: tier 14, 1418406 bytes
submitted deploy 626fc9387ecc1f6b39f44184807303ac2843029d8fb8e28338bf186445927530
…
| ID program | 740236918310f8e52bb0c1ef49b2b0e0c018762e289666660685b0694c8dd00a |
| imej | 65,096 perkataan; hc 8ca905ae… dalam ejaan rand-guest, ae05a98c… dalam ejaan dompet |
| input awam | 27,151 perkataan (ELF), digest ec57b10ed6f3a3d5fe87ec072f691322ad747377ba2f0a1788bcfe3e7334d67e |
| bundel yuran (bundel 2-masuk-2-keluar chain 13) | tier 14, 1,418,406 bait, dibuktikan dalam 94.3 s |
| tx penempatan (chain 13) | 626fc9387ecc1f6b39f44184807303ac2843029d8fb8e28338bf186445927530 |
| ditambatkan pada ketinggian (chain 13) | 400 |
| yuran | 9.2257 RAND |
Sejak chain 14, bundel pembayaran ialah satu bundel aset tersembunyi 4-masuk-4-keluar yang dibawa oleh setiap transaksi, dibuktikan terhadap pengikatan transaksi. Ia masih tier 14: kira-kira 100 s dan kira-kira 1.42 MB pada profil pengeluaran pada chain 14 dan 15. Sejak chain 17, sesebuah bundel turut membawa bukti auth tier-10 (pengesahan terpisah), maka pada chain 18 dan 19 bundel yuran sesebuah transaksi ialah kira-kira 1.49 MB bukti bundel dan kira-kira 1.37 MB bukti auth.
ID program mengikat ELF, maka ia berbeza daripada ID yang dicetak oleh rand-guest info untuk imej kosong. Panggil ID yang dicetak oleh deploy.
Had
- Tiada panggilan kepada program ini yang telah dibuktikan, ia tidak ditempatkan pada chain 20, dan chain 20 menolak penempatan serta panggilan. Penempatan di atas dibuat pada chain 13. Di bawah
hardening_v6chain 20, penempatan dengan perkataan yang lebih banyak daripada yang dapat dimuatkan oleh panggilan tier-14 adalah tidak sah (ProgramUncallable; paling banyak 8,180 perkataan), dan imej ini ialah 65,096. Bahagian input akan muat: ELF ialah input awam penempatan, yang diambil sendiri olehrand call, dan 10,458 perkataan persendirian muat dalam had input 16,071, yang dikekalkan oleh chain 20. Tetapi setiap vektor SPL ialah tier 20, dan sejak fullnode v0.5.6 (2026-09-25) nod menolak sebarang bukti panggilan di atas tier 14 (CallTierTooHigh), sebelum ia membina kunci pengesah. Semakan yang sama turut mengehadkan jadual cincangan yang boleh diisytiharkan oleh sesuatu panggilan: 2¹³ baris SHA-256 (128 pemampatan) dan 2¹² baris Keccak (128 pilih atur). Panggilan tier-20 hanya boleh dibuktikan di luar rantaian, dan belum ada bukti tier-20 (perkara seterusnya). - Belum ada bukti dibuat pada tier 20. Satu bukti tier-20 dimatikan pada komputer riba 48 GB pada kira-kira 31 GB, dan dimatikan oleh OOM pada droplet 64 GB pada 65.1 GB selepas 10 m 41 s. Berdasarkan ekstrapolasi skala tier-16/18 yang diukur (memori kira-kira ×3.9, masa kira-kira ×4.1 bagi setiap +2 tier), tier 20 memerlukan kira-kira 330 GB dan kira-kira 3.6 j, iaitu lebih daripada droplet memori terbesar DigitalOcean (m-32vcpu-256gb, 256 GB). Prover berjalan dengan satu thread: kotak 16-vCPU berada pada 99% satu teras. Lihat memori pembuktian.
- Tiada CPI. Pemanggilan antara program akan trap.
- sBPF v1 sahaja. Opcode khusus v2 akan trap.
- Syscall Ed25519 dan secp256k1 trap sehingga ia mempunyai jadual koprosesor.
- Rantaian merekodkan ELF hanya sebagai input awam. Penempatan dengan
--publicmenyimpan perkataan ELF dan digestnya, danrand_getProgramPublicmenyajikannya. Rantaian tidak merekodkan bagaimana imej dibina daripadanya: terbitkan input binaan supaya pihak lain dapat membina semulahc.