1 | "use strict";
|
2 | var __assign = (this && this.__assign) || function () {
|
3 | __assign = Object.assign || function(t) {
|
4 | for (var s, i = 1, n = arguments.length; i < n; i++) {
|
5 | s = arguments[i];
|
6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
7 | t[p] = s[p];
|
8 | }
|
9 | return t;
|
10 | };
|
11 | return __assign.apply(this, arguments);
|
12 | };
|
13 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
14 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
15 | return new (P || (P = Promise))(function (resolve, reject) {
|
16 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
17 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
18 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
19 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
20 | });
|
21 | };
|
22 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
23 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
24 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
25 | function verb(n) { return function (v) { return step([n, v]); }; }
|
26 | function step(op) {
|
27 | if (f) throw new TypeError("Generator is already executing.");
|
28 | while (_) try {
|
29 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
30 | if (y = 0, t) op = [op[0] & 2, t.value];
|
31 | switch (op[0]) {
|
32 | case 0: case 1: t = op; break;
|
33 | case 4: _.label++; return { value: op[1], done: false };
|
34 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
35 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
36 | default:
|
37 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
38 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
39 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
40 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
41 | if (t[2]) _.ops.pop();
|
42 | _.trys.pop(); continue;
|
43 | }
|
44 | op = body.call(thisArg, _);
|
45 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
46 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
47 | }
|
48 | };
|
49 | Object.defineProperty(exports, "__esModule", { value: true });
|
50 | var BN = require("bn.js");
|
51 | var ethereumjs_util_1 = require("ethereumjs-util");
|
52 | var exceptions_1 = require("../exceptions");
|
53 | var message_1 = require("./message");
|
54 | var promisify = require('util.promisify');
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | var EEI = (function () {
|
64 | function EEI(env, state, evm, common, gasLeft) {
|
65 | this._env = env;
|
66 | this._state = state;
|
67 | this._evm = evm;
|
68 | this._lastReturned = Buffer.alloc(0);
|
69 | this._common = common;
|
70 | this._gasLeft = gasLeft;
|
71 | this._result = {
|
72 | logs: [],
|
73 | returnValue: undefined,
|
74 | selfdestruct: {},
|
75 | };
|
76 | }
|
77 | |
78 |
|
79 |
|
80 |
|
81 |
|
82 | EEI.prototype.useGas = function (amount) {
|
83 | this._gasLeft.isub(amount);
|
84 | if (this._gasLeft.ltn(0)) {
|
85 | this._gasLeft = new BN(0);
|
86 | trap(exceptions_1.ERROR.OUT_OF_GAS);
|
87 | }
|
88 | };
|
89 | |
90 |
|
91 |
|
92 |
|
93 | EEI.prototype.refundGas = function (amount) {
|
94 | this._evm._refund.iadd(amount);
|
95 | };
|
96 | |
97 |
|
98 |
|
99 |
|
100 | EEI.prototype.subRefund = function (amount) {
|
101 | this._evm._refund.isub(amount);
|
102 | if (this._evm._refund.ltn(0)) {
|
103 | this._evm._refund = new BN(0);
|
104 | trap(exceptions_1.ERROR.REFUND_EXHAUSTED);
|
105 | }
|
106 | };
|
107 | |
108 |
|
109 |
|
110 | EEI.prototype.getAddress = function () {
|
111 | return this._env.address;
|
112 | };
|
113 | |
114 |
|
115 |
|
116 |
|
117 | EEI.prototype.getExternalBalance = function (address) {
|
118 | return __awaiter(this, void 0, void 0, function () {
|
119 | var account;
|
120 | return __generator(this, function (_a) {
|
121 | switch (_a.label) {
|
122 | case 0:
|
123 |
|
124 | if (address.toString('hex') === this._env.address.toString('hex')) {
|
125 | return [2 , new BN(this._env.contract.balance)];
|
126 | }
|
127 | return [4 , this._state.getAccount(address)];
|
128 | case 1:
|
129 | account = _a.sent();
|
130 | return [2 , new BN(account.balance)];
|
131 | }
|
132 | });
|
133 | });
|
134 | };
|
135 | |
136 |
|
137 |
|
138 | EEI.prototype.getSelfBalance = function () {
|
139 | return new BN(this._env.contract.balance);
|
140 | };
|
141 | |
142 |
|
143 |
|
144 |
|
145 | EEI.prototype.getCaller = function () {
|
146 | return new BN(this._env.caller);
|
147 | };
|
148 | |
149 |
|
150 |
|
151 |
|
152 | EEI.prototype.getCallValue = function () {
|
153 | return new BN(this._env.callValue);
|
154 | };
|
155 | |
156 |
|
157 |
|
158 |
|
159 | EEI.prototype.getCallData = function () {
|
160 | return this._env.callData;
|
161 | };
|
162 | |
163 |
|
164 |
|
165 |
|
166 | EEI.prototype.getCallDataSize = function () {
|
167 | return new BN(this._env.callData.length);
|
168 | };
|
169 | |
170 |
|
171 |
|
172 | EEI.prototype.getCodeSize = function () {
|
173 | return new BN(this._env.code.length);
|
174 | };
|
175 | |
176 |
|
177 |
|
178 | EEI.prototype.getCode = function () {
|
179 | return this._env.code;
|
180 | };
|
181 | |
182 |
|
183 |
|
184 | EEI.prototype.isStatic = function () {
|
185 | return this._env.isStatic;
|
186 | };
|
187 | |
188 |
|
189 |
|
190 |
|
191 | EEI.prototype.getExternalCodeSize = function (address) {
|
192 | return __awaiter(this, void 0, void 0, function () {
|
193 | var addressBuf, code;
|
194 | return __generator(this, function (_a) {
|
195 | switch (_a.label) {
|
196 | case 0:
|
197 | addressBuf = addressToBuffer(address);
|
198 | return [4 , this._state.getContractCode(addressBuf)];
|
199 | case 1:
|
200 | code = _a.sent();
|
201 | return [2 , new BN(code.length)];
|
202 | }
|
203 | });
|
204 | });
|
205 | };
|
206 | |
207 |
|
208 |
|
209 |
|
210 | EEI.prototype.getExternalCode = function (address) {
|
211 | return __awaiter(this, void 0, void 0, function () {
|
212 | return __generator(this, function (_a) {
|
213 | if (!Buffer.isBuffer(address)) {
|
214 | address = addressToBuffer(address);
|
215 | }
|
216 | return [2 , this._state.getContractCode(address)];
|
217 | });
|
218 | });
|
219 | };
|
220 | |
221 |
|
222 |
|
223 |
|
224 |
|
225 | EEI.prototype.getReturnDataSize = function () {
|
226 | return new BN(this._lastReturned.length);
|
227 | };
|
228 | |
229 |
|
230 |
|
231 |
|
232 |
|
233 | EEI.prototype.getReturnData = function () {
|
234 | return this._lastReturned;
|
235 | };
|
236 | |
237 |
|
238 |
|
239 | EEI.prototype.getTxGasPrice = function () {
|
240 | return new BN(this._env.gasPrice);
|
241 | };
|
242 | |
243 |
|
244 |
|
245 |
|
246 |
|
247 | EEI.prototype.getTxOrigin = function () {
|
248 | return new BN(this._env.origin);
|
249 | };
|
250 | |
251 |
|
252 |
|
253 | EEI.prototype.getBlockNumber = function () {
|
254 | return new BN(this._env.block.header.number);
|
255 | };
|
256 | |
257 |
|
258 |
|
259 | EEI.prototype.getBlockCoinbase = function () {
|
260 | return new BN(this._env.block.header.coinbase);
|
261 | };
|
262 | |
263 |
|
264 |
|
265 | EEI.prototype.getBlockTimestamp = function () {
|
266 | return new BN(this._env.block.header.timestamp);
|
267 | };
|
268 | |
269 |
|
270 |
|
271 | EEI.prototype.getBlockDifficulty = function () {
|
272 | return new BN(this._env.block.header.difficulty);
|
273 | };
|
274 | |
275 |
|
276 |
|
277 | EEI.prototype.getBlockGasLimit = function () {
|
278 | return new BN(this._env.block.header.gasLimit);
|
279 | };
|
280 | |
281 |
|
282 |
|
283 |
|
284 | EEI.prototype.getChainId = function () {
|
285 | return new BN(this._common.chainId());
|
286 | };
|
287 | |
288 |
|
289 |
|
290 |
|
291 | EEI.prototype.getBlockHash = function (num) {
|
292 | return __awaiter(this, void 0, void 0, function () {
|
293 | var block;
|
294 | return __generator(this, function (_a) {
|
295 | switch (_a.label) {
|
296 | case 0: return [4 , promisify(this._env.blockchain.getBlock).bind(this._env.blockchain)(num)];
|
297 | case 1:
|
298 | block = _a.sent();
|
299 | return [2 , new BN(block.hash())];
|
300 | }
|
301 | });
|
302 | });
|
303 | };
|
304 | |
305 |
|
306 |
|
307 | EEI.prototype.storageStore = function (key, value) {
|
308 | return __awaiter(this, void 0, void 0, function () {
|
309 | var account;
|
310 | return __generator(this, function (_a) {
|
311 | switch (_a.label) {
|
312 | case 0: return [4 , this._state.putContractStorage(this._env.address, key, value)];
|
313 | case 1:
|
314 | _a.sent();
|
315 | return [4 , this._state.getAccount(this._env.address)];
|
316 | case 2:
|
317 | account = _a.sent();
|
318 | this._env.contract = account;
|
319 | return [2 ];
|
320 | }
|
321 | });
|
322 | });
|
323 | };
|
324 | |
325 |
|
326 |
|
327 |
|
328 | EEI.prototype.storageLoad = function (key) {
|
329 | return __awaiter(this, void 0, void 0, function () {
|
330 | return __generator(this, function (_a) {
|
331 | return [2 , this._state.getContractStorage(this._env.address, key)];
|
332 | });
|
333 | });
|
334 | };
|
335 | |
336 |
|
337 |
|
338 | EEI.prototype.getGasLeft = function () {
|
339 | return this._gasLeft.clone();
|
340 | };
|
341 | |
342 |
|
343 |
|
344 |
|
345 | EEI.prototype.finish = function (returnData) {
|
346 | this._result.returnValue = returnData;
|
347 | trap(exceptions_1.ERROR.STOP);
|
348 | };
|
349 | |
350 |
|
351 |
|
352 |
|
353 |
|
354 | EEI.prototype.revert = function (returnData) {
|
355 | this._result.returnValue = returnData;
|
356 | trap(exceptions_1.ERROR.REVERT);
|
357 | };
|
358 | |
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 | EEI.prototype.selfDestruct = function (toAddress) {
|
365 | return __awaiter(this, void 0, void 0, function () {
|
366 | return __generator(this, function (_a) {
|
367 | return [2 , this._selfDestruct(toAddress)];
|
368 | });
|
369 | });
|
370 | };
|
371 | EEI.prototype._selfDestruct = function (toAddress) {
|
372 | return __awaiter(this, void 0, void 0, function () {
|
373 | var toAccount, newBalance, account;
|
374 | return __generator(this, function (_a) {
|
375 | switch (_a.label) {
|
376 | case 0:
|
377 |
|
378 | if (!this._result.selfdestruct[this._env.address.toString('hex')]) {
|
379 | this.refundGas(new BN(this._common.param('gasPrices', 'selfdestructRefund')));
|
380 | }
|
381 | this._result.selfdestruct[this._env.address.toString('hex')] = toAddress;
|
382 | return [4 , this._state.getAccount(toAddress)];
|
383 | case 1:
|
384 | toAccount = _a.sent();
|
385 | newBalance = new BN(this._env.contract.balance).add(new BN(toAccount.balance));
|
386 | toAccount.balance = ethereumjs_util_1.toBuffer(newBalance);
|
387 | return [4 , this._state.putAccount(toAddress, toAccount)
|
388 |
|
389 | ];
|
390 | case 2:
|
391 | _a.sent();
|
392 | return [4 , this._state.getAccount(this._env.address)];
|
393 | case 3:
|
394 | account = _a.sent();
|
395 | account.balance = ethereumjs_util_1.toBuffer(new BN(0));
|
396 | return [4 , this._state.putAccount(this._env.address, account)];
|
397 | case 4:
|
398 | _a.sent();
|
399 | trap(exceptions_1.ERROR.STOP);
|
400 | return [2 ];
|
401 | }
|
402 | });
|
403 | });
|
404 | };
|
405 | |
406 |
|
407 |
|
408 | EEI.prototype.log = function (data, numberOfTopics, topics) {
|
409 | if (numberOfTopics < 0 || numberOfTopics > 4) {
|
410 | trap(exceptions_1.ERROR.OUT_OF_RANGE);
|
411 | }
|
412 | if (topics.length !== numberOfTopics) {
|
413 | trap(exceptions_1.ERROR.INTERNAL_ERROR);
|
414 | }
|
415 |
|
416 | var log = [this._env.address];
|
417 | log.push(topics);
|
418 |
|
419 | log.push(data);
|
420 | this._result.logs.push(log);
|
421 | };
|
422 | |
423 |
|
424 |
|
425 | EEI.prototype.call = function (gasLimit, address, value, data) {
|
426 | return __awaiter(this, void 0, void 0, function () {
|
427 | var msg;
|
428 | return __generator(this, function (_a) {
|
429 | msg = new message_1.default({
|
430 | caller: this._env.address,
|
431 | gasLimit: gasLimit,
|
432 | to: address,
|
433 | value: value,
|
434 | data: data,
|
435 | isStatic: this._env.isStatic,
|
436 | depth: this._env.depth + 1,
|
437 | });
|
438 | return [2 , this._baseCall(msg)];
|
439 | });
|
440 | });
|
441 | };
|
442 | |
443 |
|
444 |
|
445 | EEI.prototype.callCode = function (gasLimit, address, value, data) {
|
446 | return __awaiter(this, void 0, void 0, function () {
|
447 | var msg;
|
448 | return __generator(this, function (_a) {
|
449 | msg = new message_1.default({
|
450 | caller: this._env.address,
|
451 | gasLimit: gasLimit,
|
452 | to: this._env.address,
|
453 | codeAddress: address,
|
454 | value: value,
|
455 | data: data,
|
456 | isStatic: this._env.isStatic,
|
457 | depth: this._env.depth + 1,
|
458 | });
|
459 | return [2 , this._baseCall(msg)];
|
460 | });
|
461 | });
|
462 | };
|
463 | |
464 |
|
465 |
|
466 |
|
467 |
|
468 | EEI.prototype.callStatic = function (gasLimit, address, value, data) {
|
469 | return __awaiter(this, void 0, void 0, function () {
|
470 | var msg;
|
471 | return __generator(this, function (_a) {
|
472 | msg = new message_1.default({
|
473 | caller: this._env.address,
|
474 | gasLimit: gasLimit,
|
475 | to: address,
|
476 | value: value,
|
477 | data: data,
|
478 | isStatic: true,
|
479 | depth: this._env.depth + 1,
|
480 | });
|
481 | return [2 , this._baseCall(msg)];
|
482 | });
|
483 | });
|
484 | };
|
485 | |
486 |
|
487 |
|
488 |
|
489 | EEI.prototype.callDelegate = function (gasLimit, address, value, data) {
|
490 | return __awaiter(this, void 0, void 0, function () {
|
491 | var msg;
|
492 | return __generator(this, function (_a) {
|
493 | msg = new message_1.default({
|
494 | caller: this._env.caller,
|
495 | gasLimit: gasLimit,
|
496 | to: this._env.address,
|
497 | codeAddress: address,
|
498 | value: value,
|
499 | data: data,
|
500 | isStatic: this._env.isStatic,
|
501 | delegatecall: true,
|
502 | depth: this._env.depth + 1,
|
503 | });
|
504 | return [2 , this._baseCall(msg)];
|
505 | });
|
506 | });
|
507 | };
|
508 | EEI.prototype._baseCall = function (msg) {
|
509 | return __awaiter(this, void 0, void 0, function () {
|
510 | var selfdestruct, results, account;
|
511 | return __generator(this, function (_a) {
|
512 | switch (_a.label) {
|
513 | case 0:
|
514 | selfdestruct = __assign({}, this._result.selfdestruct);
|
515 | msg.selfdestruct = selfdestruct;
|
516 |
|
517 | this._lastReturned = Buffer.alloc(0);
|
518 |
|
519 | if (this._env.depth >= this._common.param('vm', 'stackLimit') ||
|
520 | (msg.delegatecall !== true && new BN(this._env.contract.balance).lt(msg.value))) {
|
521 | return [2 , new BN(0)];
|
522 | }
|
523 | return [4 , this._evm.executeMessage(msg)];
|
524 | case 1:
|
525 | results = _a.sent();
|
526 | if (results.execResult.logs) {
|
527 | this._result.logs = this._result.logs.concat(results.execResult.logs);
|
528 | }
|
529 |
|
530 | this.useGas(results.gasUsed);
|
531 |
|
532 | if (results.execResult.returnValue &&
|
533 | (!results.execResult.exceptionError ||
|
534 | results.execResult.exceptionError.error === exceptions_1.ERROR.REVERT)) {
|
535 | this._lastReturned = results.execResult.returnValue;
|
536 | }
|
537 | if (!!results.execResult.exceptionError) return [3 , 3];
|
538 | Object.assign(this._result.selfdestruct, selfdestruct);
|
539 | return [4 , this._state.getAccount(this._env.address)];
|
540 | case 2:
|
541 | account = _a.sent();
|
542 | this._env.contract = account;
|
543 | _a.label = 3;
|
544 | case 3: return [2 , this._getReturnCode(results)];
|
545 | }
|
546 | });
|
547 | });
|
548 | };
|
549 | |
550 |
|
551 |
|
552 | EEI.prototype.create = function (gasLimit, value, data, salt) {
|
553 | if (salt === void 0) { salt = null; }
|
554 | return __awaiter(this, void 0, void 0, function () {
|
555 | var selfdestruct, msg, results, account;
|
556 | return __generator(this, function (_a) {
|
557 | switch (_a.label) {
|
558 | case 0:
|
559 | selfdestruct = __assign({}, this._result.selfdestruct);
|
560 | msg = new message_1.default({
|
561 | caller: this._env.address,
|
562 | gasLimit: gasLimit,
|
563 | value: value,
|
564 | data: data,
|
565 | salt: salt,
|
566 | depth: this._env.depth + 1,
|
567 | selfdestruct: selfdestruct,
|
568 | });
|
569 |
|
570 | this._lastReturned = Buffer.alloc(0);
|
571 |
|
572 | if (this._env.depth >= this._common.param('vm', 'stackLimit') ||
|
573 | (msg.delegatecall !== true && new BN(this._env.contract.balance).lt(msg.value))) {
|
574 | return [2 , new BN(0)];
|
575 | }
|
576 | this._env.contract.nonce = ethereumjs_util_1.toBuffer(new BN(this._env.contract.nonce).addn(1));
|
577 | return [4 , this._state.putAccount(this._env.address, this._env.contract)];
|
578 | case 1:
|
579 | _a.sent();
|
580 | return [4 , this._evm.executeMessage(msg)];
|
581 | case 2:
|
582 | results = _a.sent();
|
583 | if (results.execResult.logs) {
|
584 | this._result.logs = this._result.logs.concat(results.execResult.logs);
|
585 | }
|
586 |
|
587 | this.useGas(results.gasUsed);
|
588 |
|
589 | if (results.execResult.exceptionError &&
|
590 | results.execResult.exceptionError.error === exceptions_1.ERROR.REVERT) {
|
591 | this._lastReturned = results.execResult.returnValue;
|
592 | }
|
593 | if (!!results.execResult.exceptionError) return [3 , 4];
|
594 | Object.assign(this._result.selfdestruct, selfdestruct);
|
595 | return [4 , this._state.getAccount(this._env.address)];
|
596 | case 3:
|
597 | account = _a.sent();
|
598 | this._env.contract = account;
|
599 | if (results.createdAddress) {
|
600 |
|
601 | return [2 , new BN(results.createdAddress)];
|
602 | }
|
603 | _a.label = 4;
|
604 | case 4: return [2 , this._getReturnCode(results)];
|
605 | }
|
606 | });
|
607 | });
|
608 | };
|
609 | |
610 |
|
611 |
|
612 |
|
613 | EEI.prototype.create2 = function (gasLimit, value, data, salt) {
|
614 | return __awaiter(this, void 0, void 0, function () {
|
615 | return __generator(this, function (_a) {
|
616 | return [2 , this.create(gasLimit, value, data, salt)];
|
617 | });
|
618 | });
|
619 | };
|
620 | |
621 |
|
622 |
|
623 |
|
624 | EEI.prototype.isAccountEmpty = function (address) {
|
625 | return __awaiter(this, void 0, void 0, function () {
|
626 | return __generator(this, function (_a) {
|
627 | return [2 , this._state.accountIsEmpty(address)];
|
628 | });
|
629 | });
|
630 | };
|
631 | EEI.prototype._getReturnCode = function (results) {
|
632 |
|
633 |
|
634 | if (results.execResult.exceptionError) {
|
635 | return new BN(0);
|
636 | }
|
637 | else {
|
638 | return new BN(1);
|
639 | }
|
640 | };
|
641 | return EEI;
|
642 | }());
|
643 | exports.default = EEI;
|
644 | function trap(err) {
|
645 | throw new exceptions_1.VmError(err);
|
646 | }
|
647 | var MASK_160 = new BN(1).shln(160).subn(1);
|
648 | function addressToBuffer(address) {
|
649 | if (Buffer.isBuffer(address))
|
650 | return address;
|
651 | return address.and(MASK_160).toArrayLike(Buffer, 'be', 20);
|
652 | }
|
653 |
|
\ | No newline at end of file |