pool/wallet/spvnode: test imported names are added to filter and sent

This commit is contained in:
Matthew Zipkin 2022-03-25 11:16:47 -04:00
parent 107ed2be92
commit 2083050eb2
No known key found for this signature in database
GPG key ID: E7E2984B6289C93A
3 changed files with 106 additions and 0 deletions

View file

@ -3661,6 +3661,15 @@ class Pool extends EventEmitter {
this.watch(outpoint.encode());
}
/**
* Add a nameHash to the bloom filter (SPV-only).
* @param {Hash} nameHash
*/
watchName(nameHash) {
this.watch(nameHash);
}
/**
* Send `getblocks` to peer after building
* locator and resolving orphan root.

View file

@ -172,6 +172,10 @@ class NodeClient extends AsyncEmitter {
*/
async addFilter(data) {
// `data` is ignored because pool.spvFilter === walletDB.filter
// and therefore is already updated.
// Argument is kept here to be consistent with API in
// wallet/client.js (hs-client NodeClient) and wallet/nullclient.js
this.node.pool.queueFilterLoad();
}

93
test/node-spv-test.js Normal file
View file

@ -0,0 +1,93 @@
'use strict';
const assert = require('bsert');
const SPVNode = require('../lib/node/spvnode');
const rules = require('../lib/covenants/rules');
describe('SPV Node', function() {
describe('Filter update', function() {
const node = new SPVNode({
memory: true,
network: 'regtest',
plugins: [require('../lib/wallet/plugin')]
});
const pool = node.pool;
const {wdb} = node.require('walletdb');
let wallet;
const name1 = 'control'; // never add
const hash1 = rules.hashName(name1);
const name2 = 'lettuce';
const hash2 = rules.hashName(name2);
const name3 = 'tomato';
const hash3 = rules.hashName(name3);
// This function normally calls
// peer.sendFilterLoad(this.spvFilter)
// for each peer in pool.
// This stub hands us the filter directly without any p2p connections.
pool.sendFilterLoad = () => {
pool.emit('filter load', pool.spvFilter);
};
before(async () => {
await node.open();
wallet = await wdb.get('primary');
});
after(async () => {
await node.close();
});
it('should test false for all names', () => {
assert(!wdb.filter.test(hash1));
assert(!wdb.filter.test(hash2));
assert(!wdb.filter.test(hash3));
assert(!pool.spvFilter.test(hash1));
assert(!pool.spvFilter.test(hash2));
assert(!pool.spvFilter.test(hash3));
});
it('should import name (wallet) and update filter', async () => {
const waiter = new Promise((resolve) => {
pool.once('filter load', (filter) => {
resolve(filter);
});
});
await wallet.importName(name2);
// WalletDB filter has added name
assert(!wdb.filter.test(hash1));
assert(wdb.filter.test(hash2));
assert(!wdb.filter.test(hash3));
// Filter sent from pool has also added name
const filter = await waiter;
assert(!filter.test(hash1));
assert(filter.test(hash2));
assert(!filter.test(hash3));
});
it('should watch name (pool) and update filter again', async () => {
const waiter = new Promise((resolve) => {
pool.once('filter load', (filter) => {
resolve(filter);
});
});
await pool.watchName(hash3);
// Filter sent from pool has added name
const filter = await waiter;
assert(!filter.test(hash1));
assert(filter.test(hash2));
assert(filter.test(hash3));
// ...so has walletDB filter
// (seems backwards, but the filters are the same literal object)
assert(!wdb.filter.test(hash1));
assert(wdb.filter.test(hash2));
assert(wdb.filter.test(hash3));
});
});
});