Skip to content

Commit b572d52

Browse files
committed
wasm wip
1 parent 3ff32a6 commit b572d52

File tree

8 files changed

+140
-42
lines changed

8 files changed

+140
-42
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pk = Application.fetch_env!(:ama, :trainer_pk)
4141
sk = Application.fetch_env!(:ama, :trainer_sk)
4242
Testnet.deploy "/home/user/project/node/contract_samples/assemblyscript/counter.wasm"
4343
Testnet.call sk, pk, "get", []
44+
Testnet.call sk, pk, "increment", ["2"]
4445
```
4546

4647
### AutoUpdates + Running as a systemd service

contract_samples/assemblyscript/0_counter.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@ import { b, b58 } from "./sdk";
33

44
export function get(): void {
55
sdk.log(`get called`)
6+
if (sdk.kv_exists(b("the_counter"))) {
7+
sdk.log("exists")
8+
}
69
let cur_counter = sdk.kv_get_or<i64>(b("the_counter"), 0)
7-
assert(cur_counter > 10, "counter is over 10")
10+
sdk.kv_put(b("the_counter"), b("1"))
11+
//let new_counter = sdk.kv_increment(b("the_counter"), "1")
12+
assert(cur_counter < 10, "counter is over 10")
813
sdk.ret(cur_counter)
914
}
1015

11-
function loop(num: i32): void {
12-
while(1) {
13-
num = num + 1;
14-
}
15-
}
16-
1716
export function increment(amount_ptr: i32): void {
18-
// let amount = sdk.memory_read_string(amount_ptr);
19-
// let new_counter = sdk.kv_increment("the_counter", amount);
20-
// sdk.return_value(new_counter);
17+
let amount = sdk.memory_read_string(amount_ptr)
18+
let new_counter = sdk.kv_increment(b("the_counter"), amount)
19+
sdk.ret(new_counter)
2120
}

contract_samples/assemblyscript/sdk.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,20 @@ export function ret<T>(retv: T): void {
236236
}
237237
}
238238

239+
@external("env", "import_kv_put")
240+
declare function import_kv_put(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32): i32;
241+
export function kv_put<T>(key: T, val: T): void {
242+
if (isString<T>()) {
243+
let bkey = String.UTF8.encode(key, false);
244+
let bval = String.UTF8.encode(val, false);
245+
import_kv_put(changetype<i32>(bkey), bkey.byteLength, changetype<i32>(bval), bval.byteLength);
246+
} else if (key instanceof Uint8Array) {
247+
import_kv_put(changetype<i32>(key.dataStart), key.byteLength, changetype<i32>(val.dataStart), val.byteLength);
248+
} else {
249+
abort("kv_put_invalid_type")
250+
}
251+
}
252+
239253
@external("env", "import_kv_increment")
240254
declare function import_kv_increment(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32): i32;
241255
export function kv_increment<T>(key: T, val: string): string {
@@ -253,10 +267,16 @@ export function kv_increment<T>(key: T, val: string): string {
253267
}
254268
}
255269

270+
@external("env", "import_kv_exists")
271+
declare function import_kv_exists(ptr: i32, len: i32): i32;
272+
export function kv_exists(key: Uint8Array): bool {
273+
const result = import_kv_exists(changetype<i32>(key.dataStart), key.byteLength);
274+
return result == 1
275+
}
276+
256277
@external("env", "import_kv_get")
257278
declare function import_kv_get(ptr: i32, len: i32): i32;
258279
function __kv_get<T>(ptr: i32, len: i32): T {
259-
260280
const termPtr = import_kv_get(ptr, len);
261281
const size = load<i32>(termPtr);
262282
const dataPtr = termPtr + 4;

ex/native/rdb/src/atoms.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,6 @@ rustler::atoms! {
9090
txid,
9191
success,
9292
exec_used,
93+
result,
9394
logs,
9495
}

ex/native/rdb/src/consensus/bic/protocol.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ pub const COST_PER_DB_READ_BYTE: i128 = 50;
2020
pub const COST_PER_DB_WRITE_BASE: i128 = 25_000;
2121
pub const COST_PER_DB_WRITE_BYTE: i128 = 250;
2222

23+
/*
24+
pub const COST_PER_DB_READ_BASE: i128 = 5_000 * 10;
25+
pub const COST_PER_DB_READ_BYTE: i128 = 50 * 10;
26+
pub const COST_PER_DB_WRITE_BASE: i128 = 25_000 * 10;
27+
pub const COST_PER_DB_WRITE_BYTE: i128 = 250 * 10;
28+
*/
29+
2330
pub const COST_PER_DEPLOY: i128 = AMA_1_CENT; //cost to deploy contract
2431
pub const COST_PER_SOL: i128 = AMA_1_CENT; //cost to submit_sol
2532
pub const COST_PER_NEW_LEAF_MERKLE: i128 = COST_PER_BYTE_STATE * 128; //cost to grow the merkle tree
2633

2734
pub const LOG_MSG_SIZE: usize = 4096; //max log line length
2835
pub const LOG_TOTAL_SIZE: usize = 16384; //max log total size
2936
pub const LOG_TOTAL_ELEMENTS: usize = 32; //max elements in list
30-
//pub const WASM_MAX_PTR_LEN: usize = 1048576; //largest term passable from inside WASM to HOST
31-
pub const WASM_MAX_PTR_LEN: usize = 32768; //dont smash passed first page
37+
pub const WASM_MAX_PTR_LEN: usize = 1048576; //largest term passable from inside WASM to HOST
38+
//pub const WASM_MAX_PTR_LEN: usize = 32768; //dont smash passed first page
3239
pub const WASM_MAX_PANIC_MSG_SIZE: usize = 128;
3340

3441
pub const MAX_DB_KEY_SIZE: usize = 512;
@@ -44,7 +51,7 @@ pub const WASM_MAX_IMPORTS: u32 = 50;
4451
pub struct ExecutionReceipt {
4552
pub txid: Vec<u8>,
4653
pub success: bool,
47-
pub error: Vec<u8>,
54+
pub result: Vec<u8>,
4855
pub exec_used: Vec<u8>,
4956
pub logs: Vec<Vec<u8>>,
5057
}

ex/native/rdb/src/consensus/bic/wasm.rs

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ fn import_log_implementation(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i3
6060
let applyenv = unsafe { data.applyenv_ptr.as_mut() };
6161
let len = len as usize;
6262

63+
if len <= 0 {
64+
panic_any("exec_ptr_term_too_short")
65+
}
6366
if len > protocol::WASM_MAX_PTR_LEN {
6467
panic_any("exec_ptr_term_too_long")
6568
}
@@ -106,6 +109,56 @@ fn build_prefixed_key(applyenv: &mut ApplyEnv, view: &MemoryView, ptr: i32, len:
106109
crate::bcat(&[&b"account:"[..], &applyenv.caller_env.account_current, &b":storage:"[..], &key])
107110
}
108111

112+
fn import_storage_kv_put_implementation(mut env: FunctionEnvMut<HostEnv>, key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> Result<i32, RuntimeError> {
113+
let (data, mut store) = env.data_and_store_mut();
114+
let instance = data.instance.clone().unwrap_or_else(|| panic_any("exec_instance_not_injected"));
115+
let applyenv = unsafe { data.applyenv_ptr.as_mut() };
116+
117+
if key_len as usize > protocol::WASM_MAX_PTR_LEN {
118+
panic_any("exec_ptr_term_too_long")
119+
}
120+
if val_len as usize > protocol::WASM_MAX_PTR_LEN {
121+
panic_any("exec_ptr_term_too_long")
122+
}
123+
124+
let view = data.memory.clone().view(&store);
125+
let key = build_prefixed_key(applyenv, &view, key_ptr, key_len);
126+
let mut value = vec![0u8; val_len as usize];
127+
view.read(val_ptr as u64, &mut value).unwrap_or_else(|_| panic_any("exec_log_invalid_ptr"));
128+
129+
kv_put(applyenv, &key, &value);
130+
Ok(1)
131+
}
132+
133+
fn import_storage_kv_increment_implementation(mut env: FunctionEnvMut<HostEnv>, key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> Result<i32, RuntimeError> {
134+
let (data, mut store) = env.data_and_store_mut();
135+
let instance = data.instance.clone().unwrap_or_else(|| panic_any("exec_instance_not_injected"));
136+
let applyenv = unsafe { data.applyenv_ptr.as_mut() };
137+
138+
if key_len as usize > protocol::WASM_MAX_PTR_LEN {
139+
panic_any("exec_ptr_term_too_long")
140+
}
141+
if val_len as usize > protocol::WASM_MAX_PTR_LEN {
142+
panic_any("exec_ptr_term_too_long")
143+
}
144+
145+
let view = data.memory.clone().view(&store);
146+
let key = build_prefixed_key(applyenv, &view, key_ptr, key_len);
147+
let mut value = vec![0u8; val_len as usize];
148+
view.read(val_ptr as u64, &mut value).unwrap_or_else(|_| panic_any("exec_log_invalid_ptr"));
149+
150+
let value_int128 = std::str::from_utf8(&value).ok().and_then(|s| s.parse::<i128>().ok()).unwrap_or_else(|| panic_any("invalid_integer"));
151+
let new_value = kv_increment(applyenv, &key, value_int128).to_string();
152+
let new_value = new_value.as_bytes();
153+
154+
view.write(10_000, &new_value.len().to_le_bytes()).unwrap_or_else(|_| panic_any("exec_memwrite"));
155+
view.write(10_004, &new_value).unwrap_or_else(|_| panic_any("exec_memwrite"));
156+
//For C / ZIG
157+
view.write(10_004 + new_value.len() as u64, &[0]).unwrap_or_else(|_| panic_any("exec_memwrite"));
158+
159+
Ok(10_000)
160+
}
161+
109162
fn import_storage_kv_get_implementation(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i32) -> Result<i32, RuntimeError> {
110163
let (data, mut store) = env.data_and_store_mut();
111164
let instance = data.instance.clone().unwrap_or_else(|| panic_any("exec_instance_not_injected"));
@@ -124,12 +177,34 @@ fn import_storage_kv_get_implementation(mut env: FunctionEnvMut<HostEnv>, ptr: i
124177
Some(value) => {
125178
view.write(10_000, &value.len().to_le_bytes()).unwrap_or_else(|_| panic_any("exec_memwrite"));
126179
view.write(10_004, &value).unwrap_or_else(|_| panic_any("exec_memwrite"));
180+
// For C / ZIG
181+
view.write(10_004 + value.len() as u64, &[0]).unwrap_or_else(|_| panic_any("exec_memwrite"));
127182
}
128183
}
129184
set_remaining_points(&mut store, &instance, applyenv.exec_left.max(0) as u64);
130185
Ok(10_000)
131186
}
132187

188+
fn import_storage_kv_exists_implementation(mut env: FunctionEnvMut<HostEnv>, ptr: i32, len: i32) -> Result<i32, RuntimeError> {
189+
let (data, mut store) = env.data_and_store_mut();
190+
let instance = data.instance.clone().unwrap_or_else(|| panic_any("exec_instance_not_injected"));
191+
let applyenv = unsafe { data.applyenv_ptr.as_mut() };
192+
193+
if len as usize > protocol::WASM_MAX_PTR_LEN {
194+
panic_any("exec_ptr_term_too_long")
195+
}
196+
197+
let view = data.memory.clone().view(&store);
198+
let key = build_prefixed_key(applyenv, &view, ptr, len);
199+
200+
let result = kv_exists(applyenv, &key);
201+
set_remaining_points(&mut store, &instance, applyenv.exec_left.max(0) as u64);
202+
match result {
203+
true => Ok(1),
204+
false => Ok(0)
205+
}
206+
}
207+
133208
//AssemblyScript specific
134209
fn as_read_string(view: &MemoryView, ptr: i32) -> String {
135210
if ptr == 0 { return "null".to_string(); }
@@ -329,24 +404,24 @@ pub fn setup_wasm_instance(env: &mut ApplyEnv, module: &Module, store: &mut Stor
329404
// Setup Memory
330405
let memory = Memory::new(store, MemoryType::new(Pages(2), Some(Pages(30)), false)).unwrap_or_else(|_| panic_any("exec_memory_alloc"));
331406

332-
let mut wasm_arg_ptrs = Vec::new();
407+
let mut wasm_arg_ptrs: Vec<Value> = Vec::new();
333408
{
334409
let view = memory.view(store);
335410
inject_env_data(&view, env);
336411
let mut current_offset: u64 = 10_000;
337412
for arg_bytes in function_args {
413+
// Write the length
414+
let len = arg_bytes.len() as i32;
415+
view.write(current_offset, &len.to_le_bytes()).unwrap_or_else(|_| panic_any("exec_arg_len_write"));
338416
// Write the bytes
339-
view.write(current_offset, arg_bytes).unwrap_or_else(|_| panic_any("exec_arg_write"));
340-
417+
view.write(current_offset + 4, arg_bytes).unwrap_or_else(|_| panic_any("exec_arg_write"));
341418
// NULL terminate for C / ZIG compat
342-
let null_term_offset = current_offset + arg_bytes.len() as u64;
419+
let null_term_offset = current_offset + 4 + arg_bytes.len() as u64;
343420
view.write(null_term_offset, &[0]).unwrap_or_else(|_| panic_any("exec_arg_null_write"));
344-
345421
// Save the POINTER (i32) to pass to the function call later
346422
wasm_arg_ptrs.push(Value::I32(current_offset as i32));
347-
348423
// Advance offset (Add +1 if you need null-termination for C-strings)
349-
current_offset += (arg_bytes.len() as u64) + 1;
424+
current_offset += 4 + (arg_bytes.len() as u64) + 1;
350425
}
351426
}
352427

@@ -371,11 +446,14 @@ pub fn setup_wasm_instance(env: &mut ApplyEnv, module: &Module, store: &mut Stor
371446
"import_return" => Function::new_typed_with_env(store, &host_env, import_return_implementation),
372447

373448
//Storage
374-
"import_kv_get" => Function::new_typed_with_env(store, &host_env, import_storage_kv_get_implementation),
449+
"import_kv_put" => Function::new_typed_with_env(store, &host_env, import_storage_kv_put_implementation),
450+
"import_kv_increment" => Function::new_typed_with_env(store, &host_env, import_storage_kv_increment_implementation),
375451

376-
/*
452+
"import_kv_get" => Function::new_typed_with_env(store, &host_env, import_storage_kv_get_implementation),
453+
"import_kv_exists" => Function::new_typed_with_env(store, &host_env, import_storage_kv_exists_implementation),
377454

378455

456+
/*
379457
"import_attach" => Function::new_typed_with_env(&mut store, &host_env, import_attach_implementation),
380458
381459
@@ -386,17 +464,12 @@ pub fn setup_wasm_instance(env: &mut ApplyEnv, module: &Module, store: &mut Stor
386464
"import_call_4" => Function::new_typed_with_env(&mut store, &host_env, import_call_4_implementation),
387465
388466
//storage
389-
"import_kv_put" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_put_implementation),
390-
"import_kv_increment" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_increment_implementation),
391467
"import_kv_delete" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_delete_implementation),
392468
"import_kv_clear" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_clear_implementation),
393469
394-
"import_kv_exists" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_exists_implementation),
395470
"import_kv_get_prev" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_get_prev_implementation),
396471
"import_kv_get_next" => Function::new_typed_with_env(&mut store, &host_env, import_storage_kv_get_next_implementation),
397472
*/
398-
//"import_kv_put_int" => Function::new_typed(&mut store, || println!("called_kv_put_in_rust")),
399-
//"import_kv_get_prefix" => Function::new_typed(&mut store, || println!("called_kv_get_in_rust")),
400473

401474
//AssemblyScript specific
402475
"abort" => Function::new_typed_with_env(store, &host_env, as_abort_implementation),
@@ -486,7 +559,7 @@ pub fn call_contract(env: &mut ApplyEnv, wasm_bytes: &[u8], function_name: Strin
486559
}
487560
};
488561

489-
let (instance, wasm_args) = setup_wasm_instance(env, &module, &mut store, false, &[]);
562+
let (instance, wasm_args) = setup_wasm_instance(env, &module, &mut store, false, &function_args);
490563

491564
let entry_to_call = instance.exports.get_function(&function_name).unwrap_or_else(|e| {
492565
log_line(env, e.to_string().into_bytes());

ex/native/rdb/src/consensus/consensus_apply.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,12 @@ pub fn apply_entry<'db, 'a>(db: &'db TransactionDB<MultiThreaded>, pk: &[u8], sk
222222
false => {
223223
//println!("{:?}->{:?} {:?} {:?}", String::from_utf8_lossy(&contract), String::from_utf8_lossy(&function), attached_amount, attached_symbol);
224224
call_bic(&mut applyenv, contract, function, args, attached_symbol, attached_amount);
225+
b"ok".to_vec()
225226
}
226227
true => {
227228
//println!("{:?}->{:?} {:?} {:?}", bs58::encode(&contract).into_string(), String::from_utf8_lossy(&function), attached_amount, attached_symbol);
228-
call_wasmvm(&mut applyenv, contract, function, args, attached_symbol, attached_amount);
229+
let result = call_wasmvm(&mut applyenv, contract, function, args, attached_symbol, attached_amount);
230+
result
229231
}
230232
}
231233
}));
@@ -239,7 +241,7 @@ pub fn apply_entry<'db, 'a>(db: &'db TransactionDB<MultiThreaded>, pk: &[u8], sk
239241
}
240242

241243
match res {
242-
Ok(_) => {
244+
Ok(result) => {
243245
applyenv.muts_final.append(&mut applyenv.muts);
244246
applyenv.muts_final_rev.append(&mut applyenv.muts_rev);
245247
refund_exec_storage_deposit(&mut applyenv);
@@ -268,7 +270,7 @@ pub fn apply_entry<'db, 'a>(db: &'db TransactionDB<MultiThreaded>, pk: &[u8], sk
268270
let receipt = protocol::ExecutionReceipt {
269271
txid: tx_hash.into(),
270272
success: true,
271-
error: "ok".to_string().into(),
273+
result: result.into(),
272274
exec_used: exec_cost_total.clone().into(),
273275
logs: applyenv.logs.clone(),
274276
};
@@ -288,7 +290,7 @@ pub fn apply_entry<'db, 'a>(db: &'db TransactionDB<MultiThreaded>, pk: &[u8], sk
288290
let receipt = protocol::ExecutionReceipt {
289291
txid: tx_hash.into(),
290292
success: false,
291-
error: s.to_string().into(),
293+
result: s.to_string().into(),
292294
exec_used: exec_cost_total.clone().into(),
293295
logs: applyenv.logs.clone(),
294296
};
@@ -302,7 +304,7 @@ pub fn apply_entry<'db, 'a>(db: &'db TransactionDB<MultiThreaded>, pk: &[u8], sk
302304
let receipt = protocol::ExecutionReceipt {
303305
txid: tx_hash.into(),
304306
success: false,
305-
error: "unknown".to_string().into(),
307+
result: b"unknown".into(),
306308
exec_used: exec_cost_total.clone().into(),
307309
logs: applyenv.logs.clone(),
308310
};
@@ -696,7 +698,7 @@ fn call_bic(env: &mut ApplyEnv, contract: Vec<u8>, function: Vec<u8>, args: Vec<
696698
}
697699
}
698700

699-
fn call_wasmvm(env: &mut ApplyEnv, contract: Vec<u8>, function: Vec<u8>, args: Vec<Vec<u8>>, attached_symbol: Option<Vec<u8>>, attached_amount: Option<Vec<u8>>) {
701+
fn call_wasmvm(env: &mut ApplyEnv, contract: Vec<u8>, function: Vec<u8>, args: Vec<Vec<u8>>, attached_symbol: Option<Vec<u8>>, attached_amount: Option<Vec<u8>>) -> Vec<u8> {
700702
let function = String::from_utf8(function).unwrap_or_else(|_| panic_any("invalid_function"));
701703

702704
env.caller_env.attached_symbol = Vec::new();
@@ -722,11 +724,6 @@ fn call_wasmvm(env: &mut ApplyEnv, contract: Vec<u8>, function: Vec<u8>, args: V
722724
}
723725

724726
std::panic::panic_any("wasm_noop");
725-
726727
let error = consensus::bic::wasm::call_contract(env, bytecode.as_deref().unwrap_or_else(|| panic_any("invalid_bytecode")), function, args);
727-
728-
//let result = ();
729-
730-
//exec used
731-
//muts
728+
error
732729
}

ex/native/rdb/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ fn apply_entry<'a>(env: Env<'a>, db: ResourceArc<DbResource>, next_entry_trimmed
714714
let mut map = Term::map_new(env);
715715
map = map.map_put(atoms::success(), r.success).ok().unwrap();
716716
map = map.map_put(atoms::txid(), to_binary2(env, &r.txid)).ok().unwrap();
717-
map = map.map_put(atoms::error(), to_binary2(env, &r.error)).ok().unwrap();
717+
map = map.map_put(atoms::result(), to_binary2(env, &r.result)).ok().unwrap();
718718
map = map.map_put(atoms::exec_used(), to_binary2(env, &r.exec_used)).ok().unwrap();
719719
let logs_list: Vec<Binary> = r.logs.iter().map(|log| {
720720
to_binary2(env, log)

0 commit comments

Comments
 (0)