Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neutrino: getblockpeer #1167

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
27 changes: 26 additions & 1 deletion lib/blockchain/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Chain extends AsyncEmitter {

this.orphanMap = new BufferMap();
this.orphanPrev = new BufferMap();

this.getPrunedMap = new BufferMap();
}

/**
Expand Down Expand Up @@ -1368,7 +1370,15 @@ class Chain extends AsyncEmitter {
}

// Do we already have this block?
if (await this.hasEntry(hash)) {
const existingEntry = await this.getEntry(hash);

if (existingEntry && this.getPrunedMap.has(hash)) {
block = block.toBlock();
this.emit('getblockpeer', existingEntry, block);
return null;
}

if (existingEntry) {
this.logger.debug('Already have block: %h.', block.hash());
throw new VerifyError(block, 'duplicate', 'duplicate', 0);
}
Expand Down Expand Up @@ -1925,6 +1935,21 @@ class Chain extends AsyncEmitter {
return this.db.getBlock(hash);
}

async getBlockPeer(hash) {
this.logger.warning('Block not found, attempting to download');

// Ensure hash not height
hash = await this.db.getHash(hash);

const wait = new Promise((resolve, reject) => {
this.getPrunedMap.set(hash, resolve);
});

await this.emitAsync('getprunedblock', hash);
await wait;
return;
}

/**
* Retrieve a block from the database (not filled with coins).
* @param {Hash} block
Expand Down
5 changes: 2 additions & 3 deletions lib/client/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ class NodeClient extends Client {
* @returns {Promise}
*/

getFilter(filter) {
assert(typeof filter === 'string' || typeof filter === 'number');
return this.get(`/filter/${filter}`);
getBlockPeer(hash) {
return this.call('get block peer', hash);
}

/**
Expand Down
34 changes: 32 additions & 2 deletions lib/net/pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ class Pool extends EventEmitter {
this.handleBadOrphan('block', err, id);
});

this.chain.on('getprunedblock', async (hash) => {
// Find the first peer with a completed handshake
for (let peer = this.peers.head(); peer; peer = peer.next) {
if (!peer.handshake)
continue;

await this.getBlock(peer, [hash]);
}
});

if (this.mempool) {
this.mempool.on('tx', (tx) => {
this.emit('tx', tx);
Expand Down Expand Up @@ -2293,7 +2303,7 @@ class Pool extends EventEmitter {

const hash = block.hash();

if (!this.resolveBlock(peer, hash)) {
if (!this.options.neutrino && !this.resolveBlock(peer, hash)) {
this.logger.warning(
'Received unrequested block: %h (%s).',
block.hash(), peer.hostname());
Expand All @@ -2316,6 +2326,14 @@ class Pool extends EventEmitter {
}

// Block was orphaned.

const resolve = this.chain.getPrunedMap.get(hash);
if (resolve) {
this.logger.warning('Received pruned block by special request');
this.chain.getPrunedMap.delete(hash);
resolve();
}

if (!entry) {
if (this.checkpoints) {
this.logger.warning(
Expand Down Expand Up @@ -3690,6 +3708,7 @@ class PoolOptions {
this.prefix = null;
this.checkpoints = true;
this.spv = false;
this.neutrino = false;
this.bip37 = false;
this.bip157 = false;
this.listen = false;
Expand Down Expand Up @@ -3772,12 +3791,17 @@ class PoolOptions {

if (options.spv != null) {
assert(typeof options.spv === 'boolean');
assert(options.spv === this.chain.options.spv);
this.spv = options.spv;
} else {
this.spv = this.chain.options.spv;
}

if (options.neutrino != null) {
assert(options.compact !== true);
assert(typeof options.neutrino === 'boolean');
this.neutrino = options.neutrino;
}

if (options.bip37 != null) {
assert(typeof options.bip37 === 'boolean');
this.bip37 = options.bip37;
Expand Down Expand Up @@ -3953,6 +3977,12 @@ class PoolOptions {
this.listen = false;
}

if (this.neutrino) {
this.requiredServices |= common.services.NODE_COMPACT_FILTERS;
this.checkpoints = true;
this.compact = false;
}

if (this.selfish) {
this.services &= ~common.services.NETWORK;
this.bip37 = false;
Expand Down
6 changes: 6 additions & 0 deletions lib/node/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,12 @@ class HTTP extends Server {
return null;
});

socket.hook('get block peer', (...args) => {
const valid = new Validator(args);
const hash = valid.hash(0);
return this.chain.getBlockPeer(hash);
});

socket.hook('estimate fee', (...args) => {
const valid = new Validator(args);
const blocks = valid.u32(0);
Expand Down
11 changes: 11 additions & 0 deletions lib/wallet/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ class WalletClient extends NodeClient {
return super.setFilter(filter.toRaw());
}

/**
* Check filter against wallet key ring
* @param {WalletKey} ring
* @param {Filter} filter
* @returns {Promise}
*/

async getBlockFromNode(hash) {
return super.getBlockPeer(hash);
}

async rescan(start) {
if (Buffer.isBuffer(start))
start = util.revHex(start);
Expand Down
11 changes: 11 additions & 0 deletions lib/wallet/nodeclient.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ class NodeClient extends AsyncEmitter {

init() {
this.node.chain.on('connect', async (entry, block) => {
if (!this.opened || this.node.neutrino)
return;

await this.emitAsync('block connect', entry, block.txs);
});

this.node.chain.on('getblockpeer', async (entry, block) => {
if (!this.opened)
return;

Expand Down Expand Up @@ -134,6 +141,10 @@ class NodeClient extends AsyncEmitter {
return entry;
}

async getBlockFromNode(hash) {
await this.node.chain.getBlockPeer(hash);
}

/**
* Send a transaction. Do not wait for promise.
* @param {TX} tx
Expand Down
11 changes: 11 additions & 0 deletions lib/wallet/nullclient.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ class NullClient extends EventEmitter {
this.wdb.emit('reset filter');
}

/**
* Check filter against wallet key ring
* @param {WalletKey} ring
* @param {Filter} filter
* @returns {Promise}
*/

async getBlockFromNode(hash) {
;
}

/**
* Esimate smart fee.
* @param {Number?} blocks
Expand Down