aozhiwei 324ec86928 1
2022-04-04 13:14:44 +08:00

206 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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');
/*
需要重试的情况:
1、调用合约后当前块的高度>合约高度 + 6并且getPastEvent里查询不到该事件
2、connection not open on send网络不通目前未处理
3、 Returned error: replacement transaction underpriced(目前排队没这个问题)
*/
class ContractExecutor {
constructor() {
this.instanceName = '';
this.suspend = 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) {
await this.bcSync();
}
}
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.suspend(this.searchLogClass, 'blocNumber is empty');
return false;
}
await this.setSuccessBlockNumber(this.searchLogClass, blockNumber);
}
return events.length > 0;
}
async bcSync() {
await bc.mustBeActive();
let currBlockNumber = bc.getCurrBlockNumber();
try {
let hasErr = false;
let holdErr = null;
let nowTime = utils.getUtcTime();
//要确保100%能unlock
let result = null;
await bc.lock();
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;
}
}
await dblog.addLog(
this.syncDbLogClass,
'success',
this.getLogKey(),
utils.jsonEncode(this.getLogData()),
utils.jsonEncode(result),
currBlockNumber);
const blockNumber = result['blockNumber'];
if (!blockNumber) {
await this.suspend(this.syncLogClass, 'blockNumber is empty');
}
await this.onSyncSuccess(this.syncLogClass, result);
} catch (err) {
await dblog.addLog(
this.syncDbLogClass,
'failed',
this.getLogKey(),
utils.jsonEncode(this.getLogData()),
err,
currBlockNumber);
await this.suspend(this.syncLogClass, err);
}
}
};
function extractEventTxHash(event)
{
let txHash = '';
try {
txHash = event['transactionHash'];
} catch (err) {
}
return txHash;
}
function extractEventBlockNumber(event)
{
let blockNumber = '';
try {
blockNumber = event['blockNumber'];
} catch (err) {
}
return blockNumber;
}
exports.ContractExecutor = ContractExecutor;
exports.extractEventTxHash = extractEventTxHash;
exports.extractEventBlockNumber = extractEventBlockNumber;