aozhiwei 24bc8ab81b 1
2022-02-17 10:36:50 +08:00

203 lines
5.4 KiB
JavaScript

const util = require('util');
const utils = require('./utils');
const metamgr = require('./metamgr');
const dbhelper = require("./dbhelper");
const log = require("./log");
const dblog = require("./dblog");
const bc = require('./blockchain');
const C = require('./C');
class ContractExecutor {
constructor() {
this.instanceName = '';
this.doSuspend = null;
this.getLogKey = null;
this.getLogData = null;
this.getPrepareBlockNumber = null;
this.setPrepareBlockNumber = null;
this.getSuccessBlockNumber = null;
this.setSuccessBlockNumber = null;
this.getSyncCount = null;
this.searchLogClass = '';
this.eventName = '';
this.eventFilter = null;
this.syncLogClass = '';
this.methodName = '';
this.methodArgs = [];
this.syncDbLogClass = '';
this.onSyncSuccess = null;
this.onConfirmed = null;
}
init() {
this.instance = bc[this.instanceName];
this.method = this.instance.methods[this.methodName];
}
async execute() {
let tryCount = 0;
do {
await this.sync();
const confirmed = await this.confirm();
if (confirmed) {
this.onConfirmed(this.syncLogClass + '.confirmed');
return true;
} else {
++tryCount;
await this.setPrepareBlockNumber('execute.setPrepareBlockNumber:' + this.instanceName, 0);
await this.setSuccessBlockNumber('execute:setSuccessBlockNumber:' + this.instanceName, 0);
await utils.sleep(utils.randRange(1500, 4000));
}
} while (tryCount < 3 && this.getSyncCount() < 3);
return false;
}
async sync() {
await bc.mustBeActive();
const found = await this.bcSearch();
if (!found) {
const ok = await this.bcSync();
if (!ok) {
this.doSuspend(this.syncLogClass, '');
return;
}
}
}
async confirm() {
while (true) {
if (bc.isComfirmed(this.getSuccessBlockNumber())) {
const found = await this.bcSearch();
return found;
break;
}
await utils.sleep(1000 * 3);
}
return false;
}
async bcSearch() {
if (this.getPrepareBlockNumber() <= 0) {
return false;
}
let events = [];
while (true) {
try {
const fromBlock = Math.max(this.getPrepareBlockNumber() - 1000, 0);
events = await this.instance.getPastEvents(
this.eventName,
{
fromBlock: fromBlock,
toBlock: fromBlock + 5000 - 1,
filter: this.eventFilter
});
break;
} catch (err) {
log.warning(
util.format('%s getPastEvents data:%s err:%s',
this.searchLogClass,
utils.jsonEncode(this.getLogData()),
err
));
}
await utils.sleep(1000 * 3);
}
if (events.length > 0) {
const blockNumber = events[0]['blockNumber'];
if (!blockNumber) {
await this.doSuspend(this.searchLogClass, 'blocNumber is empty');
return false;
}
await this.setSuccessBlockNumber(this.searchLogClass, blockNumber);
}
return events.length > 0;
}
async bcSync() {
const doSync = async() => {
let result = null;
await bc.mustBeActive();
let currBlockNumber = bc.getCurrBlockNumber();
try {
log.info(
util.format('%s begin sync logKey:%s',
this.syncLogClass,
this.getLogKey()
));
let hasErr = false;
let holdErr = null;
let nowTime = utils.getUtcTime();
//要确保100%能unlock
await bc.lock();
try {
try {
await bc.mustBeActive();
currBlockNumber = bc.getCurrBlockNumber();
nowTime = utils.getUtcTime();
result = await this.method(...this.methodArgs).send({gas: 1000000});
} catch (err) {
hasErr = true;
holdErr = err;
}
} finally {
await bc.unLock();
await dblog.addLogEx(
nowTime,
this.syncDbLogClass,
'prepare',
this.getLogKey(),
utils.jsonEncode(this.getLogData()),
currBlockNumber);
await this.setPrepareBlockNumber(this.syncLogClass, currBlockNumber);
if (hasErr) {
throw holdErr;
}
}
log.info(
util.format('%s end sync logKey:%s',
this.syncLogClass,
this.getLogKey()
));
await dblog.addLog(
this.syncDbLogClass,
'success',
this.getLogKey(),
utils.jsonEncode(this.getLogData()),
utils.jsonEncode(result),
currBlockNumber);
await this.onSyncSuccess(this.syncLogClass, result);
} catch (err) {
await dblog.addLog(
this.syncDbLogClass,
'failed',
this.getLogKey(),
utils.jsonEncode(this.getLogData()),
err,
currBlockNumber);
await this.doSuspend(this.syncLogClass, err);
}
return result;
};
try {
const result = await doSync();
return true;
} catch (err) {
log.warning(
util.format('%s end data:%s err:%s',
this.syncLogClass,
utils.jsonEncode(this.getLogData()),
err
)
);
}
return false;
}
};
exports.ContractExecutor = ContractExecutor;