Skip to content

Commit 4f61230

Browse files
committed
Export the rust version to WASM + Use it in a Go library
1 parent 9f02805 commit 4f61230

File tree

9 files changed

+219
-0
lines changed

9 files changed

+219
-0
lines changed

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.PHONY: wasm
2+
wasm:
3+
cd rust && \
4+
cargo build --target wasm32-unknown-unknown --release
5+
cp rust/target/wasm32-unknown-unknown/release/evmole.wasm go/evmole.wasm

evmole.wasm

1.44 MB
Binary file not shown.

go/evmole.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package evmole
2+
3+
import (
4+
"context"
5+
_ "embed"
6+
"encoding/binary"
7+
"fmt"
8+
9+
"github.com/tetratelabs/wazero"
10+
)
11+
12+
//go:embed evmole.wasm
13+
var evmoleWASM []byte
14+
15+
// FunctionSelectors tries to extract from the given bytecode the function selectors.
16+
func FunctionSelectors(ctx context.Context, code []byte) ([][4]byte, error) {
17+
// Create a new WebAssembly runtime
18+
runtime := wazero.NewRuntime(ctx)
19+
defer func() { _ = runtime.Close(ctx) }()
20+
21+
instance, err := runtime.Instantiate(ctx, evmoleWASM)
22+
if err != nil {
23+
panic(fmt.Errorf("failed to instantiate WASM module: %w", err))
24+
}
25+
defer func() { _ = instance.Close(ctx) }()
26+
27+
gasLimit := 0
28+
29+
memory := instance.Memory()
30+
functionSelectorsFunc := instance.ExportedFunction("ext_function_selectors")
31+
32+
codeOffset := uint32(0)
33+
resultLenOffset := uint32(len(code))
34+
resultOffset := resultLenOffset + 4
35+
resultCapacity := uint32(512 * 4)
36+
37+
// Write input to memory
38+
ok := memory.Write(codeOffset, code)
39+
if !ok {
40+
return nil, fmt.Errorf("failed to write input to memory")
41+
}
42+
43+
// Call the WASM function
44+
results, err := functionSelectorsFunc.Call(ctx,
45+
uint64(codeOffset), uint64(len(code)), uint64(gasLimit),
46+
uint64(resultLenOffset), uint64(resultOffset), uint64(resultCapacity))
47+
if err != nil {
48+
return nil, fmt.Errorf("failed to call function_selectors: %w", err)
49+
}
50+
51+
if status := uint32(results[0]); status != 0 {
52+
return nil, fmt.Errorf("error: status=%d", status)
53+
}
54+
55+
// Read the actual result length
56+
rawResultLen, ok := memory.Read(resultLenOffset, 4)
57+
if !ok {
58+
return nil, fmt.Errorf("failed to read result length")
59+
}
60+
resultLen := binary.LittleEndian.Uint32(rawResultLen)
61+
62+
// Success, read the result
63+
result, ok := memory.Read(resultOffset, resultLen)
64+
if !ok {
65+
return nil, fmt.Errorf("failed to read result from memory")
66+
}
67+
68+
// Convert to [][4]byte
69+
selectors := make([][4]byte, len(result)/4)
70+
for i := 0; i < len(result); i += 4 {
71+
copy(selectors[i/4][:], result[i:i+4])
72+
}
73+
74+
return selectors, nil
75+
}

go/evmole.wasm

1.44 MB
Binary file not shown.

go/evmole_test.go

Lines changed: 98 additions & 0 deletions
Large diffs are not rendered by default.

go/go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/cdump/evmole/go
2+
3+
go 1.22.5
4+
5+
require github.com/tetratelabs/wazero v1.7.3

go/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/tetratelabs/wazero v1.7.3 h1:PBH5KVahrt3S2AHgEjKu4u+LlDbbk+nsGE3KLucy6Rw=
2+
github.com/tetratelabs/wazero v1.7.3/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=

rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ license = "MIT"
88
readme = "README.md"
99
repository = "https://github.com/cdump/evmole"
1010

11+
[lib]
12+
crate-type = ["cdylib"]
13+
1114
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1215

1316
[dependencies]

rust/src/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,34 @@ mod evm;
1414
pub mod selectors;
1515

1616
pub type Selector = [u8; 4];
17+
18+
#[no_mangle]
19+
pub extern "C" fn ext_function_selectors(
20+
code_ptr: *const u8,
21+
code_len: usize,
22+
gas_limit: u32,
23+
result_len_ptr: *mut u32,
24+
result_ptr: *mut u8,
25+
result_capacity: usize,
26+
) -> u32 {
27+
let code = unsafe { std::slice::from_raw_parts(code_ptr, code_len) };
28+
let selectors = function_selectors(code, gas_limit);
29+
30+
let flattened: Vec<u8> = selectors.into_iter().flatten().collect();
31+
let result_len = flattened.len();
32+
33+
unsafe {
34+
*result_len_ptr = result_len as u32;
35+
}
36+
37+
if result_len > result_capacity {
38+
// Buffer too small
39+
return 1;
40+
}
41+
42+
unsafe {
43+
std::ptr::copy_nonoverlapping(flattened.as_ptr(), result_ptr, result_len);
44+
}
45+
// Success
46+
0
47+
}

0 commit comments

Comments
 (0)