Commit fc6f0a0f0855a69b0137cdf8dd265e6e2fb4e16f
added sill design doc
wanderer committed on 7/12/2016, 2:11:46 AMParent: 798d22f70346b2550010f853c9c3582ae86e1f35
Files changed
README.md | changed |
index.js | changed |
interface.js | changed |
package.json | changed |
tests/runner.js | changed |
design.md | added |
environment.js | added |
README.md | ||
---|---|---|
@@ -1,14 +1,35 @@ | ||
1 | -# JS prototype | |
1 | +# SYNOPSIS | |
2 | +[![Gitter](https://img.shields.io/gitter/room/ethereum/ethereumjs-lib.svg?style=flat-square)](https://gitter.im/ethereum/ethereumjs-lib) or #ethereumjs on freenode | |
2 | 3 | |
3 | -The js prototype just implements the Ethereum interface. It uses v8 to run the WASM code. | |
4 | +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) | |
4 | 5 | |
5 | -## Run tests | |
6 | -The tests are written in wasm's text format (.wast) which are then compiled into binary format and ran in v8. | |
6 | +This is a JS prototype of the [eWASM kernal](https://github.com/ethereum/evm2.0-design). | |
7 | 7 | |
8 | + | |
9 | +# INSTALL | |
10 | +You need to compile [nodejs](https://github.com/nodejs/node) from master to run | |
11 | +~~`npm install ewasm-kernal`~~ | |
12 | + | |
13 | +clone and run `npm install` | |
14 | + | |
15 | +# CLONE | |
16 | +* [mango](https://github.com/axic/mango) `git clone mango://{repo address}` | |
17 | +* [git-ssb](https://github.com/clehner/git-ssb) `git clone ssb://{}` | |
18 | +* git `git clone ` | |
19 | + | |
20 | + | |
21 | + | |
22 | +# TESTS | |
23 | +The tests are written in wasm's text format (.wast) which are then compiled into binary format and ran in node. | |
24 | + | |
8 | 25 | To run the test you need |
9 | -* download the submodules. | |
10 | -* compile [v8](https://github.com/v8/v8), which will be in the v8 folder, Instuctions [here](https://github.com/v8/v8/wiki/Building-with-Gyp) | |
11 | -* compile the [sexpr-wasm-prototype](https://github.com/WebAssembly/sexpr-wasm-prototype) which will be in the sexpr-wasm-prototype folder | |
12 | - `cd sexpr-wasm-prototype && make` | |
13 | -* `npm install` | |
26 | +* `git submodule update --init` | |
27 | +* `cd sexpr-wasm-prototype && make` | |
14 | 28 | * `npm test` |
29 | + | |
30 | + | |
31 | +# API | |
32 | +todo | |
33 | + | |
34 | +# LICENSE | |
35 | +[MPL-2.0](https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2)) |
index.js | ||
---|---|---|
@@ -1,36 +1,53 @@ | ||
1 | -const Environment = require('./testEnvironment.js') | |
1 | +/** | |
2 | + * This implements the Ethereum Kernel | |
3 | + * The kernal handles the following | |
4 | + * - Interprocess communications | |
5 | + * - Intializing the VM and exposes ROM to it (codeHandler) | |
6 | + * - Expose namespace which VM instance exists and Intializes the Environment (callHandler) | |
7 | + * - Provides some built in contract (runTx, runBlock) | |
8 | + * - Provides resource sharing and limiting via gas | |
9 | + * | |
10 | + * All State should be stored in the Environment. | |
11 | + */ | |
12 | +// const Environment = require('./environment.js') | |
2 | 13 | const Interface = require('./interface.js') |
3 | 14 | |
4 | -module.exports = class BaseStateTranitions { | |
15 | +module.exports = class Kernal { | |
5 | 16 | // runs some code in the VM |
6 | - constructor (state) { | |
7 | - this.state = state | |
17 | + constructor (nameState) { | |
18 | + this.state = nameState | |
8 | 19 | } |
9 | 20 | |
10 | - // handles running code | |
21 | + // handles running code. `code` can be seen as ROM here | |
11 | 22 | static codeHandler (code, environment) { |
12 | 23 | const ethInterface = new Interface(environment) |
13 | 24 | const instance = Wasm.instantiateModule(code, ethInterface) |
14 | 25 | ethInterface.setModule(ethInterface) |
15 | 26 | return instance |
16 | 27 | } |
17 | 28 | |
18 | - // loads code from the merkle trie and run it | |
19 | - // callHandler (msg, code) { | |
20 | - // const instance = Wasm.instantiateModule(code, interface) | |
21 | - // interface.setModule(instance) | |
22 | - // return instance | |
23 | - // } | |
29 | + // loads code from the merkle trie and delegates the message | |
30 | + static call (path, data, environment) { | |
31 | + // const instance = Wasm.instantiateModule(code, interface) | |
32 | + // interface.setModule(instance) | |
33 | + // return instance | |
34 | + } | |
24 | 35 | |
25 | - // Builtin contracts | |
26 | - // run code | |
27 | - | |
28 | 36 | // run tx |
29 | - // runTx () {} | |
37 | + runTx (tx, environment) { | |
38 | + // verify tx then send to call Handler | |
39 | + this.call(tx, environment) | |
40 | + } | |
30 | 41 | |
31 | 42 | // run block |
32 | - // runBlock () {} | |
43 | + runBlock (block, environment) { | |
44 | + // verify block then run each tx | |
45 | + block.tx.forEach((tx) => { | |
46 | + this.runTx(tx, environment) | |
47 | + }) | |
33 | 48 | |
49 | + } | |
50 | + | |
34 | 51 | // run blockchain |
35 | 52 | // runBlockchain () {} |
36 | 53 | } |
interface.js | ||
---|---|---|
@@ -1,7 +1,11 @@ | ||
1 | +/** | |
2 | + * This is the Ethereum interface that is exposed to the WASM instance which | |
3 | + * enables to interact with the Ethereum Environment | |
4 | + */ | |
1 | 5 | const constants = require('./constants.js') |
2 | 6 | |
3 | -// function.bind is not working corretly whith Wasm imports. So instead create | |
7 | +// function.bind is not working corretly whith Wasm imports. So instead create | |
4 | 8 | // a global for now. TODO REMOVE |
5 | 9 | let ENV |
6 | 10 | let MOD |
7 | 11 | // The interface exposed to the WebAessembly Core |
@@ -13,15 +17,15 @@ | ||
13 | 17 | setModule (mod) { |
14 | 18 | this.module = MOD = mod |
15 | 19 | } |
16 | 20 | |
17 | - debugPrint (a, b) { | |
18 | - console.log(a) | |
19 | - } | |
21 | + // debugPrint (a, b) { | |
22 | + // console.log(a) | |
23 | + // } | |
20 | 24 | |
21 | - memPrint () { | |
22 | - console.log((new Uint8Array(MOD.exports.memory)).toString()) | |
23 | - } | |
25 | + // memPrint () { | |
26 | + // console.log((new Uint8Array(MOD.exports.memory)).toString()) | |
27 | + // } | |
24 | 28 | |
25 | 29 | /** |
26 | 30 | * Subtracts an amount to the gas counter |
27 | 31 | * @param {integer} amount the amount to subtract to the gas counter |
package.json | ||
---|---|---|
@@ -1,14 +1,39 @@ | ||
1 | 1 | { |
2 | - "name": "js-prototype", | |
2 | + "name": "ewams-kernal", | |
3 | 3 | "version": "0.0.0", |
4 | - "description": "", | |
4 | + "description": "This is a JS prototype of the eWASM kernal.", | |
5 | 5 | "scripts": { |
6 | - "test": "tape ./test_runner.js" | |
6 | + "lint": "standard", | |
7 | + "test": "node --expose-wasm ./tests/runner.js" | |
7 | 8 | }, |
9 | + "repository": { | |
10 | + "type": "git", | |
11 | + "url": "git+https://github.com/ethereumjs/ethereumjs-account.git" | |
12 | + }, | |
13 | + "bugs": { | |
14 | + "url": "https://github.com/ethereumjs/ethereumjs-account/issues" | |
15 | + }, | |
16 | + "homepage": "https://github.com/ethereumjs/ethereumjs-account#readme", | |
17 | + "keywords": [ | |
18 | + "ethereum", | |
19 | + "webassebly", | |
20 | + "wasm" | |
21 | + ], | |
8 | 22 | "author": "mjbecze <mjbecze@gmail.com>", |
9 | - "license": "ISC", | |
23 | + "license": "MPL-2.0", | |
24 | + "devDependencies": { | |
25 | + "standard": "^7.1.2", | |
26 | + "tape": "^4.5.1" | |
27 | + }, | |
28 | + "standard": { | |
29 | + "ignore": [ | |
30 | + "/sexpr-wasm-prototype/" | |
31 | + ], | |
32 | + "globals": [ | |
33 | + "Wasm" | |
34 | + ] | |
35 | + }, | |
10 | 36 | "dependencies": { |
11 | - "es6-autobind": "^1.0.2", | |
12 | - "tape": "^4.5.1" | |
37 | + "generic-digraph": "^3.1.0" | |
13 | 38 | } |
14 | 39 | } |
tests/runner.js | ||
---|---|---|
@@ -3,22 +3,22 @@ | ||
3 | 3 | const fs = require('fs') |
4 | 4 | const cp = require('child_process') |
5 | 5 | |
6 | 6 | // This |
7 | -const Environment = require('./environment.js') | |
7 | +const Environment = require('../environment.js') | |
8 | 8 | const Interface = require('../interface.js') |
9 | 9 | // console.log('tes1 11') |
10 | 10 | // get the test names |
11 | -let tests = fs.readdirSync('.').filter((file) => file.endsWith('.wast')) | |
11 | +let tests = fs.readdirSync(__dirname).filter((file) => file.endsWith('.wast')) | |
12 | 12 | // tests = ['balance.wast'] |
13 | 13 | // run the tests |
14 | 14 | for (let testName of tests) { |
15 | 15 | testName = testName.split('.')[0] |
16 | 16 | tape(testName, (t) => { |
17 | 17 | // Compile Command |
18 | - cp.execSync(`../../evm-wasm-transcompiler/deps/sexpr-wasm-prototype/out/sexpr-wasm ./${testName}.wast -o ./${testName}.wasm`) | |
19 | - const buffer = fs.readFileSync(`./${testName}.wasm`) | |
20 | - const envData = fs.readFileSync(`./${testName}.json`) | |
18 | + cp.execSync(`${__dirname}/../../evm-wasm-transcompiler/deps/sexpr-wasm-prototype/out/sexpr-wasm ${__dirname}/${testName}.wast -o ${__dirname}/${testName}.wasm`) | |
19 | + const buffer = fs.readFileSync(`${__dirname}/${testName}.wasm`) | |
20 | + const envData = fs.readFileSync(`${__dirname}/${testName}.json`) | |
21 | 21 | |
22 | 22 | const environment = new Environment(envData) |
23 | 23 | const ethInterface = new Interface(environment) |
24 | 24 |
design.md | ||
---|---|---|
@@ -1,0 +1,53 @@ | ||
1 | +# Architechture | |
2 | + | |
3 | +This prototype attemps to module Ethereum as three seperate but interlocking | |
4 | +layers. Environment, Kernel, and VM | |
5 | + | |
6 | + +------------------+ | |
7 | + | | | |
8 | + | Environment | | |
9 | + | | | |
10 | + +------------------+ | |
11 | + | | |
12 | + +------------------+ | |
13 | + | | | |
14 | + | Kernal | | |
15 | + | | | |
16 | + +------------------+ | |
17 | + | | |
18 | + interfaces | |
19 | + | | |
20 | + +------------------+ | |
21 | + | | | |
22 | + | VM | | |
23 | + | | | |
24 | + +------------------+ | |
25 | + | |
26 | +## VM | |
27 | + | |
28 | +The Vm implements [webassembly](https://github.com/WebAssembly/design). Two | |
29 | +sets of intefaces are exposed to it by the kernal. The Kernal Interface and | |
30 | +The Environment Interface. | |
31 | + | |
32 | +## Kernel Interface | |
33 | + | |
34 | +The kernal handles the following | |
35 | + * Interprocess communication | |
36 | + * Intializing the VM and exposes ROM to it (codeHandler) | |
37 | + * Exposing the namespace and Intializes the Environment which VM instance exists | |
38 | + (callHandler) | |
39 | + * Provides some built in contracts that facilitates different run levels | |
40 | + (runTx, runBlock) | |
41 | + * Provides resource sharing and limiting via gas | |
42 | + | |
43 | +The kernel Interface expose kernal primitives to VM which contain | |
44 | + * IPC (calls) | |
45 | + * Namespace Interface | |
46 | + * GET/PUT/DELETE/ROOT/NEXT - currently implemented as a [digraph](https://github.com/wanderer/generic-digraph/blob/master/docs/index.md) | |
47 | + | |
48 | +## Environment Interface | |
49 | + | |
50 | +The Environment Interface expose the following | |
51 | +* blockchain infromation | |
52 | +* current block infromation | |
53 | +* transaction infromation |
environment.js | ||
---|---|---|
@@ -1,0 +1,103 @@ | ||
1 | +const Graph = require('generic-digraph') | |
2 | +const MAX_BAL_BYTES = require('./constants.js').MAX_BAL_BYTES | |
3 | + | |
4 | +module.exports = class Environment { | |
5 | + constructor (data) { | |
6 | + const defaults = { | |
7 | + gasCounter: 0, // TODO: gasCounter is only 53 bits | |
8 | + gas: 0, // The amount of gas this contract has | |
9 | + gasPrice: 0, | |
10 | + gasLimit: 0, // The gas limit for the block | |
11 | + address: new Uint8Array(20), | |
12 | + origin: new Uint8Array(20), | |
13 | + coinbase: new Uint8Array(20), | |
14 | + difficulty: new Uint8Array(20), | |
15 | + caller: new Uint8Array(20), | |
16 | + callValue: new Uint8Array(MAX_BAL_BYTES), | |
17 | + callData: new ArrayBuffer(), | |
18 | + code: new ArrayBuffer(), // the current running code | |
19 | + logs: [], | |
20 | + returnValue: new ArrayBuffer(), | |
21 | + suicideAddress: new ArrayBuffer(), | |
22 | + accounts: new Map() | |
23 | + } | |
24 | + | |
25 | + if (data) { | |
26 | + data = JSON.parse(data) | |
27 | + Object.assign(this, defaults, data) | |
28 | + } else { | |
29 | + data = {} | |
30 | + } | |
31 | + | |
32 | + if (data.accounts) { | |
33 | + this.accounts = new Graph() | |
34 | + const self = this | |
35 | + debugger | |
36 | + data.accounts.forEach((account) => { | |
37 | + self.accounts.set(new Uint8Array(account[0]).toString(), account[1]) | |
38 | + }) | |
39 | + } | |
40 | + | |
41 | + if (data.address) { | |
42 | + this.address = new Uint8Array(data.address) | |
43 | + } | |
44 | + | |
45 | + if (data.origin) { | |
46 | + this.origin = new Uint8Array(data.origin) | |
47 | + } | |
48 | + | |
49 | + if (data.caller) { | |
50 | + this.caller = new Uint8Array(data.caller) | |
51 | + } | |
52 | + | |
53 | + if (data.callValue) { | |
54 | + this.callValue = new Uint8Array(data.callValue) | |
55 | + } | |
56 | + | |
57 | + if (data.callData) { | |
58 | + this.callData = hexStr2arrayBuf(data.callData) | |
59 | + } | |
60 | + } | |
61 | + | |
62 | + getBalance (address) { | |
63 | + return this.accounts.getValue(address.toString()).balance | |
64 | + } | |
65 | + | |
66 | + getCode (address) { | |
67 | + // STUB | |
68 | + } | |
69 | + | |
70 | + getBlockHash (height) { | |
71 | + // STUB | |
72 | + } | |
73 | + | |
74 | + // kernal | |
75 | + create (code, value) { | |
76 | + // STUB | |
77 | + } | |
78 | + | |
79 | + call (gas, address, value, data) { | |
80 | + // STUB | |
81 | + return // result | |
82 | + } | |
83 | + | |
84 | + delegateCall (gas, address, data) { | |
85 | + // STUB | |
86 | + return // result | |
87 | + } | |
88 | +} | |
89 | + | |
90 | +function hexStr2arrayBuf (string) { | |
91 | + const ab = new ArrayBuffer(string.length / 2) | |
92 | + const view = new Uint8Array(ab) | |
93 | + string = [...string] | |
94 | + let temp = '' | |
95 | + string.forEach((el, i) => { | |
96 | + temp += el | |
97 | + if (i % 2) { | |
98 | + view[(i + 1) / 2 - 1] = parseInt(temp, 16) | |
99 | + temp = '' | |
100 | + } | |
101 | + }) | |
102 | + return ab | |
103 | +} |
Built with git-ssb-web