Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions node/mempool.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@

const typeforce = require('typeforce');
const debugLib = require('debug');
const { sleep } = require('../utils');
const {sleep} = require('../utils');
const types = require('../types');
const Tick = require('tick-tock');
const {Dag} = require('dagjs');

const debug = debugLib('mempool:');

// TODO: add tx expiration (14 days?)

module.exports = ({ Constants, Transaction }) =>
module.exports = ({Constants, Transaction}) =>
class Mempool {
constructor(options) {
this._mapTxns = new Map();
this._tock = new Tick(this);
this._dag = new Dag();
this._dag.testForCyclic = false;
this._tock.setInterval('outdatedTimer', this.purgeOutdated.bind(this), Constants.MEMPOOL_OUTDATED_INTERVAL);

}
Expand All @@ -35,6 +38,7 @@ module.exports = ({ Constants, Transaction }) =>
// TODO: think about: is it problem that TX isn't present in mempool, but present in block
if (this._mapTxns.has(txHash)) {
this._mapTxns.delete(txHash);
this._dag.removeVertex(txHash);
} else {
debug(`removeTxns: no TX ${txHash} in mempool`);
}
Expand All @@ -45,6 +49,7 @@ module.exports = ({ Constants, Transaction }) =>
this._mapTxns.forEach((tx, hash) => {
if (tx.arrived < Date.now() - Constants.MEMPOOL_TX_LIFETIME) {
this._mapTxns.delete(hash);
this._dag.removeVertex(hash);
}
})
}
Expand All @@ -54,6 +59,7 @@ module.exports = ({ Constants, Transaction }) =>
let i = Math.floor(this._mapTxns.size / 3);
for (let [hash, tx] of this._mapTxns) {
this._mapTxns.delete(hash);
this._dag.removeVertex(hash);
if (--i == 0) break;
}
}
Expand All @@ -77,7 +83,10 @@ module.exports = ({ Constants, Transaction }) =>
const strHash = tx.hash();
if (this._mapTxns.has(strHash)) throw new Error(`tx ${strHash} already in mempool`);

this._mapTxns.set(strHash, { tx, arrived: Date.now() });
this._mapTxns.set(strHash, {tx, arrived: Date.now()});
for (const input of tx.inputs) {
this._dag.add(input.txHash.toString('hex'), strHash);
}
debug(`TX ${strHash} added`);
}

Expand Down Expand Up @@ -107,9 +116,40 @@ module.exports = ({ Constants, Transaction }) =>
// TODO: implement lock_time
// TODO: implement cache if mempool becomes huge
const arrResult = [];
for (let r of this._mapTxns.values()) {
if (r.tx.witnessGroupId === groupId) arrResult.push(r.tx);
for (let hash of this._sortTxns()){
const r = this._mapTxns.get(hash);
if (r.tx.witnessGroupId == groupId) arrResult.push(r.tx);
}
return arrResult;
}

/**
*
* @returns sorted tx hashes array
*/
_sortTxns() {
let level = [];
let used = [...this._dag.tips];
let notused = [...this._mapTxns.keys()];
while (notused.length > 0) {
level[level.length] = new Array();
for (let i = 0; i < notused.length; i++) {
const v = notused[i]
let k = 0;
const edgesTo = this._dag._edges.get(v);
if (edgesTo) {
k = edgesTo.length;
const fromPrevLevel = edgesTo.filter(e => ~used.indexOf(e.from));
if(fromPrevLevel) k -= fromPrevLevel.length
}
if (k == 0) {
level[level.length - 1].push(v)
notused.splice(i, 1);
i--;
}
}
used.push(...level[level.length - 1])
}
return [].concat(...level);
}
};
19 changes: 19 additions & 0 deletions tests/mempool.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('Mempool tests', () => {

mempool.addTx(tx);
assert.isOk(mempool.hasTx(tx.hash()));
assert.isOk(mempool._dag.hasVertex(tx.hash()))
});

it('should FAIL add tx to mempool (already exists)', async () => {
Expand Down Expand Up @@ -82,6 +83,9 @@ describe('Mempool tests', () => {

assert.isNotOk(mempool.hasTx(tx1.hash()));
assert.isNotOk(mempool.hasTx(tx2.hash()));
assert.isNotOk(mempool._dag.hasVertex(tx1.hash()))
assert.isNotOk(mempool._dag.hasVertex(tx2.hash()))

});

it('should get tx by hash', async () => {
Expand Down Expand Up @@ -168,4 +172,19 @@ describe('Mempool tests', () => {

});

it('should sort txns', () => {
const mempool = new factory.Mempool();
const tx1 = new factory.Transaction(createDummyTx());
const tx2 = new factory.Transaction(createDummyTx());
const tx3 = new factory.Transaction();
tx3.addInput(tx1.hash(), 1);
tx3.addInput(tx2.hash(), 2);
mempool.addTx(tx2);
mempool.addTx(tx3);
mempool.addTx(tx1);

const arrTxns = mempool.getFinalTxns(0);
assert.deepEqual(arrTxns,[tx2, tx1, tx3]);
})

});