Source: core/monitor.js

'use strict'
const   pu              = require('promisefy-util');
const   ccUtil          = require('../api/ccUtil');
let  Logger             = require('../logger/logger');
const BigNumber         = require('bignumber.js');
let  mrLogger;
/**
 * Used to monitor the cross transaction status.
 *
 */
const   MonitorRecord   = {
  async init(config){
    this.config           = config;
    this.crossCollection  = config.crossCollection;
    this.name             = "monitorETH&E20";

    mrLogger              = new Logger("Monitor",this.config.logfileNameMR, this.config.errfileNameMR,this.config.loglevel);
    global.mrLogger       = mrLogger;
  },
  receiptFailOrNot(receipt){
    if(receipt && receipt.status !== '0x1'){
      return true;
    }
    return false;
  },
  async waitLockConfirm(record){
    try{
      mrLogger.debug("Entering waitLockConfirm, lockTxHash = %s",record.lockTxHash);
      let receipt = await ccUtil.waitConfirm(record.lockTxHash,this.config.confirmBlocks,record.srcChainType);
      mrLogger.debug("%%%%%%%%%%%%%%%%%%%%%%%response from waitLockConfirm lockTxHash = %s%%%%%%%%%%%%%%%%%%%%%",
        record.lockTxHash);
      mrLogger.debug(receipt);
      if(receipt && receipt.hasOwnProperty('blockNumber') && receipt.status === '0x1'){
        record.status       = 'Locked';
        let blockNumber     = receipt.blockNumber;
        let chainType       = record.srcChainType;
        let block           = await ccUtil.getBlockByNumber(blockNumber,chainType);
        let newTime         = Number(block.timestamp); // unit s
        record.lockedTime   = newTime.toString();

        let htlcTimeOut;
        if(record.tokenStand === 'E20'){
          htlcTimeOut       = Number(block.timestamp)+Number(2*global.lockedTimeE20); // unit:s
        }else{
          htlcTimeOut       = Number(block.timestamp)+Number(2*global.lockedTime); // unit:s
        }
        record.htlcTimeOut  = htlcTimeOut.toString();
        mrLogger.info("waitLockConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
      if (this.receiptFailOrNot(receipt) === true){
        record.status       = 'LockFail';
        mrLogger.info("waitLockConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
    }catch(error){
      mrLogger.error("error waitLockConfirm");
      mrLogger.error(error);
    }
  },
  async waitRedeemConfirm(record){
    try{
      mrLogger.debug("Entering waitRedeemConfirm, redeemTxHash = %s",record.redeemTxHash);
      let receipt = await ccUtil.waitConfirm(record.redeemTxHash,this.config.confirmBlocks,record.dstChainType);
      mrLogger.debug("response from waitRedeemConfirm");
      mrLogger.debug(receipt);
      if(receipt && receipt.hasOwnProperty('blockNumber') && receipt.status === '0x1') {
        record.status = 'Redeemed';
        mrLogger.info("waitRedeemConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
      if (this.receiptFailOrNot(receipt) === true){
        record.status       = 'RedeemFail';
        mrLogger.info("waitRedeemConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
    }catch(error){
      mrLogger.error("error waitRedeemConfirm");
      mrLogger.error(error);
    }
  },
  async waitRevokeConfirm(record){
    try{
      mrLogger.debug("Entering waitRevokeConfirm, revokeTxHash = %s",record.revokeTxHash);
      let receipt = await ccUtil.waitConfirm(record.revokeTxHash,this.config.confirmBlocks,record.srcChainType);
      mrLogger.debug("response from waitRevokeConfirm,revokeTxHash = %s",record.revokeTxHash);
      mrLogger.debug(receipt);
      if(receipt && receipt.hasOwnProperty('blockNumber') && receipt.status === '0x1') {
        record.status = 'Revoked';
        mrLogger.info("waitRevokeConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
      if (this.receiptFailOrNot(receipt) === true){
        record.status       = 'RevokeFail';
        mrLogger.info("waitRevokeConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
    }catch(error){
      mrLogger.error("error waitRevokeConfirm");
      mrLogger.error(error);
    }
  },
  async waitApproveConfirm(record){
    try{
      mrLogger.debug("Entering waitApproveConfirm, approveTxHash = %s",record.approveTxHash);
      let receipt = await ccUtil.waitConfirm(record.approveTxHash,this.config.confirmBlocks,record.srcChainType);
      mrLogger.debug("response from waitApproveConfirm, approveTxHash = %s",record.approveTxHash);
      mrLogger.debug(receipt);
      if(receipt && receipt.hasOwnProperty('blockNumber') && receipt.status === '0x1'){
        record.status = 'Approved';
        mrLogger.info("waitApproveConfirm update record %s, status %s ", record.lockTxHash,record.status);
        this.updateRecord(record);
      }
    }catch(error){
      mrLogger.error("error waitApproveConfirm");
      mrLogger.error(error);
    }
  },
  async waitBuddyLockConfirm(record){
    mrLogger.debug("Entering waitBuddyLockConfirm, lockTxHash = %s",record.lockTxHash);

    try{
      // step1: get block number by event
      let bInbound  = false;
      let chainNameItemSrc;
      let chainNameItemDst;

      chainNameItemSrc = ccUtil.getSrcChainNameByContractAddr(record.srcChainAddr,record.srcChainType);
      chainNameItemDst = ccUtil.getSrcChainNameByContractAddr(record.dstChainAddr,record.dstChainType);

      if(global.crossInvoker.isInSrcChainsMap(chainNameItemSrc)){
        // destination is WAN, inbound
        bInbound    = true;
      };

      let bE20      = false;
      let chainNameItem;
      if(bInbound === true){
        chainNameItem = chainNameItemSrc;
      }else{
        chainNameItem = chainNameItemDst;
      }

      if(chainNameItem[1].tokenStand === 'E20'){
        bE20        = true;
      }

      // step2: build the right event by record, consider E20 and in bound or out bound
      let logs;
      let abi;
      let chainType = record.dstChainType; // because check buddy event.
      if(bInbound === true){
        if(bE20 === true){
          // bE20 bInbound  getInStgLockEventE20
          mrLogger.debug("Entering getInStgLockEventE20");
          logs  = await ccUtil.getInStgLockEventE20(chainType,record.hashX,record.contractValue);
          abi   = this.config.wanAbiE20;
        }else{
          // bInbound not E20 getInStgLockEvent
          mrLogger.debug("Entering getInStgLockEvent");
          logs  = await ccUtil.getInStgLockEvent(chainType,record.hashX,record.contractValue);
          abi   = this.config.HtlcWANAbi;
        }
      }else{
        if(bE20 === true){
          // bE20 outBound getOutStgLockEventE20
          mrLogger.debug("Entering getOutStgLockEventE20");
          logs  = await ccUtil.getOutStgLockEventE20(chainType,record.hashX,record.contractValue);
          abi   = this.config.ethAbiE20;
        }else{
          // outBound not E20 getOutStgLockEvent
          mrLogger.debug("Entering getOutStgLockEvent");
          logs = await ccUtil.getOutStgLockEvent(chainType,record.hashX,record.contractValue);
          abi  = this.config.HtlcETHAbi;
        }
      }
      mrLogger.debug("bInbound = ",bInbound);
      mrLogger.debug("bE20 = ",bE20);
      mrLogger.debug("chainType=",chainType);
      // mrLogger.debug("logs[0]",logs[0]);
      // mrLogger.debug("typeof logs[0]",typeof(logs[0]));

      if(typeof(logs[0]) === "undefined"){
        mrLogger.debug("waiting buddy locking");
        return;
      }

      let retResult = ccUtil.parseLogs(logs,abi);
      mrLogger.debug("retResult of parseLogs:", retResult);
      mrLogger.debug("retResult.value of parseLogs:", retResult[0].args.value);
      let valueEvent;
      valueEvent = new BigNumber(retResult[0].args.value);
      valueEvent = '0x'+valueEvent.toString(16);
      let valueContract = record.contractValue;
      mrLogger.debug("valueEvent: valueContract", valueEvent,valueContract);
      if(valueEvent.toString() == valueContract.toString()){
        mrLogger.debug("--------------equal----------------");

        // step3: get the lock transaction hash of buddy from block number
        let crossTransactionTx;
        if(typeof(logs[0].transactionHash) !== "undefined"){
          crossTransactionTx = logs[0].transactionHash;
          // step4: get transaction confirmation
          mrLogger.debug("Entering waitBuddyLockConfirm LockTx %s buddyTx %s", record.lockTxHash,crossTransactionTx);
          let receipt = await ccUtil.waitConfirm(crossTransactionTx,this.config.confirmBlocks,chainType);
          mrLogger.debug("response from waitBuddyLockConfirm, LockTx %s buddyTx %s", record.lockTxHash,crossTransactionTx);
          mrLogger.debug(receipt);
          if(receipt && receipt.hasOwnProperty('blockNumber') && receipt.status === '0x1'){

            let recordTemp    = global.wanDb.getItem(this.crossCollection,{hashX:record.hashX});
            let currentStatus = recordTemp.status;

            mrLogger.debug("waitBuddyLockConfirm current record.status is :", record.status);
            mrLogger.debug("waitBuddyLockConfirm current recordTemp.status is :", recordTemp.status);

            if(currentStatus != 'Locked') {
              mrLogger.debug("waitBuddyLockConfirm current status is :", currentStatus);
              return;
            }

            record.status           = 'BuddyLocked';
            let blockNumber         = receipt.blockNumber;
            // step5: get the time of buddy lock.
            let block               = await ccUtil.getBlockByNumber(blockNumber,chainType);
            let newTime             = Number(block.timestamp);  // unit : s
            record.buddyLockedTime  = newTime.toString();

            record.buddyLockTxHash  = crossTransactionTx;
            let buddyLockedTimeOut;
            if(record.tokenStand === 'E20'){
              buddyLockedTimeOut    = Number(block.timestamp)+Number(global.lockedTimeE20); // unit:s
            }else{
              buddyLockedTimeOut    = Number(block.timestamp)+Number(global.lockedTime); // unit:s
            }
            record.buddyLockedTimeOut= buddyLockedTimeOut.toString();
            mrLogger.info("waitBuddyLockConfirm update record %s, status %s ", record.lockTxHash,record.status);
            this.updateRecord(record);
          }
        }

      }else{
        mrLogger.error("--------------Not equal----------------");
      }

    }catch(err){
      mrLogger.error("waitBuddyLockConfirm error!");
      mrLogger.error(err);
    }
  },
  updateRecord(record){
    global.wanDb.updateItem(this.crossCollection,{'hashX':record.hashX},record);
  },
  monitorTask(){
    mrLogger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    mrLogger.info("Entering monitor task");
    mrLogger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    let records = global.wanDb.filterNotContains(this.config.crossCollection,'status',['Redeemed','Revoked']);
    for(let i=0; i<records.length; i++){
      let record = records[i];
      this.monitorRecord(record);
    }
  },
  async monitorRecord(record){
    //mrLogger.debug(this.name);
    switch(record.status) {
      /// approve begin
      case 'ApproveSending':
      {
        //this.approveSendRetry(record);
        break;
      }
      case 'ApproveSendFail':
      {
        //this.approveSendRetry(record);
        break;
      }
      case 'ApproveSendFailAfterRetries':
      {
        break;
      }
      case 'ApproveSent':
      {
        this.waitApproveConfirm(record);
        break;
      }
      case 'Approved':
      {
        break;
      }
      /// approve end
      /// lock   begin
      case 'LockSending':
      {
        //this.lockSendRetry(record);
        break;
      }
      case 'LockSendFail':
      {
        //this.lockSendRetry(record);
        break;
      }
      case 'LockSendFailAfterRetries':
      {
        break;
      }
      case 'LockSent':
      {
        this.waitLockConfirm(record);
        // Locked
        break;
      }
      case 'Locked':
      {
        this.waitBuddyLockConfirm(record);
        break;
      }
      case 'BuddyLocked':
      {
        break;
      }
      /// lock   end
      /// redeem  begin
      case 'RedeemSending':
      {
        //this.redeemSendRetry(record);
        break;
      }
      case 'RedeemSendFail':
      {
        //this.redeemSendRetry(record);
        break;
      }
      case 'RedeemSendFailAfterRetries':
      {
        break;
      }
      case 'RedeemSent':
      {
        this.waitRedeemConfirm(record);
        break;
      }
      case 'Redeemed':
      {
        break;
      }
      /// redeem  end
      /// revoke   begin
      case 'RevokeSending':
      {
        //this.revokeSendRetry(record);
        break;
      }
      case 'RevokeSendFail':
      {
        //this.revokeSendRetry(record);
        break;
      }
      case 'RevokeSendFailAfterRetries':
      {
        break;
      }
      case 'RevokeSent':
      {
        this.waitRevokeConfirm(record);
        break;
      }
      case 'Revoked':
      {
        break;
      }
      /// revoke   end
      /// default  begin
      default:
        break;
    }
  },
}
exports.MonitorRecord = MonitorRecord;