'use strict'
let Transaction = require('../../Transaction/common/Transaction');
let DataSign = require('../../DataSign/common/DataSign');
let TxDataCreator = require('../../TxDataCreator/common/TxDataCreator');
let errorHandle = require('../../transUtil').errorHandle;
let retResult = require('../../transUtil').retResult;
let ccUtil = require('../../../api/ccUtil');
let sdkConfig = require('../../../conf/config');
/**
* @class
* @classdesc class used to transfer coin or token on the same chain.
*/
class NormalChain {
/**
* @constructor
* @param {Object} input - {@link CrossChain#input input}
* @param {Object} config - {@link CrossChain#config config}
*/
constructor(input,config) {
global.logger.debug("=========this.input====================");
global.logger.debug(ccUtil.hiddenProperties(input,['password','x']));
this.input = input;
this.config = config;
this.trans = null;
this.dataSign = null;
this.txDataCreator = null;
this.chainType = null;
this.input.chainType = config.srcChainType;
this.input.keystorePath = config.srcKeystorePath;
let x = ccUtil.generatePrivateKey();
this.input.hashX = ccUtil.getHashKey(x);
}
// used for revoke and redeem, to check whether the status and time is ok or not.
checkPreCondition(){
retResult.code = true;
return retResult;
}
createTrans(){
retResult.code = true;
retResult.result = new Transaction(this.input,this.config);
return retResult;
}
createDataCreator(){
retResult.code = true;
retResult.result = new TxDataCreator(this.input,this.config);
return retResult;
}
createDataSign(){
retResult.code = true;
retResult.result = new DataSign(this.input,this.config);
return retResult;
}
sendTrans(data){
let chainType = this.input.chainType;
global.logger.debug("sendTrans chainType is :",chainType);
return ccUtil.sendTrans(data,chainType);
}
setCommonData(commonData){
this.trans.setCommonData(commonData);
retResult.code = true;
return retResult;
}
setContractData(contractData){
this.trans.setContractData(contractData);
retResult.code = true;
return retResult;
}
preSendTrans(signedData){
retResult.code = true;
return retResult;
}
postSendTrans(resultSendTrans){
retResult.code = true;
return retResult;
}
/**
* Main process of normal transaction
* @returns {Promise<*>}
*/
async run(){
let ret;
let signedData = null;
try{
global.logger.debug("Entering NormalChain::run");
// step0 : check pre condition
ret = this.checkPreCondition();
if(ret.code !== true){
global.logger.debug("result from checkPreCondition is :",ret.result);
return ret;
}
ret = this.createTrans();
if(ret.code !== true){
return ret;
}else{
this.trans = ret.result;
}
ret = this.createDataCreator();
if(ret.code !== true){
return ret;
}else{
this.txDataCreator = ret.result;
}
ret = this.createDataSign();
if(ret.code !== true){
return ret;
}else{
this.dataSign = ret.result;
}
// step1 : build common data of transaction
let commonData = null;
ret = await this.txDataCreator.createCommonData();
if(ret.code !== true){
return ret;
}else{
commonData = ret.result;
global.logger.debug("NormalChain::run commontdata is:");
global.logger.debug(commonData);
this.trans.setCommonData(commonData);
}
// step2 : build contract data of transaction
let contractData = null;
ret = this.txDataCreator.createContractData();
if(ret.code !== true){
return ret;
}else{
contractData = ret.result;
global.logger.debug("NormalChain::run contractData is:");
global.logger.debug(contractData);
this.trans.setContractData(contractData);
}
}catch(error){
// global.logger.debug("error:",error);
ret.code = false;
ret.result = error;
global.logger.error("NormalChain run error:",error);
return ret;
}
try{
// step3 : get singedData
// global.logger.debug("NormalChain::run before sign trans is:");
// global.logger.debug(this.trans);
ret = this.dataSign.sign(this.trans);
global.logger.debug("NormalChain::run end sign, signed data is:");
global.logger.debug(ret.result);
if(ret.code !== true){
return ret;
}else{
signedData = ret.result;
}
}catch(error){
// global.logger.debug("error:",error);
ret.code = false;
ret.result = 'Wrong password';
global.logger.error("NormalChain run error:",error);
return ret;
}
try{
//step4.0 : insert in DB for resending.
global.logger.debug("before preSendTrans:");
ret = this.preSendTrans(signedData);
if(ret.code !== true){
return ret;
}
global.logger.debug("after preSendTrans:");
}catch(error){
// global.logger.debug("error:",error);
ret.code = false;
ret.result = error;
global.logger.error("NormalChain run error:",error);
return ret;
}
// step4 : send transaction to API server or web3;
let resultSendTrans;
let sendSuccess = false;
for(let i = 0 ; i< sdkConfig.tryTimes;i++){
try{
resultSendTrans = await this.sendTrans(signedData);
sendSuccess = true;
ret.result = resultSendTrans;
break;
}catch(error){
global.logger.error("NormalChain::run sendTrans error:");
global.logger.error("retry time:",i);
global.logger.error(error);
ret.result = error;
}
}
if(sendSuccess !== true){
ret.code = false;
return ret;
}
try{
global.logger.debug("result of sendTrans:", resultSendTrans);
global.logger.debug("before postSendTrans");
this.postSendTrans(resultSendTrans);
global.logger.debug("after postSendTrans");
// global.logger.debug("resultSendTrans :",resultSendTrans);
ret.code = true;
ret.result = resultSendTrans;
// step5 : update transaction status in the database
}catch(error){
ret.code = false;
ret.result = error;
global.logger.error("postSendTrans error:",error);
}
return ret;
}
}
module.exports = NormalChain;