as-json
as-json copied to clipboard
partial initialisation of deserialised class object - RuntimeError: out of bounds memory access
I am trying out below code which has some imports which gets length prefixed strings from memory. These host native imports implementation is closed. Below is the code
import { JSON } from "json-as/assembly";
// Runtime imported functions
// @ts-ignore
@external("env", "get_state")
declare function getState(): i32
// @ts-ignore
@external("env", "get_args")
declare function getArgs(): i32
// @ts-ignore
@external("env", "debug_log")
declare function debugLog(buf: ArrayBuffer): i32
// @ts-ignore
@external("env", "set_state")
declare function setState(buf: ArrayBuffer): i32
type GetFn = () => i32;
function readStringFromMemory(fn: GetFn): string {
let ptr = fn()
let len: i32 = load<u32>(ptr)
let buffer = new Uint8Array(len);
for (let i = 0; i < len; ++i) {
buffer[i] = load<u8>(ptr + 4 + i);
}
let s = String.UTF8.decode(buffer.buffer);
return s
}
function getLengthPrefixedString(s: string): ArrayBuffer {
let stringBuf = Uint8Array.wrap(String.UTF8.encode(s))
let newLen = stringBuf.byteLength
let buffer = new ArrayBuffer(4 + newLen);
let dataView = new DataView(buffer);
dataView.setUint32(0, newLen, true);
for (let i = 0; i < newLen; ++i) {
dataView.setInt8(4 + i, stringBuf[i])
}
return buffer
}
@json
class TokenMetaData {
id: u64;
name: string;
uri: string;
constructor(id: u64, name: string, uri: string) {
this.id = id;
this.name = name;
this.uri = uri;
}
}
@json
class NonFungibleToken {
owner: string;
counter: u64;
tokens: Map<u64, TokenMetaData>;
owners: Map<u64, string>;
balances: Map<string, u64[]>;
constructor() {
this.owner = "";
this.counter = 0;
this.tokens = new Map();
this.owners = new Map();
this.balances = new Map();
}
mint(name: string, uri: string, toAddress: string): u64 {
this.counter += 1;
let id = this.counter;
const tokenMetaData = new TokenMetaData(id, name, uri);
// beyond this point program fails with `out of memory bound access` error!
this.tokens.set(id, tokenMetaData);
this.owners.set(id, toAddress);
if (!this.balances.has(toAddress)) {
this.balances.set(toAddress, []);
}
this.balances.get(toAddress).push(id);
return id;
}
}
// Argument classes
@json
class NonfungibletokenMintArgs {
name!: string;
uri!: string;
toAddress!: string;
}
// WASM exported functions
export function init(): void {
let serializedState = JSON.stringify<NonFungibleToken>(new NonFungibleToken());
let buffer = getLengthPrefixedString(serializedState);
setState(buffer);
}
export function mint(): void {
let state_str = readStringFromMemory(getState);
debugLog(getLengthPrefixedString("inside wasm module state: " + state_str)); // only for testing
let args_str = readStringFromMemory(getArgs);
debugLog(getLengthPrefixedString("inside wasm module args: " + args_str)); // only for testing
let state = JSON.parse<NonFungibleToken>(state_str);
let args = JSON.parse<NonfungibletokenMintArgs>(args_str);
// let state = JSON.parse<NonFungibleToken>('{"owner":"","counter":0,"tokens":{},"owners":{},"balances":{}}');
// let args = JSON.parse<NonfungibletokenMintArgs>('{"name":"yamini","toAddress":"awesome","uri":"bhavya"}');
state.mint(args.name, args.uri, args.toAddress);
let serializedState = JSON.stringify<NonFungibleToken>(state);
let buffer = getLengthPrefixedString(serializedState);
setState(buffer);
}
I am not understanding where the issue is, when I am using hardcoded strings (commented in above code), it is working fine, but when I am reading it from the memory and then parsing it, it is only able to initialise just the counter field rest the maps seem to be uninitialised. Is this issue related to json-as
or assemblyscript
garbage collection? I even tried compiler option --runtime stub
but same error is occurring.