mirror of
https://github.com/fluencelabs/aquavm
synced 2025-03-16 04:50:49 +00:00
Marine-js stage 2: move avm-related helpers to appropriate package (#239)
This commit is contained in:
parent
06d275ea16
commit
c2bfad7f79
5
avm/client/.gitignore
vendored
5
avm/client/.gitignore
vendored
@ -2,8 +2,3 @@ dist
|
||||
node_modules
|
||||
wasm
|
||||
*.tgz
|
||||
|
||||
# this file is auto-generated
|
||||
src/wasm.js
|
||||
src/importObject.ts
|
||||
src/avm.wasm
|
||||
|
16
avm/client/package-lock.json
generated
16
avm/client/package-lock.json
generated
@ -8,20 +8,10 @@
|
||||
"name": "@fluencelabs/avm",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache 2.0",
|
||||
"bin": {
|
||||
"copy-avm": "dist/copyAvm.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.0",
|
||||
"typescript": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "14.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.9.tgz",
|
||||
"integrity": "sha512-j11XSuRuAlft6vLDEX4RvhqC0KxNxx6QIyMXNb0vHHSNPXTPeiy3algESWmOOIzEtiEL0qiowPU3ewW9hHVa7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
||||
@ -37,12 +27,6 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.9.tgz",
|
||||
"integrity": "sha512-j11XSuRuAlft6vLDEX4RvhqC0KxNxx6QIyMXNb0vHHSNPXTPeiy3algESWmOOIzEtiEL0qiowPU3ewW9hHVa7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
||||
|
@ -2,23 +2,19 @@
|
||||
"name": "@fluencelabs/avm",
|
||||
"description": "Aquamarine VM",
|
||||
"version": "0.0.0",
|
||||
"main": "./dist/avm.wasm",
|
||||
"main": "./dist/index.js",
|
||||
"repository": "https://github.com/fluencelabs/air",
|
||||
"author": "Fluence Labs",
|
||||
"license": "Apache 2.0",
|
||||
"files": [
|
||||
"dist/*"
|
||||
],
|
||||
"bin": {
|
||||
"copy-avm": "./dist/copyAvm.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc && ./build_wasm.sh"
|
||||
},
|
||||
"private": false,
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^4.0.0",
|
||||
"@types/node": "^14.0.0"
|
||||
"typescript": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
169
avm/client/src/avmHelpers.ts
Normal file
169
avm/client/src/avmHelpers.ts
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2022 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CallResultsArray, InterpreterResult, CallRequest } from './types';
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
/**
|
||||
* Serializes AVM arguments in JSON string which can be passed into marine-js
|
||||
* @param initPeerId - peer ID which initialized particle
|
||||
* @param currentPeerId - peer ID which is currently executing the particle
|
||||
* @param air - particle's air script as string
|
||||
* @param prevData - particle's prev data as raw byte array
|
||||
* @param data - particle's data as raw byte array
|
||||
* @param callResults - array of tuples [callResultKey, callResult]
|
||||
* @returns AVM call arguments as serialized JSON string
|
||||
*/
|
||||
export function serializeAvmArgs(
|
||||
initPeerId: string,
|
||||
currentPeerId: string,
|
||||
air: string,
|
||||
prevData: Uint8Array,
|
||||
data: Uint8Array,
|
||||
callResults: CallResultsArray,
|
||||
): string {
|
||||
const callResultsToPass: any = {};
|
||||
for (let [key, callResult] of callResults) {
|
||||
callResultsToPass[key] = {
|
||||
ret_code: callResult.retCode,
|
||||
result: callResult.result,
|
||||
};
|
||||
}
|
||||
|
||||
const paramsToPass = {
|
||||
init_peer_id: initPeerId,
|
||||
current_peer_id: currentPeerId,
|
||||
};
|
||||
|
||||
const encoded = encoder.encode(JSON.stringify(callResultsToPass));
|
||||
|
||||
const avmArg = JSON.stringify([
|
||||
// force new line
|
||||
air,
|
||||
Array.from(prevData),
|
||||
Array.from(data),
|
||||
paramsToPass,
|
||||
Array.from(encoded),
|
||||
]);
|
||||
|
||||
return avmArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes raw result of AVM call obtained from marine-js into structured form
|
||||
* @param rawResult - string containing raw result of AVM call
|
||||
* @returns structured InterpreterResult
|
||||
*/
|
||||
export function deserializeAvmResult(rawResult: string): InterpreterResult {
|
||||
let result: any;
|
||||
try {
|
||||
result = JSON.parse(rawResult);
|
||||
} catch (ex) {
|
||||
throw 'call_module result parsing error: ' + ex + ', original text: ' + rawResult;
|
||||
}
|
||||
|
||||
if (result.error !== '') {
|
||||
throw 'call_module returned error: ' + result.error;
|
||||
}
|
||||
|
||||
result = result.result;
|
||||
|
||||
const callRequestsStr = decoder.decode(new Uint8Array(result.call_requests));
|
||||
let parsedCallRequests;
|
||||
try {
|
||||
if (callRequestsStr.length === 0) {
|
||||
parsedCallRequests = {};
|
||||
} else {
|
||||
parsedCallRequests = JSON.parse(callRequestsStr);
|
||||
}
|
||||
} catch (e) {
|
||||
throw "Couldn't parse call requests: " + e + '. Original string is: ' + callRequestsStr;
|
||||
}
|
||||
|
||||
let resultCallRequests: Array<[key: number, callRequest: CallRequest]> = [];
|
||||
for (const key in parsedCallRequests) {
|
||||
const callRequest = parsedCallRequests[key];
|
||||
|
||||
let arguments_;
|
||||
let tetraplets;
|
||||
try {
|
||||
arguments_ = JSON.parse(callRequest.arguments);
|
||||
} catch (e) {
|
||||
throw "Couldn't parse arguments: " + e + '. Original string is: ' + arguments_;
|
||||
}
|
||||
|
||||
try {
|
||||
tetraplets = JSON.parse(callRequest.tetraplets);
|
||||
} catch (e) {
|
||||
throw "Couldn't parse tetraplets: " + e + '. Original string is: ' + tetraplets;
|
||||
}
|
||||
|
||||
resultCallRequests.push([
|
||||
key as any,
|
||||
{
|
||||
serviceId: callRequest.service_id,
|
||||
functionName: callRequest.function_name,
|
||||
arguments: arguments_,
|
||||
tetraplets: tetraplets,
|
||||
},
|
||||
]);
|
||||
}
|
||||
return {
|
||||
retCode: result.ret_code,
|
||||
errorMessage: result.error_message,
|
||||
data: result.data,
|
||||
nextPeerPks: result.next_peer_pks,
|
||||
callRequests: resultCallRequests,
|
||||
};
|
||||
}
|
||||
|
||||
type CallToAvm = ((args: string) => Promise<string>) | ((args: string) => string);
|
||||
|
||||
/**
|
||||
* Utility function which serializes AVM args and passed them into AVM returning interpreter result.
|
||||
* Call to AVM is delegated to a function which must be provided by user.
|
||||
* It might be either synchronous or asynchronous (returning a promise)
|
||||
* @param fn - delegated call to AVM
|
||||
* @param initPeerId - peer ID which initialized particle
|
||||
* @param currentPeerId - peer ID which is currently executing the particle
|
||||
* @param air - particle's air script as string
|
||||
* @param prevData - particle's prev data as raw byte array
|
||||
* @param data - particle's data as raw byte array
|
||||
* @param callResults - array of tuples [callResultKey, callResult]
|
||||
* @returns structured InterpreterResult
|
||||
*/
|
||||
export async function callAvm(
|
||||
fn: CallToAvm,
|
||||
initPeerId: string,
|
||||
currentPeerId: string,
|
||||
air: string,
|
||||
prevData: Uint8Array,
|
||||
data: Uint8Array,
|
||||
callResults: CallResultsArray,
|
||||
): Promise<InterpreterResult> {
|
||||
try {
|
||||
const avmArg = serializeAvmArgs(initPeerId, currentPeerId, air, prevData, data, callResults);
|
||||
const rawResult = await fn(avmArg);
|
||||
return deserializeAvmResult(rawResult);
|
||||
} catch (e) {
|
||||
return {
|
||||
retCode: -1,
|
||||
errorMessage: 'marine-js call failed, ' + e,
|
||||
} as any;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const firstArgument = process.argv[2];
|
||||
|
||||
if (!firstArgument) {
|
||||
console.log(`Expected exactly 1 argument, got 0. Usage: ${path.basename(process.argv[1])} <destination directory>`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let destPath = firstArgument;
|
||||
if (!path.isAbsolute(destPath)) {
|
||||
destPath = path.join(process.cwd(), destPath);
|
||||
}
|
||||
|
||||
const wasmName = 'avm.wasm';
|
||||
const packageName = '@fluencelabs/avm';
|
||||
|
||||
const modulePath = require.resolve(packageName);
|
||||
const source = path.join(path.dirname(modulePath), wasmName);
|
||||
const dest = path.join(destPath, wasmName);
|
||||
|
||||
console.log('ensure directory exists: ', destPath);
|
||||
fs.mkdirSync(destPath, { recursive: true });
|
||||
|
||||
console.log('copying AVM wasm');
|
||||
console.log('from: ', source);
|
||||
console.log('to: ', dest);
|
||||
fs.copyFileSync(source, dest);
|
||||
|
||||
console.log('done!');
|
18
avm/client/src/index.ts
Normal file
18
avm/client/src/index.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2022 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './types';
|
||||
export * from './avmHelpers';
|
122
avm/client/src/types.ts
Normal file
122
avm/client/src/types.ts
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2022 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type LogLevel = 'info' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||
|
||||
/**
|
||||
* Represents an executed host function result.
|
||||
*/
|
||||
export interface CallServiceResult {
|
||||
/**
|
||||
* A error code service or builtin returned, where 0 represents success.
|
||||
*/
|
||||
retCode: number;
|
||||
|
||||
/**
|
||||
* Serialized return value from the service.
|
||||
*/
|
||||
result: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains arguments of a call instruction and all other necessary information required for calling a service.
|
||||
*/
|
||||
export interface CallRequest {
|
||||
/**
|
||||
* Id of a service that should be called.
|
||||
*/
|
||||
serviceId: string;
|
||||
|
||||
/**
|
||||
* Name of a function from service identified by service_id that should be called.
|
||||
*/
|
||||
functionName: string;
|
||||
|
||||
/**
|
||||
* Arguments that should be passed to the service.
|
||||
*/
|
||||
arguments: any[];
|
||||
|
||||
/**
|
||||
* Security tetraplets that should be passed to the service.
|
||||
*/
|
||||
tetraplets: SecurityTetraplet[][];
|
||||
}
|
||||
|
||||
export type CallRequestsArray = Array<[key: number, callRequest: CallRequest]>;
|
||||
|
||||
export type CallResultsArray = Array<[key: number, callServiceResult: CallServiceResult]>;
|
||||
|
||||
/**
|
||||
* Describes a result returned at the end of the interpreter execution_step.
|
||||
*/
|
||||
export interface InterpreterResult {
|
||||
/**
|
||||
* A return code, where 0 means success.
|
||||
*/
|
||||
retCode: number;
|
||||
|
||||
/**
|
||||
* Contains error message if ret_code != 0
|
||||
*/
|
||||
errorMessage: string;
|
||||
|
||||
/**
|
||||
* Contains script data that should be preserved in an executor of this interpreter regardless of ret_code value.
|
||||
*/
|
||||
data: Uint8Array;
|
||||
|
||||
/**
|
||||
* Public keys of peers that should receive data.
|
||||
*/
|
||||
nextPeerPks: Array<string>;
|
||||
|
||||
/**
|
||||
* Collected parameters of all met call instructions that could be executed on a current peer.
|
||||
*/
|
||||
callRequests: CallRequestsArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* ResolvedTriplet represents peer network location with all variables, literals and etc resolved into final string.
|
||||
* This structure contains a subset of values that SecurityTetraplet consists of.
|
||||
*/
|
||||
export interface ResolvedTriplet {
|
||||
/**
|
||||
* Id of a peer where corresponding value was set.
|
||||
*/
|
||||
peer_pk: string;
|
||||
|
||||
/**
|
||||
* Id of a service that set corresponding value.
|
||||
*/
|
||||
service_id: string;
|
||||
|
||||
/**
|
||||
* Name of a function that returned corresponding value.
|
||||
*/
|
||||
function_name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes an origin that set corresponding value.
|
||||
*/
|
||||
export interface SecurityTetraplet extends ResolvedTriplet {
|
||||
/**
|
||||
* Value was produced by applying this `json_path` to the output from `call_service`.
|
||||
*/
|
||||
json_path: string;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user