diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index adf5fecd..295c9e7c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,6 +65,16 @@ jobs: if: matrix.rust == 'nightly' && matrix.os != 'windows-latest' shell: bash + wasm-test: + name: Wasm tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - run: wasm-pack test --node + coverage: name: Coverage runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 262b73c8..f4caf2bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,12 @@ dependencies = [ "wyz", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "0.5.3" @@ -84,6 +90,16 @@ dependencies = [ "unreachable", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "derive_arbitrary" version = "1.1.0" @@ -151,8 +167,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -170,6 +188,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "json" version = "0.12.4" @@ -360,6 +387,7 @@ dependencies = [ "combine", "elf", "gdbstub", + "getrandom", "hash32", "json", "libc", @@ -370,6 +398,7 @@ dependencies = [ "shuttle", "test_utils", "thiserror", + "wasm-bindgen-test", "winapi", ] @@ -464,6 +493,106 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 781ce874..91dcb7ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,12 @@ winapi = { version = "0.3", features = ["memoryapi", "sysinfoapi", "winnt", "err [target.'cfg(not(windows))'.dependencies] libc = { version = "0.2", optional = true } +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2.6", features = ["js", "wasm-bindgen"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3" + [features] default = ["jit"] jit = ["libc", "winapi"] diff --git a/tests/assembler.rs b/tests/assembler.rs index 4020d6cd..1fd53fb0 100644 --- a/tests/assembler.rs +++ b/tests/assembler.rs @@ -11,6 +11,8 @@ extern crate test_utils; use solana_rbpf::{assembler::assemble, ebpf, program::BuiltinProgram, vm::TestContextObject}; use std::sync::Arc; use test_utils::{TCP_SACK_ASM, TCP_SACK_BIN}; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test as test; fn asm(src: &str) -> Result, String> { let executable = assemble::(src, Arc::new(BuiltinProgram::new_mock()))?; diff --git a/tests/disassembler.rs b/tests/disassembler.rs index 57856131..d27c3e07 100644 --- a/tests/disassembler.rs +++ b/tests/disassembler.rs @@ -14,6 +14,8 @@ use solana_rbpf::{ vm::{Config, TestContextObject}, }; use std::sync::Arc; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test as test; // Using a macro to keep actual line numbers in failure output macro_rules! disasm { diff --git a/tests/execution.rs b/tests/execution.rs index e7f77ce2..edbbce95 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -11,6 +11,8 @@ extern crate libc; extern crate solana_rbpf; extern crate test_utils; extern crate thiserror; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test as test; use byteorder::{ByteOrder, LittleEndian}; #[cfg(all(not(windows), target_arch = "x86_64"))] diff --git a/tests/exercise_instructions.rs b/tests/exercise_instructions.rs index e2fc04b8..1148d7aa 100644 --- a/tests/exercise_instructions.rs +++ b/tests/exercise_instructions.rs @@ -11,6 +11,8 @@ extern crate libc; extern crate solana_rbpf; extern crate test_utils; extern crate thiserror; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test as test; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use solana_rbpf::{ diff --git a/tests/verifier.rs b/tests/verifier.rs index 5124e8b8..a06b66e6 100644 --- a/tests/verifier.rs +++ b/tests/verifier.rs @@ -21,11 +21,14 @@ extern crate solana_rbpf; extern crate thiserror; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test as test; use solana_rbpf::{ assembler::assemble, ebpf, elf::Executable, + error::EbpfError, program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, syscalls, verifier::{RequisiteVerifier, Verifier, VerifierError}, @@ -90,7 +93,6 @@ fn test_verifier_success() { } #[test] -#[should_panic(expected = "NoProgram")] fn test_verifier_fail() { let executable = assemble::( " @@ -99,11 +101,14 @@ fn test_verifier_fail() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::NoProgram)) = + executable.verify::() + else { + panic!("Expected VerifierError::NoProgram") + }; } #[test] -#[should_panic(expected = "DivisionByZero(1)")] fn test_verifier_err_div_by_zero_imm() { let executable = assemble::( " @@ -113,11 +118,15 @@ fn test_verifier_err_div_by_zero_imm() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::DivisionByZero(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::DivisionByZero") + }; + assert_eq!(num, 1) } #[test] -#[should_panic(expected = "UnsupportedLEBEArgument(0)")] fn test_verifier_err_endian_size() { let prog = &[ 0xdc, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // @@ -131,11 +140,15 @@ fn test_verifier_err_endian_size() { FunctionRegistry::default(), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::UnsupportedLEBEArgument(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::UnsupportedLEBEArgument") + }; + assert_eq!(num, 0); } #[test] -#[should_panic(expected = "IncompleteLDDW(0)")] fn test_verifier_err_incomplete_lddw() { // Note: ubpf has test-err-incomplete-lddw2, which is the same let prog = &[ @@ -149,7 +162,12 @@ fn test_verifier_err_incomplete_lddw() { FunctionRegistry::default(), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::IncompleteLDDW(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::IncompleteLDDW") + }; + assert_eq!(num, 0); } #[test] @@ -218,7 +236,6 @@ fn test_verifier_resize_stack_ptr_success() { } #[test] -#[should_panic(expected = "JumpToMiddleOfLDDW(2, 0)")] fn test_verifier_err_jmp_lddw() { let executable = assemble::( " @@ -228,11 +245,16 @@ fn test_verifier_err_jmp_lddw() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::JumpToMiddleOfLDDW(a, b))) = + executable.verify::() + else { + panic!("Expected VerifierError::JumpToMiddleOfLDDW") + }; + assert_eq!(a, 2); + assert_eq!(b, 0); } #[test] -#[should_panic(expected = "InvalidFunction(1)")] fn test_verifier_err_call_lddw() { let executable = assemble::( " @@ -242,11 +264,15 @@ fn test_verifier_err_call_lddw() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::InvalidFunction(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::InvalidFunction"); + }; + assert_eq!(num, 1) } #[test] -#[should_panic(expected = "InvalidFunction(0)")] fn test_verifier_err_function_fallthrough() { let executable = assemble::( " @@ -256,11 +282,15 @@ fn test_verifier_err_function_fallthrough() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::InvalidFunction(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::InvalidFunction"); + }; + assert_eq!(num, 0); } #[test] -#[should_panic(expected = "JumpOutOfCode(3, 0)")] fn test_verifier_err_jmp_out() { let executable = assemble::( " @@ -269,11 +299,16 @@ fn test_verifier_err_jmp_out() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::JumpOutOfCode(a, b))) = + executable.verify::() + else { + panic!("Expected VerifierError::JumpOutOfCode"); + }; + assert_eq!(a, 3); + assert_eq!(b, 0); } #[test] -#[should_panic(expected = "JumpOutOfCode(18446744073709551615, 0)")] fn test_verifier_err_jmp_out_start() { let executable = assemble::( " @@ -282,11 +317,16 @@ fn test_verifier_err_jmp_out_start() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::JumpOutOfCode(a, b))) = + executable.verify::() + else { + panic!("Expected VerifierError::JumpOutOfCode") + }; + assert_eq!(a, usize::MAX); + assert_eq!(b, 0); } #[test] -#[should_panic(expected = "UnknownOpCode(6, 0)")] fn test_verifier_err_unknown_opcode() { let prog = &[ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @@ -299,11 +339,16 @@ fn test_verifier_err_unknown_opcode() { FunctionRegistry::default(), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::UnknownOpCode(a, b))) = + executable.verify::() + else { + panic!("Expected VerifierError::UnknownOpCode") + }; + assert_eq!(a, 6); + assert_eq!(b, 0) } #[test] -#[should_panic(expected = "InvalidFunction(1811268606)")] fn test_verifier_unknown_sycall() { let prog = &[ 0x85, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0xf5, 0x6b, // call 0x6bf5c3fe @@ -316,7 +361,12 @@ fn test_verifier_unknown_sycall() { FunctionRegistry::default(), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::InvalidFunction(idx))) = + executable.verify::() + else { + panic!("Expected InvalidFunction error") + }; + assert_eq!(idx, 1811268606); } #[test] @@ -343,7 +393,6 @@ fn test_verifier_known_syscall() { } #[test] -#[should_panic(expected = "CannotWriteR10(0)")] fn test_verifier_err_write_r10() { let executable = assemble::( " @@ -352,7 +401,12 @@ fn test_verifier_err_write_r10() { Arc::new(BuiltinProgram::new_mock()), ) .unwrap(); - executable.verify::().unwrap(); + let Err(EbpfError::VerifierError(VerifierError::CannotWriteR10(num))) = + executable.verify::() + else { + panic!("Expected VerifierError::CannotWriteR10"); + }; + assert_eq!(num, 0); } #[test]