RuffVM is a small embeddable VM provides security, isolate execution environment for run DApp(Decentralized application). It provides resource(e.g Memory and CPU) control ability to limit resource could be consumed by DApp. RuffVM aim to provide a Uniform Blockchain DApp runtime, DApp developer could develop DApp by a user friendly programming language JavaScript(but not only limit to it). RuffVM provide modules build-in,plug-in mechanism for Blockchain developer to customize DApp runtime depends on their need, these modules expected to be shareable across difference Blockchain platform(e.g EOS,Ethereum,ruffchain). For DApp developer that means their DApp could be ported to different Blockchain platform smoothly.
- 0.1 Implement on Node.js
- Provide build-in modules
- Standerlize modules build-in, plug-in mechanism
- verify and optimize on ruffchain blockchain
- splitting out ruffvm-core into separate repo
- ported to EOS
- ported to Ethereum
- DApp Module registry
RuffVM integration for node.js, aim at providing simple usable, security sandbox for run untrusted javascript code in nodejs, meantime provides resource control abilities(e.g. cpu time and memory). RuffVM leverage jerryscript(a lightweight JavaScript engine) as javascript runtime, it is isolated with Node V8 engine naturally. Refer some idea from duktape.node.
So far enabled build on Macos only
build
git clone --recurse-submodules [email protected]:ruffchain/RuffVM.git
cd RuffVM
npm install
build manually
node-gyp configure
node-gyp build
npm run test
- Undefined
- Boolean
- Number
- String
- ArrayBuffer
Description
Runs a single script on ruffvm and returns error status and return value to callback.
Parameters
- script: a script to run in
context
- context: to compile and evaluate
script
in - apiTable: API table for script and context
- properties:
- key: name for function
- value: function to call
- properties:
- resourceCtrl: resource control params
- properties:
- cpuTime: cpu count to limit
- memSizeKB: memory size in KB
- properties:
- callback: function with signature
function(error, returnValue)
- error: error status (boolean)
- returnValue: return value from script or error in case of an error
Example
Host return no Promised
value to VM
const assert = require('assert');
const vm = require('ruffvm');
let isTriggered = false;
function bufferToArrayBuffer(b ){
return b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
}
function apiFunction(resolve, param) {
isTriggered = true;
const u8 = new Uint8Array(param, 0, param.byteLength);
assert(u8.length === 20);
assert(u8[0] = 1 && u8[1] === 2);
return true;
}
var contextStr = " \
function helloFun(parameterString) { \
var buf = new Uint8Array(20); \
buf[0] = 1; \
buf[1] = 2; \
return hello(buf.buffer); \
} \
";
var apiObject = {
hello: apiFunction
};
const contextAB = bufferToArrayBuffer(Buffer.from(contextStr));
const contextU8Buf = new Uint8Array(contextAB, 0, contextAB.byteLength);
vm.run('helloFun("ruffVM")', contextU8Buf, apiObject, {cpuCount:1, memSizeKB:200}, (err, ret) => {
assert(isTriggered);
assert(err === false && ret === true);
});
Host return Resolved Promised
value to VM
const assert = require('assert');
const vm = require('ruffvm');
var apiFunction = function(vmResolve, name) {
var ret = new Promise(function(resolve){
let ab1 = bufferToArrayBuffer(Buffer.from('this is hostapi test'));
const u8 = new Uint8Array(ab1, 0, ab1.byteLength);
setTimeout(() => {
vmResolve(u8); // send resolved value to VM
resolve();
}, 20);
});
return ret;
}
var contextStr = " \
function helloFun(parameterString) { \
var buf = new Uint8Array(20); \
buf[0] = 1; \
buf[1] = 2; \
return hello(buf.buffer); \
} \
";
var apiObject = {
hello: apiFunction
};
const contextAB = bufferToArrayBuffer(Buffer.from(contextStr));
const contextU8Buf = new Uint8Array(contextAB, 0, contextAB.byteLength);
vm.run('helloFun("ruffVM")', contextU8Buf, apiObject, {cpuCount:1, memSizeKB:200}, (err, ret) => {
assert(isTriggered);
assert(err === false);
var expectBuffer = bufferToArrayBuffer(Buffer.from('this is hostapi test'));
var expectU8 = new Uint8Array(expectBuffer, 0, expectBuffer.byteLength);
var retU8 = new Uint8Array(ret, 0, ret.byteLength);
assert.deepStrictEqual(retU8, expectU8);
});
more Example please refer to test/basic.test.js
- function hostApi(vmResolve, parmFromVM)
- vmResolve: resolve handle to resolve Resolved Value on Node.js, just ignore this handle if the return value is not promise
- paramFromVM: parameter specified from VM
ruffchain
use ruffvm as its smart contract execute engine, provide the ability for user develop their smart contract by JavaScript.
Following code will escape node vm sandbox
and do exit on host
const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('Never gets executed.');
ruffvm-node support set both CPU and Memory limitation whereas duktape.node do not support
- Enable build on Linux and Windows
- Add node.js
vm
module compatible API - Add SharedArrayBuffer support (ES2017)
- Evaluate
XS
JavaScript Engine
Does not support multiple instance of vm run simultaneously. Communication between VM and Host is not optimized for heavily usage scenario.