Skip to content

Commit df8e45e

Browse files
pinheadmznodech
authored andcommitted
Merge PR handshake-org#671 from 'nodech/mempool-spent-port'
1 parent 5a8f5f1 commit df8e45e

File tree

2 files changed

+121
-11
lines changed

2 files changed

+121
-11
lines changed

lib/mempool/mempool.js

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,28 @@ class Mempool extends EventEmitter {
790790
return Coin.fromTX(entry.tx, index, -1);
791791
}
792792

793+
/**
794+
* Check whether coin is still unspent.
795+
* @param {Hash} hash
796+
* @param {Number} index
797+
* @returns {boolean}
798+
*/
799+
800+
hasCoin(hash, index) {
801+
const entry = this.map.get(hash);
802+
803+
if (!entry)
804+
return false;
805+
806+
if (this.isSpent(hash, index))
807+
return false;
808+
809+
if (index >= entry.tx.outputs.length)
810+
return false;
811+
812+
return true;
813+
}
814+
793815
/**
794816
* Check to see if a coin has been spent. This differs from
795817
* {@link ChainDB#isSpent} in that it actually maintains a
@@ -2404,6 +2426,8 @@ class Mempool extends EventEmitter {
24042426

24052427
/**
24062428
* Get coin viewpoint (lock).
2429+
* Note: this does not return the historical
2430+
* view of coins from the indexers
24072431
* @method
24082432
* @param {TX} tx
24092433
* @returns {Promise} - Returns {@link CoinView}.
@@ -2412,12 +2436,40 @@ class Mempool extends EventEmitter {
24122436
async getSpentView(tx) {
24132437
const unlock = await this.locker.lock();
24142438
try {
2415-
return await this.getCoinView(tx);
2439+
return await this._getSpentView(tx);
24162440
} finally {
24172441
unlock();
24182442
}
24192443
}
24202444

2445+
/**
2446+
* Get coin viewpoint
2447+
* @param {TX} tx
2448+
* @returns {Promise} - Returns {@link CoinView}
2449+
*/
2450+
2451+
async _getSpentView(tx) {
2452+
const view = new CoinView();
2453+
2454+
for (const {prevout} of tx.inputs) {
2455+
const {hash, index} = prevout;
2456+
const tx = this.getTX(hash);
2457+
2458+
if (tx) {
2459+
if (index < tx.outputs.length)
2460+
view.addIndex(tx, index, -1);
2461+
continue;
2462+
}
2463+
2464+
const coin = await this.chain.readCoin(prevout);
2465+
2466+
if (coin)
2467+
view.addEntry(prevout, coin);
2468+
}
2469+
2470+
return view;
2471+
}
2472+
24212473
/**
24222474
* Get coin viewpoint (no lock).
24232475
* @method
@@ -2433,7 +2485,7 @@ class Mempool extends EventEmitter {
24332485
const tx = this.getTX(hash);
24342486

24352487
if (tx) {
2436-
if (index < tx.outputs.length)
2488+
if (this.hasCoin(hash, index))
24372489
view.addIndex(tx, index, -1);
24382490
continue;
24392491
}

test/mempool-test.js

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
const assert = require('bsert');
77
const random = require('bcrypto/lib/random');
8+
const Network = require('../lib/protocol/network');
89
const MempoolEntry = require('../lib/mempool/mempoolentry');
910
const Mempool = require('../lib/mempool/mempool');
1011
const WorkerPool = require('../lib/workers/workerpool');
@@ -36,13 +37,14 @@ const ownership = require('../lib/covenants/ownership');
3637
const ONE_HASH = Buffer.alloc(32, 0x00);
3738
ONE_HASH[0] = 0x01;
3839

40+
const network = Network.get('regtest');
3941
const workers = new WorkerPool({
4042
enabled: true
4143
});
4244

4345
const chain = new Chain({
44-
network: 'regtest',
4546
memory: true,
47+
network,
4648
workers
4749
});
4850

@@ -52,7 +54,7 @@ const mempool = new Mempool({
5254
workers
5355
});
5456

55-
const wallet = new MemWallet();
57+
const wallet = new MemWallet({ network });
5658

5759
let cachedTX = null;
5860

@@ -225,6 +227,62 @@ describe('Mempool', function() {
225227
}));
226228
});
227229

230+
it('should get spent coins and reflect in coinview', async () => {
231+
const wallet = new MemWallet({ network });
232+
const addr = wallet.getAddress();
233+
234+
const dummyCoin = dummyInput(addr, random.randomBytes(32));
235+
236+
const mtx1 = new MTX();
237+
mtx1.addOutput(wallet.getAddress(), 50000);
238+
mtx1.addCoin(dummyCoin);
239+
240+
wallet.sign(mtx1);
241+
242+
const tx1 = mtx1.toTX();
243+
const coin1 = Coin.fromTX(tx1, 0, -1);
244+
245+
const mtx2 = new MTX();
246+
mtx2.addOutput(wallet.getAddress(), 10000);
247+
mtx2.addOutput(wallet.getAddress(), 30000); // 10k fee
248+
mtx2.addCoin(coin1);
249+
250+
wallet.sign(mtx2);
251+
252+
const tx2 = mtx2.toTX();
253+
254+
await mempool.addTX(tx1);
255+
256+
{
257+
const view = await mempool.getCoinView(tx2);
258+
const sview = await mempool.getSpentView(tx2);
259+
assert(view.hasEntry(coin1));
260+
assert(sview.hasEntry(coin1));
261+
assert.strictEqual(mempool.hasCoin(coin1.hash, coin1.index), true);
262+
assert.strictEqual(mempool.isSpent(coin1.hash, coin1.index), false);
263+
}
264+
265+
await mempool.addTX(tx2);
266+
267+
{
268+
const view = await mempool.getCoinView(tx1);
269+
const sview = await mempool.getSpentView(tx1);
270+
assert(!view.hasEntry(dummyCoin));
271+
assert(sview.hasEntry(dummyCoin));
272+
assert.strictEqual(mempool.hasCoin(coin1.hash, coin1.index), false);
273+
assert.strictEqual(mempool.isSpent(coin1.hash, coin1.index), true);
274+
}
275+
276+
{
277+
const view = await mempool.getCoinView(tx2);
278+
const sview = await mempool.getSpentView(tx2);
279+
assert(!view.hasEntry(coin1));
280+
assert(sview.hasEntry(coin1));
281+
assert.strictEqual(mempool.hasCoin(coin1.hash, coin1.index), false);
282+
assert.strictEqual(mempool.isSpent(coin1.hash, coin1.index), true);
283+
}
284+
});
285+
228286
it('should handle locktime', async () => {
229287
const key = KeyRing.generate();
230288
const addr = key.getAddress();
@@ -416,7 +474,7 @@ describe('Mempool', function() {
416474
const chain = new Chain({
417475
memory: true,
418476
workers,
419-
network: 'regtest'
477+
network
420478
});
421479

422480
const mempool = new Mempool({
@@ -425,6 +483,8 @@ describe('Mempool', function() {
425483
memory: true
426484
});
427485

486+
const wallet = new MemWallet({ network });
487+
428488
const COINBASE_MATURITY = mempool.network.coinbaseMaturity;
429489
const TREE_INTERVAL = mempool.network.names.treeInterval;
430490
mempool.network.names.auctionStart = 0;
@@ -444,9 +504,7 @@ describe('Mempool', function() {
444504
// Number of coins available in
445505
// chaincoins (100k satoshi per coin).
446506
const N = 100;
447-
const chaincoins = new MemWallet({
448-
network: 'regtest'
449-
});
507+
const chaincoins = new MemWallet({ network });
450508

451509
chain.on('block', (block, entry) => {
452510
chaincoins.addBlock(entry, block.txs);
@@ -1180,7 +1238,7 @@ describe('Mempool', function() {
11801238
const chain = new Chain({
11811239
memory: true,
11821240
workers,
1183-
network: 'regtest'
1241+
network
11841242
});
11851243

11861244
const mempool = new Mempool({
@@ -1206,8 +1264,8 @@ describe('Mempool', function() {
12061264
// Number of coins available in
12071265
// chaincoins (100k satoshi per coin).
12081266
const N = 100;
1209-
const chaincoins = new MemWallet();
1210-
const wallet = new MemWallet();
1267+
const chaincoins = new MemWallet({ network });
1268+
const wallet = new MemWallet({ network });
12111269

12121270
async function getMockBlock(chain, txs = [], cb = true) {
12131271
if (cb) {

0 commit comments

Comments
 (0)