UNPKG

int-cli

Version:

INT is the new generation of bottom-up created system of IoT and blockchain

187 lines (186 loc) 7.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const assert = require('assert'); const error_code_1 = require("../error_code"); const chain_1 = require("../chain"); const util_1 = require("util"); const client_1 = require("../../client"); const { LogShim } = require('../lib/log_shim'); class BaseExecutor { constructor(options) { this.m_logs = []; this.m_logger = options.logger; this.m_eventDefinations = options.eventDefinations; } async prepareContext(blockHeader, storage, externContext) { let database = (await storage.getReadWritableDatabase(chain_1.Chain.dbUser)).value; let context = Object.create(externContext); // context.getNow = (): number => { // return blockHeader.timestamp; // }; Object.defineProperty(context, 'now', { writable: false, value: blockHeader.timestamp }); Object.defineProperty(context, 'height', { writable: false, value: blockHeader.number }); Object.defineProperty(context, 'storage', { writable: false, value: database }); context.emit = (name, param) => { if (this.m_eventDefinations.has(name)) { let log = new chain_1.EventLog(); log.name = name; log.param = param; this.m_logs.push(log); } else { this.m_logger.error(`undefined event ${name}`); assert(false, `undefined event ${name}`); } }; return context; } } class TransactionExecutor extends BaseExecutor { constructor(handler, listener, tx, logger) { super({ eventDefinations: handler.getEventDefinations(), logger: new LogShim(logger).bind(`[transaction: ${tx.hash}]`, true).log }); this.m_addrIndex = 0; this.m_listener = listener; this.m_tx = tx; } async _dealNonce(tx, storage) { // 检查nonce let kvr = await storage.getKeyValue(chain_1.Chain.dbSystem, chain_1.Chain.kvNonce); if (kvr.err !== error_code_1.ErrorCode.RESULT_OK) { this.m_logger.error(`methodexecutor, _dealNonce, getReadWritableKeyValue failed`); return kvr.err; } let nonce = -1; let nonceInfo = await kvr.kv.get(tx.address); if (nonceInfo.err === error_code_1.ErrorCode.RESULT_OK) { nonce = nonceInfo.value; } if (tx.nonce !== nonce + 1) { this.m_logger.error(`methodexecutor, _dealNonce, nonce error,nonce should ${nonce + 1}, but ${tx.nonce}, txhash=${tx.hash} address=${tx.address}`); return error_code_1.ErrorCode.RESULT_ERROR_NONCE_IN_TX; } await kvr.kv.set(tx.address, tx.nonce); return error_code_1.ErrorCode.RESULT_OK; } async execute(blockHeader, storage, externContext, flag) { if (!(flag && flag.ignoreNoce)) { let nonceErr = await this._dealNonce(this.m_tx, storage); if (nonceErr !== error_code_1.ErrorCode.RESULT_OK) { return { err: nonceErr }; } } let context = await this.prepareContext(blockHeader, storage, externContext); let receipt = new chain_1.Receipt(); let work = await storage.beginTransaction(); if (work.err) { this.m_logger.error(`methodexecutor, beginTransaction error,storagefile=${storage.filePath}`); return { err: work.err }; } receipt.returnCode = await this._execute(context, this.m_tx.input); assert(util_1.isNumber(receipt.returnCode), `invalid handler return code ${receipt.returnCode}`); if (!util_1.isNumber(receipt.returnCode)) { this.m_logger.error(`methodexecutor failed for invalid handler return code type, return=`, receipt.returnCode); return { err: error_code_1.ErrorCode.RESULT_INVALID_PARAM }; } receipt.setSource({ sourceType: chain_1.ReceiptSourceType.transaction, txHash: this.m_tx.hash }); if (receipt.returnCode) { this.m_logger.warn(`handler return code=${receipt.returnCode}, will rollback storage`); await work.value.rollback(); } else { this.m_logger.debug(`handler return code ${receipt.returnCode}, will commit storage`); let err = await work.value.commit(); if (err) { this.m_logger.error(`methodexecutor, transaction commit error, err=${err}, storagefile=${storage.filePath}`); return { err }; } receipt.eventLogs = this.m_logs; } return { err: error_code_1.ErrorCode.RESULT_OK, receipt }; } async _execute(env, input) { try { this.m_logger.debug(`will execute tx ${this.m_tx.hash}: ${this.m_tx.method},from ${this.m_tx.address}, params ${JSON.stringify(this.m_tx.input)}`); return await this.m_listener(env, this.m_tx.input); } catch (e) { this.m_logger.error(`execute method linstener e=`, e.stack); return error_code_1.ErrorCode.RESULT_EXECUTE_ERROR; } } async prepareContext(blockHeader, storage, externContext) { let context = await super.prepareContext(blockHeader, storage, externContext); // 执行上下文 Object.defineProperty(context, 'caller', { writable: false, value: this.m_tx.address }); context.createAddress = () => { let buf = Buffer.from(this.m_tx.address + this.m_tx.nonce + this.m_addrIndex); this.m_addrIndex++; return client_1.addressFromPublicKey(buf); }; return context; } } exports.TransactionExecutor = TransactionExecutor; class EventExecutor extends BaseExecutor { constructor(handler, listener, logger) { super({ eventDefinations: handler.getEventDefinations(), logger }); this.m_bBeforeBlockExec = true; this.m_listener = listener; } async execute(blockHeader, storage, externalContext) { this.m_logger.debug(`execute event on ${blockHeader.number}`); let context = await this.prepareContext(blockHeader, storage, externalContext); let work = await storage.beginTransaction(); if (work.err) { this.m_logger.error(`eventexecutor, beginTransaction error,storagefile=${storage.filePath}`); return { err: work.err }; } let receipt = new chain_1.Receipt(); let returnCode; try { returnCode = await this.m_listener(context); } catch (e) { this.m_logger.error(`execute event linstener error, e=`, e); returnCode = error_code_1.ErrorCode.RESULT_EXCEPTION; } assert(util_1.isNumber(returnCode), `event handler return code invalid ${returnCode}`); if (!util_1.isNumber(returnCode)) { this.m_logger.error(`execute event failed for invalid return code`); returnCode = error_code_1.ErrorCode.RESULT_INVALID_PARAM; } receipt.returnCode = returnCode; if (receipt.returnCode === error_code_1.ErrorCode.RESULT_OK) { this.m_logger.debug(`event handler commit storage`); let err = await work.value.commit(); if (err) { this.m_logger.error(`eventexecutor, transaction commit error,storagefile=${storage.filePath}`); return { err }; } } else { this.m_logger.debug(`event handler return code ${returnCode} rollback storage`); await work.value.rollback(); } return { err: error_code_1.ErrorCode.RESULT_OK, receipt }; } } exports.EventExecutor = EventExecutor;