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;
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.height,
block.getSize(),

View File

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

View File

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

View File

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