bip152: implement segwit compact blocks.

This commit is contained in:
Christopher Jeffrey 2016-11-06 22:34:05 -08:00
parent cf5349cdaa
commit 62ef5ea7f4
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 41 additions and 33 deletions

View File

@ -1317,7 +1317,7 @@ Chain.prototype.finish = function finish(block, entry) {
time = elapsed[0] * 1000 + elapsed[1] / 1e6; time = elapsed[0] * 1000 + elapsed[1] / 1e6;
this.logger.info( this.logger.info(
'Block %s (%d) added to chain (size=%d, txs=%d time=%d).', 'Block %s (%d) added to chain (size=%d txs=%d time=%d).',
entry.rhash, entry.rhash,
entry.height, entry.height,
block.getSize(), block.getSize(),

View File

@ -183,13 +183,20 @@ CompactBlock.prototype.toRequest = function toRequest() {
return TXRequest.fromCompact(this); return TXRequest.fromCompact(this);
}; };
CompactBlock.prototype.fillMempool = function fillMempool(mempool) { CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
var have = {}; var have = {};
var hashes = mempool.getSnapshot(); var hashes = mempool.getSnapshot();
var i, id, index, hash, tx; var i, id, index, hash, tx;
for (i = 0; i < hashes.length; i++) { for (i = 0; i < hashes.length; i++) {
hash = hashes[i]; hash = hashes[i];
tx = mempool.getTX(hash);
assert(tx);
hash = tx.hash();
if (witness)
hash = tx.witnessHash();
id = this.sid(hash); id = this.sid(hash);
index = this.idMap[id]; index = this.idMap[id];
@ -203,11 +210,6 @@ CompactBlock.prototype.fillMempool = function fillMempool(mempool) {
continue; continue;
} }
tx = mempool.getTX(hash);
if (!tx)
continue;
this.available[index] = tx; this.available[index] = tx;
have[index] = true; have[index] = true;
this.count++; this.count++;
@ -334,8 +336,8 @@ CompactBlock.prototype.toBlock = function toBlock() {
return block; return block;
}; };
CompactBlock.prototype.fromBlock = function fromBlock(block, nonce) { CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
var i, tx, id; var i, tx, hash, id;
this.version = block.version; this.version = block.version;
this.prevBlock = block.prevBlock; this.prevBlock = block.prevBlock;
@ -354,7 +356,10 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, nonce) {
for (i = 1; i < block.txs.length; i++) { for (i = 1; i < block.txs.length; i++) {
tx = block.txs[i]; tx = block.txs[i];
id = this.sid(tx.hash()); hash = tx.hash();
if (witness)
hash = tx.witnessHash();
id = this.sid(hash);
this.ids.push(id); this.ids.push(id);
} }
@ -363,8 +368,8 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, nonce) {
return this; return this;
}; };
CompactBlock.fromBlock = function fromBlock(block, nonce) { CompactBlock.fromBlock = function fromBlock(block, witness, nonce) {
return new CompactBlock().fromBlock(block, nonce); return new CompactBlock().fromBlock(block, witness, nonce);
}; };
CompactBlock.prototype.wait = function wait(time) { CompactBlock.prototype.wait = function wait(time) {

View File

@ -106,6 +106,7 @@ function Peer(pool, addr, socket) {
this.syncSent = false; this.syncSent = false;
this.connectTimeout = null; this.connectTimeout = null;
this.compactMode = null; this.compactMode = null;
this.compactWitness = false;
this.compactBlocks = {}; this.compactBlocks = {};
this.sentAddr = false; this.sentAddr = false;
this.bip151 = null; this.bip151 = null;
@ -523,7 +524,7 @@ Peer.prototype.announce = co(function* announce(items) {
if (item instanceof Block) { if (item instanceof Block) {
if (!this.invFilter.added(item.hash())) if (!this.invFilter.added(item.hash()))
continue; continue;
yield this._sendCompactBlock(item, false); yield this._sendCompactBlock(item, this.compactWitness);
continue; continue;
} }
} }
@ -1543,12 +1544,12 @@ Peer.prototype._getItem = co(function* _getItem(item) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Peer.prototype._sendBlock = co(function* _sendBlock(item) { Peer.prototype._sendBlock = co(function* _sendBlock(item, witness) {
var block = this._getBroadcasted(item); var block = this._getBroadcasted(item);
// Check for a broadcasted item first. // Check for a broadcasted item first.
if (block) { if (block) {
yield this.send(new packets.BlockPacket(block, item.hasWitness())); yield this.send(new packets.BlockPacket(block, witness));
return true; return true;
} }
@ -1560,7 +1561,7 @@ Peer.prototype._sendBlock = co(function* _sendBlock(item) {
// If we have the same serialization, we // If we have the same serialization, we
// can write the raw binary to the socket. // can write the raw binary to the socket.
if (item.hasWitness() === !!this.options.witness) { if (witness === !!this.options.witness) {
block = yield this.chain.db.getRawBlock(item.hash); block = yield this.chain.db.getRawBlock(item.hash);
if (!block) if (!block)
@ -1573,7 +1574,7 @@ Peer.prototype._sendBlock = co(function* _sendBlock(item) {
if (!block) if (!block)
return false; return false;
yield this.send(new packets.BlockPacket(block, item.hasWitness())); yield this.send(new packets.BlockPacket(block, witness));
} }
return true; return true;
@ -1581,7 +1582,8 @@ Peer.prototype._sendBlock = co(function* _sendBlock(item) {
/** /**
* Send a compact block. * Send a compact block.
* @param {InvItem} item * @param {Block} block
* @param {Boolean} witness
* @returns {Boolean} * @returns {Boolean}
*/ */
@ -1590,7 +1592,7 @@ Peer.prototype._sendCompactBlock = function _sendCompactBlock(block, witness) {
// if we get a siphash collision. // if we get a siphash collision.
for (;;) { for (;;) {
try { try {
block = BIP152.CompactBlock.fromBlock(block); block = BIP152.CompactBlock.fromBlock(block, witness);
} catch (e) { } catch (e) {
continue; continue;
} }
@ -1643,7 +1645,7 @@ Peer.prototype._handleGetData = co(function* _handleGetData(packet) {
switch (item.type) { switch (item.type) {
case constants.inv.BLOCK: case constants.inv.BLOCK:
case constants.inv.WITNESS_BLOCK: case constants.inv.WITNESS_BLOCK:
result = yield this._sendBlock(item); result = yield this._sendBlock(item, item.hasWitness());
if (!result) { if (!result) {
notFound.push(item); notFound.push(item);
continue; continue;
@ -1676,7 +1678,7 @@ Peer.prototype._handleGetData = co(function* _handleGetData(packet) {
case constants.inv.CMPCT_BLOCK: case constants.inv.CMPCT_BLOCK:
// Fallback to full block. // Fallback to full block.
if (block.height < this.chain.tip.height - 10) { if (block.height < this.chain.tip.height - 10) {
result = yield this._sendBlock(item); result = yield this._sendBlock(item, this.compactWitness);
if (!result) { if (!result) {
notFound.push(item); notFound.push(item);
continue; continue;
@ -1691,7 +1693,7 @@ Peer.prototype._handleGetData = co(function* _handleGetData(packet) {
continue; continue;
} }
yield this._sendCompactBlock(block, false); yield this._sendCompactBlock(block, this.compactWitness);
break; break;
default: default:
@ -2099,7 +2101,7 @@ Peer.prototype._handleUnknown = function _handleUnknown(packet) {
*/ */
Peer.prototype._handleSendCmpct = function _handleSendCmpct(packet) { Peer.prototype._handleSendCmpct = function _handleSendCmpct(packet) {
if (packet.version !== 1) { if (packet.version > 2) {
// Ignore // Ignore
this.logger.info('Peer request compact blocks version %d (%s).', this.logger.info('Peer request compact blocks version %d (%s).',
packet.version, this.hostname); packet.version, this.hostname);
@ -2115,6 +2117,7 @@ Peer.prototype._handleSendCmpct = function _handleSendCmpct(packet) {
this.logger.info('Peer initialized compact blocks (%s).', this.hostname); this.logger.info('Peer initialized compact blocks (%s).', this.hostname);
this.compactMode = packet; this.compactMode = packet;
this.compactWitness = packet.version === 2;
this.fire('sendcmpct', packet); this.fire('sendcmpct', packet);
}; };
@ -2148,7 +2151,7 @@ Peer.prototype._handleCmpctBlock = co(function* _handleCmpctBlock(packet) {
this.compactBlocks[hash] = block; this.compactBlocks[hash] = block;
result = block.fillMempool(this.mempool); result = block.fillMempool(this.options.witness, this.mempool);
if (result) { if (result) {
delete this.compactBlocks[hash]; delete this.compactBlocks[hash];
@ -2216,7 +2219,7 @@ Peer.prototype._handleGetBlockTxn = co(function* _handleGetBlockTxn(packet) {
res = BIP152.TXResponse.fromBlock(block, req); res = BIP152.TXResponse.fromBlock(block, req);
yield this.send(new packets.BlockTxnPacket(res, false)); yield this.send(new packets.BlockTxnPacket(res, this.compactWitness));
this.fire('blocktxn', req); this.fire('blocktxn', req);
}); });

View File

@ -215,7 +215,7 @@ describe('Block', function() {
it('should handle compact block', function(cb) { it('should handle compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex');
var block = bcoin.block.fromRaw(cmpct[1], 'hex'); var block = bcoin.block.fromRaw(cmpct[1], 'hex');
var cblock2 = bip152.CompactBlock.fromBlock(block, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
assert.equal(cblock.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock.toRaw().toString('hex'), cmpct[0]);
@ -237,7 +237,7 @@ describe('Block', function() {
assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(fakeMempool); var result = cblock.fillMempool(false, fakeMempool);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++) for (var i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
@ -248,7 +248,7 @@ describe('Block', function() {
it('should handle half-full compact block', function(cb) { it('should handle half-full compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex');
var block = bcoin.block.fromRaw(cmpct[1], 'hex'); var block = bcoin.block.fromRaw(cmpct[1], 'hex');
var cblock2 = bip152.CompactBlock.fromBlock(block, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
assert.equal(cblock.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock.toRaw().toString('hex'), cmpct[0]);
@ -273,7 +273,7 @@ describe('Block', function() {
assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(fakeMempool); var result = cblock.fillMempool(false, fakeMempool);
assert(!result); assert(!result);
var req = cblock.toRequest(); var req = cblock.toRequest();
@ -301,7 +301,7 @@ describe('Block', function() {
it('should handle compact block', function(cb) { it('should handle compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex');
var block = bcoin.block.fromRaw(cmpct2block); var block = bcoin.block.fromRaw(cmpct2block);
var cblock2 = bip152.CompactBlock.fromBlock(block, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
assert.equal(cblock.toRaw().toString('hex'), cmpct2); assert.equal(cblock.toRaw().toString('hex'), cmpct2);
@ -323,7 +323,7 @@ describe('Block', function() {
//assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); //assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(fakeMempool); var result = cblock.fillMempool(false, fakeMempool);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++) for (var i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
@ -334,7 +334,7 @@ describe('Block', function() {
it('should handle half-full compact block', function(cb) { it('should handle half-full compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex');
var block = bcoin.block.fromRaw(cmpct2block); var block = bcoin.block.fromRaw(cmpct2block);
var cblock2 = bip152.CompactBlock.fromBlock(block, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
assert.equal(cblock.toRaw().toString('hex'), cmpct2); assert.equal(cblock.toRaw().toString('hex'), cmpct2);
@ -359,7 +359,7 @@ describe('Block', function() {
//assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); //assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(fakeMempool); var result = cblock.fillMempool(false, fakeMempool);
assert(!result); assert(!result);
var req = cblock.toRequest(); var req = cblock.toRequest();