bip152: implement segwit compact blocks.
This commit is contained in:
parent
cf5349cdaa
commit
62ef5ea7f4
@ -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(),
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user