mirror of
https://github.com/fluencelabs/aquavm
synced 2025-04-24 14:52:15 +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
|
node_modules
|
||||||
wasm
|
wasm
|
||||||
*.tgz
|
*.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",
|
"name": "@fluencelabs/avm",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "Apache 2.0",
|
"license": "Apache 2.0",
|
||||||
"bin": {
|
|
||||||
"copy-avm": "dist/copyAvm.js"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^14.0.0",
|
|
||||||
"typescript": "^4.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": {
|
"node_modules/typescript": {
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
||||||
@ -37,12 +27,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"typescript": {
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
|
||||||
|
@ -2,23 +2,19 @@
|
|||||||
"name": "@fluencelabs/avm",
|
"name": "@fluencelabs/avm",
|
||||||
"description": "Aquamarine VM",
|
"description": "Aquamarine VM",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"main": "./dist/avm.wasm",
|
"main": "./dist/index.js",
|
||||||
"repository": "https://github.com/fluencelabs/air",
|
"repository": "https://github.com/fluencelabs/air",
|
||||||
"author": "Fluence Labs",
|
"author": "Fluence Labs",
|
||||||
"license": "Apache 2.0",
|
"license": "Apache 2.0",
|
||||||
"files": [
|
"files": [
|
||||||
"dist/*"
|
"dist/*"
|
||||||
],
|
],
|
||||||
"bin": {
|
|
||||||
"copy-avm": "./dist/copyAvm.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && ./build_wasm.sh"
|
"build": "tsc && ./build_wasm.sh"
|
||||||
},
|
},
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^4.0.0",
|
"typescript": "^4.0.0"
|
||||||
"@types/node": "^14.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