213 lines
5.8 KiB
JavaScript
213 lines
5.8 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;
|
|
let confirmed = false;
|
|
do {
|
|
await this.sync();
|
|
confirmed = await this.confirm();
|
|
if (confirmed) {
|
|
this.onConfirmed(this.syncLogClass + '.confirmed');
|
|
} else {
|
|
++tryCount;
|
|
await this.setPrepareBlockNumber('setPrepareBlockNumber:' + this.instanceName, 0);
|
|
await this.setSuccessBlockNumber('execute:setSuccessBlockNumber:' + this.instanceName, 0);
|
|
await utils.sleep(utils.randRange(1500, 4000));
|
|
}
|
|
} while (tryCount < 3 && !confirmed && this.getSyncCount() < 3);
|
|
return confirmed;
|
|
}
|
|
|
|
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);
|
|
log.info(
|
|
util.format('%s begin search logKey:%s',
|
|
this.searchLogClass,
|
|
this.getLogKey()
|
|
));
|
|
events = await this.instance.getPastEvents(
|
|
this.eventName,
|
|
{
|
|
fromBlock: fromBlock,
|
|
toBlock: fromBlock + 5000 - 1,
|
|
filter: this.eventFilter
|
|
});
|
|
log.info(
|
|
util.format('%s end search logKey:%s',
|
|
this.searchLogClass,
|
|
this.getLogKey()
|
|
));
|
|
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;
|