const util = require('util'); const Web3 = require('web3'); const metamgr = require('./metamgr'); const utils = require('./utils'); const sync = require("./sync"); const log = require("./log"); const C = require("./C"); const dbhelper = require("./dbhelper"); class BlockChain { constructor() { this.savedFirstBlockNumber = false; this.firstBlockNumber = 0; this.initedBlockNumber = false; this.initBlockNumber = 0; this.currBlockNumber = 0; this.refreshCond = new sync.Cond(); this.lastRefreshTime = utils.getUtcTime(); this.actived = false; this.lockTimes = 0; } async initInstance(user, address, jsonUrl) { const json = utils.readJsonFromFile(jsonUrl); return new this.web3.eth.Contract( json.abi, address, { from: user } ); } async init() { this.web3 = new Web3(metamgr.getWeb3Conf()['block_server']); this.web3.eth.handleRevert = true; this.web3.eth.accounts.wallet.add(metamgr.getPrivateKey()); for (const data of metamgr.getContracts()) { this[`${data.name}Instance`] = await this.initInstance (metamgr.getUserAddress(), data.address, data.json); } setTimeout(this.refreshBlockNumber.bind(this), 1000 * 0.01); setTimeout(this.serializeBlockNumber.bind(this), 1000); setTimeout(this.serializeFirstBlockNumber.bind(this), 1000); await this.mustBeActive(); utils.emitEvent(C.BC_INITIALIZED_EVENT); } async mustBeActive() { while (!this.actived) { await utils.sleep(1000); } } async refreshBlockNumber() { const logClass = 'refreshBlockNumber'; while (true) { try { this.currBlockNumber = await this.web3.eth.getBlockNumber(); this.actived = true; this.lastRefreshTime = utils.getUtcTime(); if (!this.initedBlockNumber) { this.initedBlockNumber = true; this.initBlockNumber = this.currBlockNumber; } } catch (e) { this.actived = false; log.warning(util.format('%s err:%s', logClass, e )); } await this.refreshCond.wait(1000 * 3); } } async serializeBlockNumber() { const logClass = 'serializeBlockNumber'; while (true) { log.info(util.format('%s currBlockNumber:%s firstBlockNumber:%s actived:%s', logClass, this.getCurrBlockNumber(), this.firstBlockNumber, this.actived )); dbhelper.insert('t_block_number', [ ['block_number', this.getCurrBlockNumber()], ['createtime', utils.getUtcTime()], ['modifytime', utils.getUtcTime()], ]); await utils.sleep(1000 * 10); } } async serializeFirstBlockNumber() { const logClass = 'serializeFirstBlockNumber'; while (!this.savedFirstBlockNumber) { try { if (this.initedBlockNumber) { const {err, row} = await dbhelper.ormSelectOne( 't_parameter', [ ['name', 'first_block_number'] ]); if (err) { throw err; } else { if (row) { this.savedFirstBlockNumber = true; this.firstBlockNumber = '' + row['value']; } else { const err = await dbhelper.insert( 't_parameter', [ ['name', 'first_block_number'], ['value', this.initBlockNumber], ] ); if (err) { throw err; } } } } } catch(e) { log.warning(util.format('%s err:%s', logClass, e )); } await utils.sleep(1000 * 1); } } isComfirmed(blockNumber) { const logClass = 'isComfirmed'; try { return Number(blockNumber) + 6 < Number(this.getCurrBlockNumber()); } catch (e) { log.warning(util.format('%s err:%s', logClass, e )); } return false; } getCurrBlockNumber() { return this.currBlockNumber; } async lock() { while (this.lockTimes > 0) { await utils.sleep(100); } ++this.lockTimes; } async unLock() { --this.lockTimes; } async getFirstBlockNumber() { while (!this.savedFirstBlockNumber) { await utils.sleep(1000 * 1); } return this.firstBlockNumber; } } module.exports = new BlockChain();