From 4aa1c44f07e3b35d4acd7bfd3d443be6906e7a8b Mon Sep 17 00:00:00 2001 From: Sourabh Niyogi Date: Tue, 24 Sep 2024 14:37:24 -0700 Subject: [PATCH 1/3] jam-service-fib Rather than hand assemble https://gist.github.com/sourabhniyogi/5e44600216af117169384a51ab389c8d we would like to demonstrate how a JAM service written in Rust using #[polkavm_import(index = 0)] can be compiled into JAM-ready PVM and include "ecalli {0..22}" calls; By "JAM-ready" we mean the "0/5/10/15" entry points for is_authorized/refine/accumulate/transfer. TODO: (1) Get toolchain instructions sufficient to get above Rust compiled into PVM with (a) ecalli 16/17/3 in place of import/export (refine) + write (accumulate) (b) entrypoints 0/5/10/15 going into is_authorized/refine/accumulate/on_transfer (2) get polkatool to output .pvm byte code with (1b) streamlined --- guest-programs/jam-service-fib/Cargo.toml | 18 ++++ guest-programs/jam-service-fib/src/main.rs | 114 +++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 guest-programs/jam-service-fib/Cargo.toml create mode 100644 guest-programs/jam-service-fib/src/main.rs diff --git a/guest-programs/jam-service-fib/Cargo.toml b/guest-programs/jam-service-fib/Cargo.toml new file mode 100644 index 00000000..fc37acf1 --- /dev/null +++ b/guest-programs/jam-service-fib/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "jam-service-fib" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +name = "fib" +path = "src/main.rs" +crate-type = ["cdylib"] + +[[bin]] +name = "jam-service-fib" +path = "src/main.rs" + +[dependencies] +polkavm-derive = { path = "../../crates/polkavm-derive" } +simplealloc = { path = "../../crates/simplealloc" } diff --git a/guest-programs/jam-service-fib/src/main.rs b/guest-programs/jam-service-fib/src/main.rs new file mode 100644 index 00000000..f8422f00 --- /dev/null +++ b/guest-programs/jam-service-fib/src/main.rs @@ -0,0 +1,114 @@ +#![no_std] +#![no_main] + +#[polkavm_derive::polkavm_import] +extern "C" { + #[polkavm_import(index = 0)] + pub fn gas() -> i64; + #[polkavm_import(index = 1)] + pub fn lookup(service: u32, hash_ptr: *const u8, out: *mut u8, out_len: u32) -> u32; + #[polkavm_import(index = 2)] + pub fn read(service: u32, key_ptr: *const u8, key_len: u32, out: *mut u8, out_len: u32) -> u32; + #[polkavm_import(index = 3)] + pub fn write(key_ptr: *const u8, key_len: u32, value: *const u8, value_len: u32) -> u32; + #[polkavm_import(index = 4)] + pub fn info(service: u32, out: *mut u8) -> u32; + #[polkavm_import(index = 5)] + pub fn empower(m: u32, a: u32, v: u32, o: u32, n: u32) -> u32; + #[polkavm_import(index = 6)] + pub fn assign(c: u32, out: *mut u8) -> u32; + #[polkavm_import(index = 7)] + pub fn designate(out: *mut u8) -> u32; + #[polkavm_import(index = 8)] + pub fn checkpoint() -> u64; + #[polkavm_import(index = 9)] + pub fn new(service: u32, hash_ptr: *const u8, out: *mut u8, out_len: u32) -> u32; + #[polkavm_import(index = 10)] + pub fn upgrade(out: *const u8, g: u64, m: u64) -> u32; + #[polkavm_import(index = 11)] + pub fn transfer(d: u32, a: u64, g: u64, out: *mut u8) -> u32; + #[polkavm_import(index = 12)] + pub fn quit(d: u32, a: u64, g: u64, out: *mut u8) -> u32; + #[polkavm_import(index = 13)] + pub fn solicit(hash_ptr: *const u8, z: u32) -> u32; + #[polkavm_import(index = 14)] + pub fn forget(hash_ptr: *const u8, z: u32) -> u32; + #[polkavm_import(index = 15)] + pub fn historical_lookup(service: u32, hash_ptr: *const u8, out: *mut u8, out_len: u32) -> u32; + #[polkavm_import(index = 16)] + pub fn import(import_index: u32, out: *mut u8, out_len: u32) -> u32; + #[polkavm_import(index = 17)] + pub fn export(out: *const u8, out_len: u32) -> u32; + #[polkavm_import(index = 18)] + pub fn machine(out: *const u8, out_len: u32) -> u32; + #[polkavm_import(index = 19)] + pub fn peek(out: *const u8, out_len: u32, i: u32) -> u32; + #[polkavm_import(index = 20)] + pub fn poke(n: u32, a: u32, b: u32, l: u32) -> u32; + #[polkavm_import(index = 21)] + pub fn invoke(n: u32, out: *mut u8) -> u32; + #[polkavm_import(index = 22)] + pub fn expunge(n: u32) -> u32; + #[polkavm_import(index = 99)] + pub fn blake2b(data: *const u8, data_len: u32, hash_ptr: *mut u8) -> u32; + #[polkavm_import(index = 100)] + pub fn blake2s(data: *const u8, data_len: u32, hash_ptr: *mut u8) -> u32; + #[polkavm_import(index = 101)] + pub fn ecrecover(h: *const u8, v: *const u8, r: *const u8, s: *const u8, out: *mut u8) -> u32; + #[polkavm_import(index = 102)] + pub fn sha2_256(data: *const u8, data_len: u32, hash_ptr: *mut u8) -> u32; +} + +fn is_authorized() -> bool { + true +} + +fn refine() -> [u8; 12] { + let mut buffer = [0u8; 12]; + let result = unsafe { import(0, buffer.as_mut_ptr(), buffer.len() as u32) }; + + if result == 0 { + let n = u32::from_le_bytes(buffer[0..4].try_into().unwrap()); + let fib_n = u32::from_le_bytes(buffer[4..8].try_into().unwrap()); + let fib_n_minus_1 = u32::from_le_bytes(buffer[8..12].try_into().unwrap()); + + let new_fib_n = fib_n + fib_n_minus_1; + + let new_buffer = [ + (n + 1).to_le_bytes(), + new_fib_n.to_le_bytes(), + fib_n.to_le_bytes(), + ] + .concat(); + + buffer.copy_from_slice(&new_buffer); + } else { + buffer = [1u8, 0, 0, 0, 1u8, 0, 0, 0, 0, 0, 0, 0]; + } + + unsafe { + export(buffer.as_mut_ptr(), buffer.len() as u32); + } + + buffer +} + +fn accumulate() -> [u8; 12] { + let mut buffer = [0u8; 12]; + let key = [0u8; 1]; + + unsafe { + write(key.as_ptr(), 1, buffer.as_ptr(), buffer.len() as u32); + } + + buffer +} + +fn on_transfer() -> bool { + true +} + +// TODO: (1) Get toolchain instructions sufficient to get above Rust compiled into PVM with +// (a) ecalli 16/17/3 in place of import/export (refine) + write (accumulate) +// (b) entrypoints 0/5/10/15 going into is_authorized/refine/accumulate/on_transfer +// (2) get polkatool to output .pvm byte code with (1b) streamlined From 706c34a27efd189f3e36ea5d2014508a865f69e4 Mon Sep 17 00:00:00 2001 From: Sourabh Niyogi Date: Wed, 25 Sep 2024 14:57:42 +0000 Subject: [PATCH 2/3] polkatool jam-service [compiledcode] Sample execution: (after cargo build of jam-service-fib) ./target/release/polkatool jam-service ~/polkavm/guest-programs/jam-service-fib/target/riscv32ema-unknown-none-elf/release/jam-service-fib --- guest-programs/Cargo.lock | 8 +++ guest-programs/Cargo.toml | 1 + guest-programs/jam-service-fib/Cargo.toml | 9 ++-- guest-programs/jam-service-fib/src/main.rs | 54 +++++++++++++-------- rust-toolchain.toml | 5 +- tools/polkatool/jam_service.pvm | Bin 0 -> 1350 bytes tools/polkatool/src/main.rs | 34 +++++++++++++ 7 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 tools/polkatool/jam_service.pvm diff --git a/guest-programs/Cargo.lock b/guest-programs/Cargo.lock index a9c231c2..22285c09 100644 --- a/guest-programs/Cargo.lock +++ b/guest-programs/Cargo.lock @@ -59,6 +59,14 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "jam-service-fib" +version = "0.1.0" +dependencies = [ + "polkavm-derive", + "simplealloc", +] + [[package]] name = "mos6502" version = "0.1.0" diff --git a/guest-programs/Cargo.toml b/guest-programs/Cargo.toml index d3f90c43..a8eac1fc 100644 --- a/guest-programs/Cargo.toml +++ b/guest-programs/Cargo.toml @@ -14,6 +14,7 @@ resolver = "2" members = [ # Examples: "example-hello-world", + "jam-service-fib", # Benchmarks: "bench-minimal", diff --git a/guest-programs/jam-service-fib/Cargo.toml b/guest-programs/jam-service-fib/Cargo.toml index fc37acf1..3c2c1d5d 100644 --- a/guest-programs/jam-service-fib/Cargo.toml +++ b/guest-programs/jam-service-fib/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["edition2024"] + [package] name = "jam-service-fib" version = "0.1.0" @@ -7,12 +9,9 @@ publish = false [lib] name = "fib" path = "src/main.rs" -crate-type = ["cdylib"] - -[[bin]] -name = "jam-service-fib" -path = "src/main.rs" +crate-type = ["staticlib", "rlib"] [dependencies] polkavm-derive = { path = "../../crates/polkavm-derive" } simplealloc = { path = "../../crates/simplealloc" } + diff --git a/guest-programs/jam-service-fib/src/main.rs b/guest-programs/jam-service-fib/src/main.rs index f8422f00..7efc7b7c 100644 --- a/guest-programs/jam-service-fib/src/main.rs +++ b/guest-programs/jam-service-fib/src/main.rs @@ -1,6 +1,21 @@ #![no_std] #![no_main] +extern crate alloc; + +use alloc::vec::Vec; +use simplealloc::SimpleAlloc; + +#[global_allocator] +static ALLOCATOR: SimpleAlloc<4096> = SimpleAlloc::new(); + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + core::arch::asm!("unimp", options(noreturn)); + } +} + #[polkavm_derive::polkavm_import] extern "C" { #[polkavm_import(index = 0)] @@ -59,11 +74,13 @@ extern "C" { pub fn sha2_256(data: *const u8, data_len: u32, hash_ptr: *mut u8) -> u32; } -fn is_authorized() -> bool { - true +#[polkavm_derive::polkavm_export] +extern "C" fn is_authorized_ext() -> u32 { + 0 } -fn refine() -> [u8; 12] { +#[polkavm_derive::polkavm_export] +extern "C" fn refine_ext() -> u32 { let mut buffer = [0u8; 12]; let result = unsafe { import(0, buffer.as_mut_ptr(), buffer.len() as u32) }; @@ -73,13 +90,11 @@ fn refine() -> [u8; 12] { let fib_n_minus_1 = u32::from_le_bytes(buffer[8..12].try_into().unwrap()); let new_fib_n = fib_n + fib_n_minus_1; - - let new_buffer = [ - (n + 1).to_le_bytes(), - new_fib_n.to_le_bytes(), - fib_n.to_le_bytes(), - ] - .concat(); + let new_buffer: Vec = [(n + 1).to_le_bytes(), new_fib_n.to_le_bytes(), fib_n.to_le_bytes()] + .iter() + .flat_map(|array| array.iter()) + .copied() + .collect(); buffer.copy_from_slice(&new_buffer); } else { @@ -90,25 +105,22 @@ fn refine() -> [u8; 12] { export(buffer.as_mut_ptr(), buffer.len() as u32); } - buffer + 0 } -fn accumulate() -> [u8; 12] { - let mut buffer = [0u8; 12]; +#[polkavm_derive::polkavm_export] +extern "C" fn accumulate_ext() -> u32 { + let buffer = [0u8; 12]; let key = [0u8; 1]; unsafe { write(key.as_ptr(), 1, buffer.as_ptr(), buffer.len() as u32); } - buffer + 0 } -fn on_transfer() -> bool { - true +#[polkavm_derive::polkavm_export] +extern "C" fn on_transfer_ext() -> u32 { + 0 } - -// TODO: (1) Get toolchain instructions sufficient to get above Rust compiled into PVM with -// (a) ecalli 16/17/3 in place of import/export (refine) + write (accumulate) -// (b) entrypoints 0/5/10/15 going into is_authorized/refine/accumulate/on_transfer -// (2) get polkatool to output .pvm byte code with (1b) streamlined diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7897a24d..dd500d2b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,5 @@ [toolchain] -channel = "1.75.0" +channel = "rve-nightly" +components = ["rustc", "cargo", "rust-std"] +targets = ["riscv32imc-unknown-none-elf"] + diff --git a/tools/polkatool/jam_service.pvm b/tools/polkatool/jam_service.pvm new file mode 100644 index 0000000000000000000000000000000000000000..50d8a89f1a3165f1b9f278f0314d90a48a194ec0 GIT binary patch literal 1350 zcmZuwU1%It6u#%4J3DuF?z;DGW_D*c>n7Pw(xi=DNvamwha#zDHW0%2lUDIXD%c7> z2sNAJMcQC~+6OyUjcFeIN!t7rgoq$X9wa^((WlY}5z!Z`lxi(`$WutXlVVGuFx)wu zbI&>7{myq1bmX%MvI@Vz2K@%_pm7HXG5(2RoJ^iq*%4n_HB~1b+EMfTbAlS z6OM1v0U|NS(PNkw=p-aPjZhRF?L;<%M@NZ-3{y~ZMy*nta@H*cL#2rg9Avfvk24dG zGkl2~lO*NF1~b995ZkeFj_iWtF*qv*2bcMq$;$F;^cvK!f&aY_Ya%V4hw0MlUpU36 zDy{x*bUZrgiHDO)50acYPRBF}|6>ulH}=P96!wGkz;z(2yBF&SRllNaM7M}pk55{a z@mIq$Fkrm{ZKoOzXL-5djh)BF8ceeZPQ-+ylmyH`K11ZN!5=1uKaVU89= zcq$>;E8E~fj+s2KqlCQcjb_uPM;S>_wS|)GVo@L)!7W18qsp(-#Kd5}MR^3>Lzq37 zQeH|qx-Ru3v-Askr83Pz3_$y#puB?07gV93>W#Mmat?SNn>y6=6`=`yb@kHW(Q4nWM{&6swqbG|T{MI`^&lr_e+99l8g&I~~JNm?i}8<_wj z5BXL*K?!&tw(x!~-=iWa42C9n~%ES*fp>Rb;KT`_ArV`3%u3`HKr_je&=7z%l7@`ZX*=vJdp~foO!!6 zoOUL(xTj0kHt@2dImx)_Ra#T>2)KtJdyuN5dVnN(Z@PMnf9uUlDV|a+r6-l9xwIBS zm}g1Ri*cUTo^x;HjEMVLcToy-Ic8aVUY=|n$}AwiYMV(nyb!*v?C<0rS_aK$WoeVo zacADjOmAh*BL6XI(!&Qtk97_+9bRT+3y!sRW;#9Er5E+N&SvA8r-|q@@N2rlv@d+U zvUuAlhC^wq$*3FUeBd+@6`T4t5SO}@@EpP*?ue9BVxdAUdzfQ~_BY7?XYmqS)B zrmQ1PBYvR9yVTnI-DQ=j`fa{*BAUJ82a*5m@yKs`>KN~d{MnXjb;)lFqG~zF%y&n# zeHlNx5`@h`G}BVncY~;l_xQo3eHXP|4XQ0c6h)VOKM1?yVEpN9|6*VJ57%d+nVAn} c{Ml&VEq^?^QH`T7Ecwl|;mbjEQkUHR57YSlw*UYD literal 0 HcmV?d00001 diff --git a/tools/polkatool/src/main.rs b/tools/polkatool/src/main.rs index 4f7fb3c9..d494d685 100644 --- a/tools/polkatool/src/main.rs +++ b/tools/polkatool/src/main.rs @@ -62,6 +62,12 @@ enum Args { /// The input files. inputs: Vec, }, + + /// Builds JAM-ready polkavm file + JAMService { + /// The input file. + input: PathBuf, + }, } macro_rules! bail { @@ -90,6 +96,7 @@ fn main() { } => main_disassemble(input, format, display_gas, show_raw_bytes, output), Args::Assemble { input, output } => main_assemble(input, output), Args::Stats { inputs } => main_stats(inputs), + Args::JAMService { input } => main_jam_service(input), }; if let Err(error) = result { @@ -233,3 +240,30 @@ fn main_assemble(input_path: PathBuf, output_path: PathBuf) -> Result<(), String Ok(()) } + +fn main_jam_service(input_path: PathBuf) -> Result<(), String> { + if !input_path.exists() { + bail!("File does not exist: {input_path:?}"); + } + + use std::fs; + + let mut config = polkavm_linker::Config::default(); + config.set_strip(true); + config.set_dispatch_table(vec![ + b"is_authorized_ext".into(), + b"refine_ext".into(), + b"accumulate_ext".into(), + b"on_transfer_ext".into(), + ]); + + let elf = fs::read(input_path).map_err(|err| format!("Failed to read ELF file: {}", err))?; + let raw_blob = + polkavm_linker::program_from_elf(config, elf.as_ref()).map_err(|err| format!("Failed to create program from ELF: {}", err))?; + let parts = + polkavm_linker::ProgramParts::from_bytes(raw_blob.into()).map_err(|err| format!("Failed to parse program parts: {}", err))?; + + fs::write("jam_service.pvm", &parts.code_and_jump_table).map_err(|err| format!("Failed to write jam_service.pvm: {}", err))?; + + Ok(()) +} From 044f91a1ee344cdcac52c7603aa2e9472daa531b Mon Sep 17 00:00:00 2001 From: Sourabh Niyogi Date: Thu, 26 Sep 2024 10:11:52 +0000 Subject: [PATCH 3/3] enable polkatool to dump disassemble-able raw bytes, add doc --- guest-programs/jam-service-fib/README.md | 291 ++++++++++++++++++ guest-programs/jam-service-fib/blob.pvm | Bin 0 -> 1513 bytes .../jam-service-fib}/jam_service.pvm | Bin guest-programs/jam-service-fib/src/main.rs | 8 +- tools/polkatool/src/main.rs | 45 ++- 5 files changed, 328 insertions(+), 16 deletions(-) create mode 100644 guest-programs/jam-service-fib/README.md create mode 100644 guest-programs/jam-service-fib/blob.pvm rename {tools/polkatool => guest-programs/jam-service-fib}/jam_service.pvm (100%) diff --git a/guest-programs/jam-service-fib/README.md b/guest-programs/jam-service-fib/README.md new file mode 100644 index 00000000..b33b4bfb --- /dev/null +++ b/guest-programs/jam-service-fib/README.md @@ -0,0 +1,291 @@ + +# JAM Service: Fib + +This is a test Rust-based JAM service named "jam-service-fib" with refine/accumulate/on_transfer/is_authorized entrypoints: + +* `refine` (entry point 5) imports a 12-byte segment with [n, fib(n), f(n-1)] and exports the next segment in the same way [n+1, fib(n+1), fib(n)] +* `accumulate` (entry point 10) reads a 12-byte segment and writes to service storage key "0" +* `is_authorized` (entry point 0) and `on_transfer` (entry point 15) are just stubs right now + +It uses 3 polka_import macros for import/export/write but attempts to set up all 23 or so and a few others. These are just stubs at present, have not been checked or tested. + + +## Setup toolchain + +Install this [rustc-rv32e-toolchain](https://github.com/paritytech/rustc-rv32e-toolchain/) -- we found the release build sufficient. + +After installation you should have `~/.rustup/toolchains/rve-nightly/`. Then + +``` +export RUSTUP_TOOLCHAIN=rve-nightly +``` + +will make this accessible + +## Build Service + +``` +cargo build --release --target-dir=./target +``` + +This will generate a 1MB file in `target` here: + +``` +# ls -l target/riscv32ema-unknown-none-elf/release/jam-service-fib +-rwxr-xr-x 2 root root 1067744 Sep 26 09:37 target/riscv32ema-unknown-none-elf/release/jam-service-fib +``` + +## Generate PVM Byte code with `polkatool` + +You can then use `polkatool` to generate "JAM-ready" PVM byte code and raw code blobs with: +``` +# cargo run -p polkatool jam-service guest-programs/jam-service-fib/target/riscv32ema-unknown-none-elf/release/jam-service-fib -o guest-programs/jam-service-fib/jam_service.pvm -d guest-programs/jam-service-fib/blob.pvm +warning: /root/go/src/github.com/colorfulnotion/polkavm/Cargo.toml: unused manifest key: workspace.lints.rust.unexpected_cfgs.check-cfg + Finished dev [unoptimized + debuginfo] target(s) in 0.08s + Running `target/debug/polkatool jam-service guest-programs/jam-service-fib/target/riscv32ema-unknown-none-elf/release/jam-service-fib -o guest-programs/jam-service-fib/jam_service.pvm -d guest-programs/jam-service-fib/blob.pvm` +Writing JAM-ready code blob "guest-programs/jam-service-fib/jam_service.pvm" +Writing raw code "guest-programs/jam-service-fib/blob.pvm" +``` + +## Disassemble + +Given the above `blob.pvm`, you can disassemble it with `polkatool`: + +``` +# cargo run -p polkatool disassemble guest-programs/jam-service-fib/blob.pvm --show-raw-bytes +// RO data = 0/0 bytes +// RW data = 0/4128 bytes +// Stack size = 4096 bytes + +// Instructions = 418 +// Code size = 1185 bytes + + : @0 + 0: 05 ee 01 00 00 jump @52 // is_authorized + : @1 + 5: 05 ed 01 00 00 jump @53 // refine + : @2 + 10: 05 af 03 00 00 jump @78 // accumulate + : @3 + 15: 05 d2 03 jump @79 // on_transfer + : @4 + + + : @52 [export #0: 'is_authorized'] + 494: 04 07 a0 = 0x0 + 496: 13 00 ret + + + : @53 [export #1: 'refine'] + 498: 02 11 c0 sp = sp - 64 + 501: 03 10 3c u32 [sp + 60] = ra + 504: 03 15 38 u32 [sp + 56] = s0 + 507: 03 16 34 u32 [sp + 52] = s1 + 510: 0d 11 18 u32 [sp + 24] = 0 + 513: 0d 11 14 u32 [sp + 20] = 0 + 516: 0d 11 10 u32 [sp + 16] = 0 + 519: 02 18 10 a1 = sp + 0x10 + 522: 04 09 0c a2 = 0xc + 525: 04 07 a0 = 0x0 + 527: 4e 10 ecalli 16 // 'import' + 529: 11 fallthrough + : @54 + 530: 07 07 1a jump @56 if a0 == 0 + : @55 + 533: 0d 11 10 01 u32 [sp + 16] = 1 + 537: 0d 11 14 01 u32 [sp + 20] = 1 + 541: 1a 11 18 u8 [sp + 24] = 0 + 544: 1a 11 19 u8 [sp + 25] = 0 + 547: 1a 11 1a u8 [sp + 26] = 0 + 550: 1a 11 1b u8 [sp + 27] = 0 + 553: 05 6e 01 jump @75 + : @56 + 556: 01 17 14 a0 = u32 [sp + 20] + 559: 01 18 18 a1 = u32 [sp + 24] + 562: 01 19 10 a2 = u32 [sp + 16] + 565: 08 78 0a a3 = a1 + a0 + 568: 02 98 01 a1 = a2 + 0x1 + 571: 03 18 1c u32 [sp + 28] = a1 + 574: 02 14 20 t2 = sp + 0x20 + 577: 03 1a 20 u32 [sp + 32] = a3 + 580: 03 17 24 u32 [sp + 36] = a0 + 583: 02 10 1d ra = sp + 0x1d + 586: 04 07 00 10 a0 = 0x1000 + 590: 04 03 10 00 02 t1 = 0x20010 + 595: 04 09 10 10 02 a2 = 0x21010 + 600: 11 fallthrough + : @57 + 601: 01 9b a4 = u32 [a2] + 603: 02 ba 08 a3 = a4 + 0x8 + 606: 2f ba 87 01 jump @80 if a3 u 0x0 + 729: 02 88 ff a1 = a1 - 1 + 732: 0c 78 09 a2 = a1 | a0 + 735: 02 17 28 a0 = sp + 0x28 + 738: 52 58 a1 = s0 + 740: 03 14 0c u32 [sp + 12] = t2 + 743: 03 10 08 u32 [sp + 8] = ra + 746: 03 1c 04 u32 [sp + 4] = a5 + 749: 06 10 08 78 fe ra = 8, jump @37 + : @67 [@dyn 4] + 754: 01 1c 04 a5 = u32 [sp + 4] + 757: 04 0b 03 a4 = 0x3 + 760: 02 1a 1c a3 = sp + 0x1c + 763: 01 10 08 ra = u32 [sp + 8] + 766: 01 14 0c t2 = u32 [sp + 12] + 769: 01 17 2c a0 = u32 [sp + 44] + 772: 05 aa jump @62 + : @68 + 774: 0f 15 0c a9 00 jump @76 if s0 != 12 + : @69 + 779: 01 17 2c a0 = u32 [sp + 44] + 782: 0b 78 09 a1 = u8 [a0 + 9] + 785: 0b 79 08 a2 = u8 [a0 + 8] + 788: 0b 7a 0a a3 = u8 [a0 + 10] + 791: 0b 7b 0b a4 = u8 [a0 + 11] + 794: 09 88 08 a1 = a1 << 8 + 797: 0c 98 08 a1 = a1 | a2 + 800: 09 aa 10 a3 = a3 << 16 + 803: 09 bb 18 a4 = a4 << 24 + 806: 0c ab 0a a3 = a4 | a3 + 809: 0c 8a 08 a1 = a3 | a1 + 812: 03 18 18 u32 [sp + 24] = a1 + 815: 0b 78 05 a1 = u8 [a0 + 5] + 818: 0b 79 04 a2 = u8 [a0 + 4] + 821: 0b 7a 06 a3 = u8 [a0 + 6] + 824: 0b 7b 07 a4 = u8 [a0 + 7] + 827: 09 88 08 a1 = a1 << 8 + 830: 0c 98 08 a1 = a1 | a2 + 833: 09 aa 10 a3 = a3 << 16 + 836: 09 bb 18 a4 = a4 << 24 + 839: 0c ab 0a a3 = a4 | a3 + 842: 0c 8a 08 a1 = a3 | a1 + 845: 03 18 14 u32 [sp + 20] = a1 + 848: 0b 78 01 a1 = u8 [a0 + 1] + 851: 0b 79 a2 = u8 [a0] + 853: 09 88 08 a1 = a1 << 8 + 856: 0b 7a 02 a3 = u8 [a0 + 2] + 859: 0b 7b 03 a4 = u8 [a0 + 3] + 862: 0c 98 09 a2 = a1 | a2 + 865: 01 18 28 a1 = u32 [sp + 40] + 868: 09 aa 10 a3 = a3 << 16 + 871: 09 bb 18 a4 = a4 << 24 + 874: 0c ab 0a a3 = a4 | a3 + 877: 0c 9a 09 a2 = a3 | a2 + 880: 02 8b ff ef a4 = a1 + 0xffffefff + 884: 03 19 10 u32 [sp + 16] = a2 + 887: 2c 2b 00 f0 20 jump @75 if a4 =^v`|@7KuO?%7$BV`HqEH~8AB>8VNr@% zTDxptgrY5l2N+Rm;lZC4`a@!ZG11ZogAZc#iSS^I(U^#aph)__Qv=>95rW~x$;_EE z=iKkyZ@zPG$L8k|fQC-wPawKIf&O!8>ihpbro!}A%H5^%zBl$)x=Yp2YOCm>Te0$i z9i2Vhd-hk#wbHIbvyn<^ce$(7|7Emu=gyveJ+F6mm->G-_jm2+u5@-C*j=hb-rg9& zM?M-tGw>tK;xEW8qTK?;>95dyN|d=uu>6e(hu9WL3cp8ZAEJC@9Km_2>yrp3m~Q-l zV4UhmP%03nLPqa?90mFA^lh zh(k%56DuO{UIJO(+JZy_ICuaFNKgq?Yrx1gOY4dup_Ut(B?qY~!C_P){7YHzY7WFyHI5DwTDB-QTOI)vpbPYf>9^+m8P6eK1Ekd&p_{`;+I_B)L*${?;^S8?g5aEANkh@dau z1qV`8XK9s1=q+a;8P^?5Q3T65BG5b+2_g@67LpE@Zk-Y)B=Z#!Yl*#@Bv;0y6O)#z ziyc7?^#|=j>Ut(5pyH5`PDZ9PGLw-Dv@U>@1�!KzU_48+M|D^D_cl5(+la$Y~R z?*q~CG%HLGz@q~8La5;NPlEbH>d`R(g%&KOp zA*@BrKK*eEEVBycL6tFU*z6;G*Z`;LVT}<3AG`NANsE?c=yo15cmfFtBi4kO>x)}M zYPiqlF3gfM5~l=Zyj`l95^KR;4at>Qu2T&}(fi$1ZTwT6yqIJ$Nn@&0ah!^)LGaTw z%G*hZQ?qB?Z#hN$0qQmpoY;&cX-it{YN{nB2|I7L(_`H3J0%O2X*6$2JP8r5bw~)=lBv;F~3xp zx~XOTTHIKq6_)cl|FDF` u32 { +extern "C" fn is_authorized() -> u32 { 0 } #[polkavm_derive::polkavm_export] -extern "C" fn refine_ext() -> u32 { +extern "C" fn refine() -> u32 { let mut buffer = [0u8; 12]; let result = unsafe { import(0, buffer.as_mut_ptr(), buffer.len() as u32) }; @@ -109,7 +109,7 @@ extern "C" fn refine_ext() -> u32 { } #[polkavm_derive::polkavm_export] -extern "C" fn accumulate_ext() -> u32 { +extern "C" fn accumulate() -> u32 { let buffer = [0u8; 12]; let key = [0u8; 1]; @@ -121,6 +121,6 @@ extern "C" fn accumulate_ext() -> u32 { } #[polkavm_derive::polkavm_export] -extern "C" fn on_transfer_ext() -> u32 { +extern "C" fn on_transfer() -> u32 { 0 } diff --git a/tools/polkatool/src/main.rs b/tools/polkatool/src/main.rs index d494d685..d91a5b95 100644 --- a/tools/polkatool/src/main.rs +++ b/tools/polkatool/src/main.rs @@ -65,8 +65,16 @@ enum Args { /// Builds JAM-ready polkavm file JAMService { - /// The input file. + /// The input file (compiled Rust) input: PathBuf, + + /// The output file (JAM-Ready) + #[clap(short = 'o', long)] + output: Option, + + /// The raw code blob (can be disassembled with cargo run -p polkatool disassemble --show-raw-bytes {..}) + #[clap(short = 'd', long)] + dump: Option, }, } @@ -96,7 +104,7 @@ fn main() { } => main_disassemble(input, format, display_gas, show_raw_bytes, output), Args::Assemble { input, output } => main_assemble(input, output), Args::Stats { inputs } => main_stats(inputs), - Args::JAMService { input } => main_jam_service(input), + Args::JAMService { input, output, dump } => main_jam_service(input, output, dump), }; if let Err(error) = result { @@ -241,9 +249,9 @@ fn main_assemble(input_path: PathBuf, output_path: PathBuf) -> Result<(), String Ok(()) } -fn main_jam_service(input_path: PathBuf) -> Result<(), String> { +fn main_jam_service(input_path: PathBuf, output_path: Option, dump_path: Option) -> Result<(), String> { if !input_path.exists() { - bail!("File does not exist: {input_path:?}"); + return Err(format!("File does not exist: {:?}", input_path)); } use std::fs; @@ -251,19 +259,32 @@ fn main_jam_service(input_path: PathBuf) -> Result<(), String> { let mut config = polkavm_linker::Config::default(); config.set_strip(true); config.set_dispatch_table(vec![ - b"is_authorized_ext".into(), - b"refine_ext".into(), - b"accumulate_ext".into(), - b"on_transfer_ext".into(), + b"is_authorized".into(), + b"refine".into(), + b"accumulate".into(), + b"on_transfer".into(), ]); - let elf = fs::read(input_path).map_err(|err| format!("Failed to read ELF file: {}", err))?; + let elf = fs::read(&input_path).map_err(|err| format!("Failed to read ELF file: {}", err))?; let raw_blob = polkavm_linker::program_from_elf(config, elf.as_ref()).map_err(|err| format!("Failed to create program from ELF: {}", err))?; - let parts = - polkavm_linker::ProgramParts::from_bytes(raw_blob.into()).map_err(|err| format!("Failed to parse program parts: {}", err))?; + let parts = polkavm_linker::ProgramParts::from_bytes(raw_blob.clone().into()) + .map_err(|err| format!("Failed to parse program parts: {}", err))?; - fs::write("jam_service.pvm", &parts.code_and_jump_table).map_err(|err| format!("Failed to write jam_service.pvm: {}", err))?; + match output_path { + Some(output_path) => { + println!("Writing JAM-ready code blob {:?}", output_path); + fs::write(&output_path, &parts.code_and_jump_table).map_err(|err| format!("Failed to write output: {}", err))?; + } + None => {} + } + match dump_path { + Some(dump_path) => { + println!("Writing raw code {:?}", dump_path); + fs::write(dump_path, &raw_blob).unwrap(); + } + None => {} + } Ok(()) }