git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: dbb9b6eacbc6786a69bbe76a01aa4fb1d930ff18

Files: dbb9b6eacbc6786a69bbe76a01aa4fb1d930ff18 / index.js

5381 bytesRaw
1/**
2 * This implements the Ethereum Kernel
3 * Kernels must implement two methods `codeHandler` and `callHandler` (and `linkHandler` for sharding)
4 * The Kernel Contract handles the following
5 * - Interprocess communications
6 * - Intializing the VM and exposes ROM to it (codeHandler)
7 * - Expose namespace which VM instance exists and Intializes the Environment (callHandler)
8 * - Provides some built in contract (runTx, runBlock)
9 * - Provides resource sharing and limiting via gas
10 *
11 * All State should be stored in the Environment.
12 *
13 */
14
15// The Kernel Exposes this Interface to VM instances it makes
16const Interface = require('./interface.js')
17
18// The Kernel Stores all of its state in the Environment. The Interface is used
19// to by the VM to retrive infromation from the Environment.
20const Environment = require('./environment.js')
21
22const DebugInterface = require('./debugInterface.js')
23
24const Address = require('./address.js')
25const U256 = require('./u256.js')
26const Utils = require('./utils.js')
27
28module.exports = class Kernel {
29 // runs some code in the VM
30 constructor (environment = new Environment()) {
31 this.environment = environment
32 }
33
34 // handles running code.
35 // NOTE: it assumes that wasm will raise an exception if something went wrong,
36 // otherwise execution succeeded
37 codeHandler (code, ethInterface = new Interface(new Environment())) {
38 const debugInterface = new DebugInterface(ethInterface.environment)
39
40 const instance = Wasm.instantiateModule(code, {
41 'ethereum': ethInterface.exportTable,
42 'debug': debugInterface.exportTable,
43
44 // export this for Rust
45 // FIXME: remove once Rust has proper imports, see https://github.com/ethereum/evm2.0-design/issues/15
46 'spectest': ethInterface.exportTable,
47
48 // export this for Binaryen
49 // FIXME: remove once C has proper imports, see https://github.com/ethereum/evm2.0-design/issues/16
50 'env': ethInterface.exportTable
51 })
52
53 ethInterface.setModule(instance)
54 debugInterface.setModule(instance)
55
56 if (instance.exports.main) {
57 instance.exports.main()
58 }
59 return instance
60 }
61
62 // loads code from the merkle trie and delegates the message
63 // Detects if code is EVM or WASM
64 // Detects if the code injection is needed
65 // Detects if transcompilation is needed
66 callHandler (address, gaslimit, gasprice, value, data) {
67 // Special case: contract deployment
68 // FIXME: place this in the best location with the best condition checking
69 if (address.isZero()) {
70 if (data.length !== 0) {
71 let codeHash = sha3(data)
72 this.environment.state.set(codeHash, data);
73 this.environment.state.set(address.toString(), { balance: value, codeHash: codeHash })
74 }
75 }
76
77 let account = this.environment.state.get(address.toString())
78 if (!account) {
79 throw new Error('Account not found')
80 }
81
82 const code = this.environment.state.get(account.codeHash)
83
84 if (!code) {
85 throw new Error('Contract not found')
86 }
87
88 if (!Utils.isWASMCode(code)) {
89 throw new Error('Not an eWASM contract')
90 }
91
92 // creats a new Kernel
93 const environment = new Environment(data)
94 environment.parent = this
95
96 //environment.setCallHandler(callHandler)
97
98 const kernel = new Kernel(this, environment)
99 kernel.codeHandler(code, new Interface(environment))
100
101 // generate new stateroot
102 //this.environment.state.set(address, { stateRoot: stateRoot })
103
104 return {
105 executionOutcome: 1, // success
106 gasLeft: new U256(environment.gasLimit), // this starts as the limit and results as the gas left
107 gasRefund: new U256(environment.gasRefund),
108 returnValue: environment.returnValue,
109 selfDestructAddress: environment.selfDestructAddress,
110 logs: environment.logs
111 }
112 }
113
114 // run tx; the tx message handler
115 runTx (tx, environment = new Environment()) {
116 // verify tx then send to call Handler
117 // - from account has enough balance
118 // - check nonce
119 // - ecrecover
120 // new ethTx(tx).validate(tx)
121 // - reduce balance
122
123 this.environment = environment
124
125 //
126 // environment.state - the merkle tree
127 // key: address (20 byte, hex string, without 0x prefix)
128 // every path has an account
129 //
130 // { balance, codeHash, stateRoot }
131 //
132
133 // look up sender
134 let fromAccount = this.environment.state.get(tx.from.toString())
135 if (!fromAccount) {
136 throw new Error('Sender account not found')
137 }
138
139 // deduct gasLimit * gasPrice from sender
140 if (fromAccount.balance.lt(tx.gasLimit.mul(tx.gasPrice))) {
141 throw new Error('Insufficient account balance')
142 }
143
144 fromAccount.balance = fromAccount.balance.sub(ts.gasLimit.mul(tx.gasPrice))
145
146 let ret = this.callHandler(tx.to, tx.gasLimit, tx.gasPrice, tx.value, tx.data)
147
148 // refund gas
149 if (ret.executionOutcome === 1) {
150 fromAccount.balance = fromAccount.balance.add(tx.gasPrice.mul(ret.gasLeft.add(ret.gasRefund)))
151 }
152
153 // save new state?
154
155 return {
156 returnValue: ret.returnValue,
157 gasLeft: ret.gasLeft,
158 logs: ret.logs
159 }
160 }
161
162 // run block; the block message handler
163 runBlock (block, environment = new Environment()) {
164 // verify block then run each tx
165 block.tx.forEach((tx) => {
166 this.runTx(tx, environment)
167 })
168 }
169
170 // run blockchain
171 // runBlockchain () {}
172}
173

Built with git-ssb-web