test: add mempool indexing tests
This commit is contained in:
parent
80aaa148e4
commit
f30276bc27
@ -492,6 +492,294 @@ describe('Mempool', function() {
|
|||||||
await workers.close();
|
await workers.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Index', function () {
|
||||||
|
const workers = new WorkerPool({
|
||||||
|
enabled: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const blocks = new BlockStore({
|
||||||
|
memory: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const chain = new Chain({
|
||||||
|
memory: true,
|
||||||
|
workers,
|
||||||
|
blocks
|
||||||
|
});
|
||||||
|
|
||||||
|
const mempool = new Mempool({
|
||||||
|
chain,
|
||||||
|
workers,
|
||||||
|
memory: true,
|
||||||
|
indexAddress: true
|
||||||
|
});
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blocks.open();
|
||||||
|
await mempool.open();
|
||||||
|
await chain.open();
|
||||||
|
await workers.open();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await workers.close();
|
||||||
|
await chain.close();
|
||||||
|
await mempool.close();
|
||||||
|
await blocks.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Number of coins available in
|
||||||
|
// chaincoins (100k satoshi per coin).
|
||||||
|
const N = 100;
|
||||||
|
const chaincoins = new MemWallet();
|
||||||
|
const wallet = new MemWallet();
|
||||||
|
|
||||||
|
it('should create coins in chain', async () => {
|
||||||
|
const mtx = new MTX();
|
||||||
|
mtx.addInput(new Input());
|
||||||
|
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
const addr = chaincoins.createReceive().getAddress();
|
||||||
|
mtx.addOutput(addr, 100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cb = mtx.toTX();
|
||||||
|
const block = await getMockBlock(chain, [cb], false);
|
||||||
|
const entry = await chain.add(block, VERIFY_NONE);
|
||||||
|
|
||||||
|
await mempool._addBlock(entry, block.txs);
|
||||||
|
|
||||||
|
// Add 100 blocks so we don't get
|
||||||
|
// premature spend of coinbase.
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
const block = await getMockBlock(chain);
|
||||||
|
const entry = await chain.add(block, VERIFY_NONE);
|
||||||
|
|
||||||
|
await mempool._addBlock(entry, block.txs);
|
||||||
|
}
|
||||||
|
|
||||||
|
chaincoins.addTX(cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should spend txs and coins in the mempool', async () => {
|
||||||
|
// Verify coins are removed from the coin index.
|
||||||
|
const coin = chaincoins.getCoins()[0];
|
||||||
|
const addr = wallet.createReceive().getAddress();
|
||||||
|
|
||||||
|
const mtx1 = new MTX();
|
||||||
|
|
||||||
|
mtx1.addCoin(coin);
|
||||||
|
mtx1.addOutput(addr, 90000);
|
||||||
|
|
||||||
|
chaincoins.sign(mtx1);
|
||||||
|
|
||||||
|
const tx1 = mtx1.toTX();
|
||||||
|
|
||||||
|
chaincoins.addTX(tx1, -1);
|
||||||
|
wallet.addTX(tx1, -1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const missing = await mempool.addTX(tx1);
|
||||||
|
assert.strictEqual(missing, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mempool.hasCoin(tx1.hash(), 0));
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
const metas = mempool.getMetaByAddress(addr);
|
||||||
|
|
||||||
|
assert.strictEqual(txs.length, 1);
|
||||||
|
assert.strictEqual(metas.length, 1);
|
||||||
|
|
||||||
|
assert.bufferEqual(txs[0].hash(), tx1.hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
const mtx2 = new MTX();
|
||||||
|
|
||||||
|
mtx2.addTX(tx1, 0, -1);
|
||||||
|
mtx2.addOutput(addr, 80000);
|
||||||
|
|
||||||
|
wallet.sign(mtx2);
|
||||||
|
|
||||||
|
const tx2 = mtx2.toTX();
|
||||||
|
|
||||||
|
{
|
||||||
|
const missing = await mempool.addTX(tx2);
|
||||||
|
assert.strictEqual(missing, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.addTX(tx2, -1);
|
||||||
|
|
||||||
|
assert(!mempool.hasCoin(tx1.hash(), 0));
|
||||||
|
assert(mempool.hasCoin(tx2.hash(), 0));
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
|
||||||
|
assert.strictEqual(txs.length, 2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should spend resolved orphans', async () => {
|
||||||
|
const coin = chaincoins.getCoins()[0];
|
||||||
|
const addr = wallet.createReceive().getAddress();
|
||||||
|
|
||||||
|
const pmtx = new MTX();
|
||||||
|
|
||||||
|
pmtx.addOutput(addr, 90000);
|
||||||
|
pmtx.addCoin(coin);
|
||||||
|
|
||||||
|
chaincoins.sign(pmtx);
|
||||||
|
|
||||||
|
const parentTX = pmtx.toTX();
|
||||||
|
|
||||||
|
const cmtx = new MTX();
|
||||||
|
|
||||||
|
cmtx.addTX(pmtx.toTX(), 0, -1);
|
||||||
|
cmtx.addOutput(addr, 80000);
|
||||||
|
|
||||||
|
wallet.sign(cmtx);
|
||||||
|
|
||||||
|
const childTX = cmtx.toTX();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Create orphan tx.
|
||||||
|
const missing = await mempool.addTX(childTX);
|
||||||
|
|
||||||
|
// We only have one input missing.
|
||||||
|
assert.strictEqual(missing.length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
|
||||||
|
assert.strictEqual(txs.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Orphans are not coins.
|
||||||
|
const childCoin = mempool.getCoin(childTX.hash(), 0);
|
||||||
|
assert.strictEqual(childCoin, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Orphans should be resolved.
|
||||||
|
const missing = await mempool.addTX(parentTX);
|
||||||
|
assert.strictEqual(missing, null);
|
||||||
|
|
||||||
|
// Coins should be available once they are resolved.
|
||||||
|
const parentCoin = mempool.getCoin(parentTX.hash(), 0);
|
||||||
|
|
||||||
|
// We spent this.
|
||||||
|
assert.strictEqual(parentCoin, null);
|
||||||
|
|
||||||
|
const childCoin = mempool.getCoin(childTX.hash(), 0);
|
||||||
|
assert(childCoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
assert.strictEqual(txs.length, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update coins in wallets.
|
||||||
|
for (const tx of [parentTX, childTX]) {
|
||||||
|
chaincoins.addTX(tx);
|
||||||
|
wallet.addTX(tx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove double spend tx from mempool', async () => {
|
||||||
|
const coin = chaincoins.getCoins()[0];
|
||||||
|
const addr = wallet.createReceive().getAddress();
|
||||||
|
const randomAddress = KeyRing.generate().getAddress();
|
||||||
|
|
||||||
|
// We check double spending our mempool tx.
|
||||||
|
const mtx1 = new MTX();
|
||||||
|
|
||||||
|
mtx1.addCoin(coin);
|
||||||
|
mtx1.addOutput(addr, 90000);
|
||||||
|
|
||||||
|
chaincoins.sign(mtx1);
|
||||||
|
|
||||||
|
// This will double spend in block.
|
||||||
|
const mtx2 = new MTX();
|
||||||
|
|
||||||
|
mtx2.addCoin(coin);
|
||||||
|
mtx2.addOutput(randomAddress, 90000);
|
||||||
|
|
||||||
|
chaincoins.sign(mtx2);
|
||||||
|
|
||||||
|
const tx1 = mtx1.toTX();
|
||||||
|
const tx2 = mtx2.toTX();
|
||||||
|
|
||||||
|
{
|
||||||
|
const missing = await mempool.addTX(tx1);
|
||||||
|
assert.strictEqual(missing, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
assert.strictEqual(txs.length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mempool.hasCoin(tx1.hash(), 0));
|
||||||
|
|
||||||
|
const block = await getMockBlock(chain, [tx2]);
|
||||||
|
const entry = await chain.add(block, VERIFY_NONE);
|
||||||
|
|
||||||
|
await mempool._addBlock(entry, block.txs);
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
assert.strictEqual(txs.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!mempool.hasCoin(tx1.hash(), 0));
|
||||||
|
|
||||||
|
chaincoins.addTX(tx2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove confirmed txs from mempool', async () => {
|
||||||
|
const coin = chaincoins.getCoins()[0];
|
||||||
|
const addr = wallet.createReceive().getAddress();
|
||||||
|
|
||||||
|
const mtx = new MTX();
|
||||||
|
|
||||||
|
mtx.addCoin(coin);
|
||||||
|
mtx.addOutput(addr, 90000);
|
||||||
|
|
||||||
|
chaincoins.sign(mtx);
|
||||||
|
|
||||||
|
const tx = mtx.toTX();
|
||||||
|
|
||||||
|
await mempool.addTX(tx);
|
||||||
|
|
||||||
|
assert(mempool.hasCoin(tx.hash(), 0));
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
assert.strictEqual(txs.length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const block = await getMockBlock(chain, [tx]);
|
||||||
|
const entry = await chain.add(block, VERIFY_NONE);
|
||||||
|
|
||||||
|
await mempool._addBlock(entry, block.txs);
|
||||||
|
|
||||||
|
{
|
||||||
|
const txs = mempool.getTXByAddress(addr);
|
||||||
|
assert.strictEqual(txs.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!mempool.hasCoin(tx.hash(), 0));
|
||||||
|
|
||||||
|
chaincoins.addTX(tx);
|
||||||
|
wallet.addTX(tx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Mempool persistent cache', function () {
|
describe('Mempool persistent cache', function () {
|
||||||
const workers = new WorkerPool({
|
const workers = new WorkerPool({
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user