int-cli
Version:
INT is the new generation of bottom-up created system of IoT and blockchain
156 lines (155 loc) • 6.38 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const chain_1 = require("../chain");
const error_code_1 = require("../error_code");
const bignumber_js_1 = require("bignumber.js");
const chain_2 = require("./chain");
class ValuePendingTransactions extends chain_1.PendingTransactions {
constructor() {
super(...arguments);
this.m_balance = new Map();
}
async _onCheck(txTime, txOld) {
let ret = await super._onCheck(txTime, txOld);
if (ret) {
return ret;
}
let br = await this.getBalance(txTime.tx.address);
if (br.err) {
return br.err;
}
let balance = br.value;
let txValue = txTime.tx;
let totalUse = txValue.value.plus(txValue.limit.times(txValue.price));
if (txOld) {
let txOldValue = txOld.tx;
totalUse = totalUse.minus(txOldValue.value).minus(txOldValue.limit.times(txOldValue.price));
}
if (balance.lt(totalUse)) {
this.m_logger.error(`onCheck failed, need total ${totalUse.toString()} but balance ${balance.toString()}`);
return error_code_1.ErrorCode.RESULT_NOT_ENOUGH;
}
return error_code_1.ErrorCode.RESULT_OK;
}
async _onAddedTx(txTime, txOld) {
let br = await this.getBalance(txTime.tx.address);
if (br.err) {
return br.err;
}
let balance = br.value;
let txValue = txTime.tx;
let valueFee = txValue.limit.times(txValue.price);
if (txOld) {
let txOldValue = txOld.tx;
let oldFee = txOldValue.limit.times(txOldValue.price);
balance = balance.plus(oldFee).plus(txOldValue.value).minus(valueFee).minus(txValue.value);
}
else {
balance = balance.minus(valueFee).minus(txValue.value);
}
this.m_balance.set(txTime.tx.address, balance);
return await super._onAddedTx(txTime);
}
async updateTipBlock(header) {
this.m_balance = new Map();
return await super.updateTipBlock(header);
}
async getStorageBalance(s) {
try {
let dbr = await this.m_storageView.getReadableDataBase(chain_1.Chain.dbSystem);
if (dbr.err) {
return { err: dbr.err };
}
let kvr = await dbr.value.getReadableKeyValue(chain_2.ValueChain.kvBalance);
if (kvr.err !== error_code_1.ErrorCode.RESULT_OK) {
return { err: kvr.err };
}
let ret = await kvr.kv.get(s);
if (!ret.err) {
return ret;
}
else if (ret.err === error_code_1.ErrorCode.RESULT_NOT_FOUND) {
return { err: error_code_1.ErrorCode.RESULT_OK, value: new bignumber_js_1.BigNumber(0) };
}
else {
return { err: ret.err };
}
}
catch (error) {
this.m_logger.error(`getStorageBalance error=${error}`);
return { err: error_code_1.ErrorCode.RESULT_EXCEPTION };
}
}
// 获取pending中的balance
async getBalance(s) {
if (this.m_balance.has(s)) {
return { err: error_code_1.ErrorCode.RESULT_OK, value: this.m_balance.get(s) };
}
return this.getStorageBalance(s);
}
async _checkSmallNonceTx(txNew, txOld) {
if ((txNew.price).gt(txOld.price)) {
return error_code_1.ErrorCode.RESULT_OK;
}
return error_code_1.ErrorCode.RESULT_FEE_TOO_SMALL;
}
_addToQueue(txTime, pos) {
pos = 0;
for (let i = 0; i < this.m_transactions.length; i++) {
if (this.m_transactions[i].tx.address === txTime.tx.address) {
pos = this.m_transactions[i].tx.nonce < txTime.tx.nonce ? i + 1 : i;
}
else {
pos = this.m_transactions[i].tx.price.lt(txTime.tx.price) ? i : i + 1;
}
}
this.m_transactions.splice(pos, 0, txTime);
}
async popTransactionWithFee(maxLimit) {
let txs = [];
let addressNonceMap = new Map();
let total = new bignumber_js_1.BigNumber(0);
let nonce = 0;
for (let pos = 0; pos < this.m_transactions.length; pos++) {
let transaction = this.m_transactions[pos].tx;
if (addressNonceMap.has(transaction.address)) {
nonce = addressNonceMap.get(transaction.address);
}
else {
let nonceResult = await this.getStorageNonce(transaction.address);
if (nonceResult.err) {
this.m_logger.error(`push tx getStorageNonce error,hash=${transaction.hash},address = ${transaction.address}`);
continue;
}
nonce = nonceResult.nonce;
}
if (nonce + 1 != transaction.nonce) {
this.m_logger.error(`push tx nonce error,need ${nonce + 1} ,but ${transaction.nonce},hash=${transaction.hash},address = ${transaction.address}`);
continue;
}
let totalTxLimit = this.m_calcTxLimit.calcTxLimit(transaction.method, transaction.input);
this.m_logger.debug(`popTransactionWithFee hash ${transaction.hash}, method ${transaction.method}, input ${transaction.input}, txlimit ${totalTxLimit.toString()}`);
total = total.plus(totalTxLimit);
if (total.gt(maxLimit)) {
this.m_logger.debug(`popTransactionWithFee finished, total limit ${total.toString()}, max limit ${maxLimit.toString()}`);
break;
}
txs.push(transaction);
addressNonceMap.set(transaction.address, transaction.nonce);
}
return txs;
}
async getPendingTransactions() {
let pt = await super.getPendingTransactions();
let pendingTxs = [];
if (pt.err) {
return { err: pt.err };
}
for (let i = 0; i < pt.pendingTransactions.length; i++) {
let tx = pt.pendingTransactions[i].tx.stringify();
pendingTxs.push({ tx: tx, ct: pt.pendingTransactions[i].ct });
}
return { err: error_code_1.ErrorCode.RESULT_OK, pendingTransactions: pendingTxs };
}
}
exports.ValuePendingTransactions = ValuePendingTransactions;
;