ruff-vm v0.4.3
RuffVM
RuffVM is a light-weight VM environment designed for DApps(Decentralized applications). It provides secure, isolated execution environment as well as resource control (e.g Memory and CPU) for Dapps. It lowers the barrier of Blockchain application development by significant amount via JavaScript based abstraction (But not limited to JS).
RuffVM's build-in,plug-in mechanism allows developers to customize DApp runtime depends on their need, these modules will be completely independent to a public chain base and will be compatible with any Blockchain platforms(e.g EOS,Ethereum,ruffchain).
RoadMap
Present
- 0.1 Implementation on Node.js
 - 0.2 Build-in modules
 
In progress
- Verification and optimization on ruffchain blockchain
 - Standerlize modules build-in, plug-in mechanism
 
Future release
- Split out ruffvm-core into separate repo
 - Port to EOS
 - Port to Ethereum
 - DApp Module registry
 
RuffVM-Node
RuffVM integration for node.js, aim to provide usable, secure sandbox in order to run untrusted javascript code in nodejs, Resource control abilities supported in this version (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.
Building manually and running tests
Currently enabled build on Macos & Linux with C++1y support
build
git clone --recurse-submodules https://github.com/ruffchain/RuffVM.git
cd RuffVM
npm installbuild manually
node-gyp configure
node-gyp buildhow to test
npm run testdata type supported between VM and Host by bridge
- Undefined
 - Boolean
 - Number
 - String
 - ArrayBuffer
 
API
Class: Script
new Script(code)
code\ code to compile and evaluate in VM- Returns: \
 
script.setUserCode(userCode)
userCode\ script to run in VM aftercode- Returns: \
 
script.setOption(options)
optionscpuCount\ cpu count to limitmemSizeKB\ memory size in KB
- Returns: \
 
script.setSandbox(sandbox)
sandbox\ will be the global object in vm- Returns: \
 
script.runAsync()
- Returns: \
resolvereturn value from scriptrejecterror status (boolean)
 
createScript(code)
code\ code to compile and evaluate in VM- Returns: \
 
Example
Host return no Promised value to VM
const assert = require('assert')
const { createScript } = require('ruffvm')
const code = `
  function helloFun(parameterString) {
    var buf = new Uint8Array(20)
    buf[0] = 1
    buf[1] = 2
    return hello(buf.buffer)
  }`
let isTriggered = false
const sandbox = {
  hello: function(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
  }
}
;(async () => {
  const res = await createScript(code)
    .setUserCode(`helloFun("ruffVM")`)
    .setSandbox(sandbox)
    .setOption({ cpuCount: 1, memSizeKB: 200 })
    .runAsync()
  assert(isTriggered)
  assert(res === true)
})()Host return Resolved Promised value to VM
const assert = require('assert')
const vm = require('ruffvm')
function bufferToArrayBuffer(b ){
  return b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
}
const code = `
  function helloFun(parameterString) {
    var buf = new Uint8Array(20)
    buf[0] = 1
    buf[1] = 2
    return hello(buf.buffer)
  }`
const sandbox = {
  hello: function(vmResolve, name) {
    return 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)
    })
  }
}
;(async () => {
  const res = await createScript(code)
    .setUserCode(`helloFun("ruffVM")`)
    .setSandbox(sandbox)
    .setOption({ cpuCount: 1, memSizeKB: 200 })
    .runAsync()
  const expectBuffer = bufferToArrayBuffer(Buffer.from('this is hostapi test'))
  const expectU8 = new Uint8Array(expectBuffer, 0, expectBuffer.byteLength)
  const resU8 = new Uint8Array(res, 0, res.byteLength)
  assert.deepStrictEqual(resU8, expectU8)
})()For more example please refer to test/basic.test.js
Function export to VM from Node.js
- function hostApi(vmResolve, parmFromVM)
- vmResolve: resolve handler to resolve Resolved Value on Node.js, just ignore this handler if the return value is not promise
 - paramFromVM: parameter specified from VM
 
 
Main usage
ruffchain use ruffvm as its smart contract execute engine, provide the ability for user develop their smart contract by JavaScript.
Difference from Node's vm
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.');Difference from duktape.node
ruffvm-node support set limit on CPU and Memory comparing to duktape.node
To do list
- Enable build on Linux
 - Add chain style API
 - Add SharedArrayBuffer support (ES2017)
 - Evaluate 
XSJavaScript Engine 
Known improvements
Does not support multiple instance of vm run simultaneously. Communication between VM and Host is not optimized for heavily usage scenario.