Skip to content

Commit 62b849f

Browse files
committed
wasm call
1 parent ce12072 commit 62b849f

File tree

7 files changed

+204
-122
lines changed

7 files changed

+204
-122
lines changed

contract_samples/assemblyscript/0_counter.ts

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,31 @@ import * as sdk from "./sdk";
22
import { b, b58 } from "./sdk";
33

44
export function get(): void {
5-
sdk.log(b(`get called`))
6-
if (sdk.kv_exists(b("the_counter"))) {
7-
sdk.log("exists")
8-
}
95
let cur_counter = sdk.bToI64(sdk.kv_get("the_counter"))
10-
sdk.kv_put("the_counter", "1")
11-
sdk.kv_put(b("the_counter1"), b("1"))
12-
sdk.kv_put(b("the_counter2"), b("1"))
13-
sdk.kv_put(b("the_counter3"), b("1"))
14-
15-
let last_key = b("the_counter4")
16-
while(1) {
17-
let kv = sdk.kv_get_prev(b(""), last_key);
18-
sdk.log(kv.key);
19-
sdk.log(kv.value);
20-
if (kv.key == null) break;
21-
last_key = kv.key!;
22-
}
23-
//sdk.kv_delete(b("the_counter"))
24-
//let new_counter = sdk.kv_increment(b("the_counter"), "1")
25-
//assert(cur_counter < 10, "counter is over 10")
266
sdk.ret(cur_counter)
277
}
288

299
export function increment(amount_ptr: i32): void {
3010
let amount = sdk.memory_read_string(amount_ptr)
31-
let new_counter = sdk.kv_increment(b("the_counter"), amount)
11+
sdk.kv_increment("the_counter", amount)
12+
let new_counter = sdk.kv_increment("the_counter", roll_dice())
3213
sdk.ret(new_counter)
3314
}
3415

35-
export function roll_dice(): void {
16+
export function increment_another_counter(contract_ptr: i32): void {
17+
let contract = sdk.memory_read_bytes(contract_ptr)
18+
let incr_by = roll_dice()
19+
sdk.log(`Calling increment on ${b58(contract)} by ${incr_by}`)
20+
let other_counter = sdk.call(contract, "increment", [b(incr_by)])
21+
sdk.ret(other_counter)
22+
}
23+
24+
//Current: VRF Stage 1 is used.
25+
//Seed is signature of previous VRF by current validator.
26+
//A malicious validator can do a withholding attack (not include a TX if the RNG is unfavorable)
27+
28+
//Coming Soon: VRF Stage 2 will be only attackable if 67% are malicious as it will use BLS Threshold /w DKG
29+
export function roll_dice(): i64 {
3630
const val = Math.random(); // Returns 0.0 to 1.0
37-
let roll = floor(val * 6) as i32 + 1;
38-
sdk.ret(roll)
31+
return floor(val * 6) as i32 + 1; // Returns 1-6
3932
}

contract_samples/assemblyscript/sdk.ts

Lines changed: 54 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@inline
2-
function toBytes<T>(val: T): Uint8Array {
2+
export function toBytes<T>(val: T): Uint8Array {
33
if (isInteger<T>()) {
44
const str = val.toString();
55
return Uint8Array.wrap(String.UTF8.encode(str));
@@ -19,6 +19,10 @@ function toBytes<T>(val: T): Uint8Array {
1919
}
2020
}
2121

22+
export function b<T>(val: T): Uint8Array {
23+
return toBytes(val)
24+
}
25+
2226
class KeyValuePair {
2327
constructor(
2428
public key: Uint8Array | null,
@@ -121,7 +125,7 @@ function from_b58_1(S: string, A: string = MAP): Uint8Array | null {
121125
return result;
122126
}
123127

124-
function memory_read_bytes(ptr: i32): Uint8Array {
128+
export function memory_read_bytes(ptr: i32): Uint8Array {
125129
let length = load<i32>(ptr);
126130
let result = new Uint8Array(length);
127131
memory.copy(changetype<usize>(result.buffer), ptr+4, length);
@@ -153,10 +157,6 @@ export function base58_decode(input: string): Uint8Array {
153157
return out;
154158
}
155159

156-
export function b(str: string): Uint8Array {
157-
return Uint8Array.wrap(String.UTF8.encode(str, false));
158-
}
159-
160160
export function bToI64(data: Uint8Array | null, defaultVal: i64 = 0): i64 {
161161
if (!data) return defaultVal;
162162
const str = String.UTF8.decodeUnsafe(data.dataStart, data.byteLength);
@@ -340,53 +340,56 @@ export function kv_get_next<K, V>(prefix: K, key: V): KeyValuePair {
340340
return new KeyValuePair(prev_key, value);
341341
}
342342

343-
@external("env", "import_call_0")
344-
declare function import_call_0(module_ptr: i32, module_len: i32, function_ptr: i32, function_len: i32): i32;
345-
@external("env", "import_call_1")
346-
declare function import_call_1(module_ptr: i32, module_len: i32, function_ptr: i32, function_len: i32,
347-
args_1_ptr: i32, args_1_len: i32): i32;
348-
@external("env", "import_call_2")
349-
declare function import_call_2(module_ptr: i32, module_len: i32, function_ptr: i32, function_len: i32,
350-
args_1_ptr: i32, args_1_len: i32, args_2_ptr: i32, args_2_len: i32): i32;
351-
@external("env", "import_call_3")
352-
declare function import_call_3(module_ptr: i32, module_len: i32, function_ptr: i32, function_len: i32,
353-
args_1_ptr: i32, args_1_len: i32, args_2_ptr: i32, args_2_len: i32, args_3_ptr: i32, args_3_len: i32): i32;
354-
@external("env", "import_call_4")
355-
declare function import_call_4(module_ptr: i32, module_len: i32, function_ptr: i32, function_len: i32,
356-
args_1_ptr: i32, args_1_len: i32, args_2_ptr: i32, args_2_len: i32, args_3_ptr: i32, args_3_len: i32, args_4_ptr: i32, args_4_len: i32): i32;
357-
358-
export function call(contract: Uint8Array, func: string, args: Uint8Array[]): string {
359-
let funcBytes = String.UTF8.encode(func, false);
360-
let funcPtr = changetype<i32>(funcBytes);
361-
362-
let errorPtr = 30_000
363-
switch (args.length) {
364-
case 0:
365-
errorPtr = import_call_0(changetype<i32>(contract.dataStart), contract.byteLength, funcPtr, funcBytes.byteLength);
366-
break;
367-
case 1:
368-
errorPtr = import_call_1(changetype<i32>(contract.dataStart), contract.byteLength, funcPtr, funcBytes.byteLength,
369-
changetype<i32>(args[0].dataStart), args[0].byteLength);
370-
break;
371-
case 2:
372-
errorPtr = import_call_2(changetype<i32>(contract.dataStart), contract.byteLength, funcPtr, funcBytes.byteLength,
373-
changetype<i32>(args[0].dataStart), args[0].byteLength, changetype<i32>(args[1].dataStart), args[1].byteLength);
374-
break;
375-
case 3:
376-
errorPtr = import_call_3(changetype<i32>(contract.dataStart), contract.byteLength, funcPtr, funcBytes.byteLength,
377-
changetype<i32>(args[0].dataStart), args[0].byteLength, changetype<i32>(args[1].dataStart), args[1].byteLength,
378-
changetype<i32>(args[2].dataStart), args[2].byteLength);
379-
break;
380-
case 4:
381-
errorPtr = import_call_4(changetype<i32>(contract.dataStart), contract.byteLength, funcPtr, funcBytes.byteLength,
382-
changetype<i32>(args[0].dataStart), args[0].byteLength, changetype<i32>(args[1].dataStart), args[1].byteLength,
383-
changetype<i32>(args[2].dataStart), args[2].byteLength, changetype<i32>(args[3].dataStart), args[3].byteLength);
384-
break;
385-
default:
386-
abort("call_invalid_no_of_args");
343+
// One import to rule them all
344+
@external("env", "import_call")
345+
declare function import_call(args_ptr: i32, extra_args_ptr: i32): i32;
346+
export function call<C, F, T = Uint8Array>(contract: C, func: F, args: T[], extra_args: T[] | null = null): Uint8Array {
347+
const contractBytes = toBytes<C>(contract);
348+
const funcBytes = toBytes<F>(func);
349+
350+
const pinnedArgs = new Array<Uint8Array>(2 + args.length);
351+
pinnedArgs[0] = contractBytes;
352+
pinnedArgs[1] = funcBytes;
353+
for (let j = 0; j < args.length; j++) { pinnedArgs[2 + j] = toBytes<T>(args[j]) }
354+
355+
// 4 bytes for Count
356+
// 16 bytes for contract + func
357+
// 8 bytes * args
358+
const totalItems = 2 + args.length;
359+
const tablePtr = __alloc(4 + 16 + (8 * totalItems));
360+
store<i32>(tablePtr, totalItems);
361+
for (let i = 0; i < pinnedArgs.length; i++) {
362+
const arg = pinnedArgs[i];
363+
const offset = 4 + (i * 8);
364+
365+
store<i32>(tablePtr + offset, changetype<i32>(arg.dataStart));
366+
store<i32>(tablePtr + offset + 4, arg.byteLength);
387367
}
388368

389-
return memory_read_string(errorPtr);
369+
//Extra args
370+
let extraTablePtr = 0;
371+
if (extra_args) {
372+
const pinnedExtraArgs = new Array<Uint8Array>(extra_args.length);
373+
for (let i = 0; i < extra_args.length; i++) { pinnedExtraArgs[i] = toBytes<T>(extra_args[i]) }
374+
375+
extraTablePtr = __alloc(4 + (8 * extra_args.length)) as i32;
376+
store<i32>(extraTablePtr, extra_args.length);
377+
378+
for (let i = 0; i < extra_args.length; i++) {
379+
const earg = pinnedExtraArgs[i];
380+
const offset = 4 + (i * 8);
381+
382+
store<i32>(extraTablePtr + offset, changetype<i32>(earg.dataStart));
383+
store<i32>(extraTablePtr + offset + 4, earg.byteLength);
384+
}
385+
}
386+
387+
const errorPtr = import_call(tablePtr as i32, extraTablePtr as i32);
388+
389+
// Cleanup (Optional, but good practice if you do this in a loop)
390+
__free(tablePtr);
391+
392+
return memory_read_bytes(errorPtr);
390393
}
391394

392395
/*
@@ -453,36 +456,3 @@ function kv_get<T,Y>(key: Y): T {
453456
}*/
454457
//return null as T;
455458
//}
456-
457-
458-
/*
459-
@external("env", "import_kv_increment")
460-
declare function import_kv_increment(keyPtr: i32, keyLen: i32, amount: i64): i64;
461-
function kv_increment(key: string, amount: i64): i64 {
462-
let keyBytes = String.UTF8.encode(key);
463-
let keyPtr = changetype<i32>(keyBytes);
464-
let keyLen = keyBytes.byteLength;
465-
466-
return import_kv_increment(keyPtr, keyLen, amount);
467-
}
468-
469-
@external("env", "import_kv_get")
470-
declare function import_kv_get(keyPtr: i32, keyLen: i32): i32;
471-
function kv_get(key: string): string {
472-
let keyBytes = String.UTF8.encode(key);
473-
let keyPtr = changetype<i32>(keyBytes);
474-
let keyLen = keyBytes.byteLength;
475-
476-
const valPtr = import_kv_get(keyPtr, keyLen);
477-
if (!valPtr) {
478-
return "";
479-
}
480-
481-
const valLen = load<u32>(valPtr);
482-
const valBytesPtr = valPtr + 4;
483-
//const valBytes = new Uint8Array(import_memory.buffer, valBytesPtr, valLen);
484-
//return String.UTF8.decode(valBytes.buffer);
485-
return "";
486-
}
487-
488-
*/

ex/lib/api/api_tx.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,18 @@ defmodule API.TX do
143143
%{error: :ok} ->
144144
if broadcast do TXPool.insert_and_broadcast(txu) else TXPool.insert(txu) end
145145
txres = submit_and_wait_1(result.txu.hash)
146-
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result]}
146+
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result], receipt: txres[:receipt]}
147147
error -> error
148148
end
149149
else
150150
if broadcast do TXPool.insert_and_broadcast(txu) else TXPool.insert(txu) end
151151
txres = submit_and_wait_1(result.txu.hash)
152-
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result]}
152+
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result], receipt: txres[:receipt]}
153153
end
154154
else
155155
if broadcast do TXPool.insert_and_broadcast(txu) else TXPool.insert(txu) end
156156
txres = submit_and_wait_1(result.txu.hash)
157-
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result]}
157+
%{error: :ok, hash: Base58.encode(result.txu.hash), entry_hash: txres.metadata.entry_hash, result: txres[:result], receipt: txres[:receipt]}
158158
end
159159
else
160160
%{error: result.error}

ex/lib/misc/testnet.ex

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ defmodule Testnet do
99
RocksDB.get(key, %{db: db, cf: cf.contractstate})
1010
end
1111

12-
def deploy(path) do deploy(Application.fetch_env!(:ama, :keys) |> Enum.at(0) |> Map.fetch!(:pk), path) end
13-
def deploy(pk, path) do
14-
key0 = Application.fetch_env!(:ama, :keys) |> Enum.at(0)
15-
pk = if byte_size(pk) != 48, do: Base58.decode(pk), else: pk
12+
def deploy(path) do deploy(Application.fetch_env!(:ama, :keys) |> Enum.at(0), path) end
13+
def deploy(key, path) do
1614
wasmbytes = File.read!(path)
17-
Testnet.call(key0.seed, "Contract", "deploy", [wasmbytes])
15+
Testnet.call(key.seed, "Contract", "deploy", [wasmbytes])
1816
end
1917

2018
def transfer(to, amount, symbol \\ "AMA") do

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub const FORKHEIGHT: u64 = 435_00000;
77
pub const AMA_1_DOLLAR: i128 = 1_000_000_000;
88
pub const AMA_10_CENT: i128 = 100_000_000;
99
pub const AMA_1_CENT: i128 = 10_000_000;
10+
pub const AMA_01_CENT: i128 = 1_000_000;
1011

1112
pub const RESERVE_AMA_PER_TX_EXEC: i128 = AMA_10_CENT; //reserved for exec balance (refunded at end of TX execution)
1213
pub const RESERVE_AMA_PER_TX_STORAGE: i128 = AMA_1_DOLLAR; //reserved for storage writes
@@ -20,6 +21,7 @@ pub const COST_PER_DB_READ_BYTE: i128 = 50 * 10;
2021
pub const COST_PER_DB_WRITE_BASE: i128 = 25_000 * 10;
2122
pub const COST_PER_DB_WRITE_BYTE: i128 = 250 * 10;
2223

24+
pub const COST_PER_CALL: i128 = AMA_01_CENT;
2325
pub const COST_PER_DEPLOY: i128 = AMA_1_CENT; //cost to deploy contract
2426
pub const COST_PER_SOL: i128 = AMA_1_CENT; //cost to submit_sol
2527
pub const COST_PER_NEW_LEAF_MERKLE: i128 = COST_PER_BYTE_STATE * 128; //cost to grow the merkle tree

0 commit comments

Comments
 (0)