Skip to content

Commit

Permalink
mempool: handleReorg checks block commitment in Claims
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Jan 2, 2020
1 parent d8feadd commit fb88597
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
9 changes: 6 additions & 3 deletions lib/mempool/mempool.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,12 @@ class Mempool extends EventEmitter {
this.contracts.clear();

for (const entry of this.claims.values()) {
// The only thing that might make a Claim invalid when rewinding the
// blockchain is the inception time of the signatures in the DNSSEC proof.
if (this.chain.tip.time < entry.inception) {
// The only things that might make a Claim invalid when rewinding the
// blockchain is the inception time of the signatures in the DNSSEC proof
// and the historical block committed to by the covenant.
if (this.chain.tip.time < entry.inception
|| entry.commitHeight > this.chain.tip.height
|| !await this.chain.isMainHash(entry.commitHash)) {
// Claim is not still valid, remove from mempool and contract state.
this.untrackClaim(entry);
} else {
Expand Down
96 changes: 95 additions & 1 deletion test/mempool-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ describe('Mempool', function() {
assert(!mempool.getTX(bid.hash()));
});

it('should handle reorg: name claim', async () => {
it('should handle reorg: name claim - DNSSEC timestamp', async () => {
// Mempool is empty
await mempool.reset();
assert.strictEqual(mempool.map.size, 0);
Expand Down Expand Up @@ -987,5 +987,99 @@ describe('Mempool', function() {
assert.strictEqual(mempool.claims.size, 0);
assert(!mempool.getClaim(claim.hash()));
});

it('should handle reorg: name claim - block commitment', async () => {
// Mempool is empty
await mempool.reset();
assert.strictEqual(mempool.map.size, 0);

// Create a fake claim - just to get the correct timestamps
let claim = await chaincoins.fakeClaim('cloudflare');

// Fast-forward the next block's timestamp to allow claim.
const data = claim.getData(mempool.network);
const [block1] = await getMockBlock(chain);
block1.time = data.inception + 100;
try {
ownership.ignore = true;
await chain.add(block1, VERIFY_BODY);
} finally {
ownership.ignore = false;
}

// Add a few more blocks
let block2;
let view2;
let entry2;
for (let i = 0; i < 10; i++) {
[block2, view2] = await getMockBlock(chain);
entry2 = await chain.add(block2, VERIFY_BODY);

await mempool._addBlock(entry2, block2.txs, view2);
}

// Get *very* recent block for commitment
const options = {
commitHeight: chain.tip.height,
commitHash: chain.tip.hash
};

// Update the claim with the new block commitment
claim = await chaincoins.fakeClaim('cloudflare', options);

// Now we can add it to the mempool.
try {
ownership.ignore = true;
await mempool.addClaim(claim);
} finally {
ownership.ignore = false;
}
assert.strictEqual(mempool.claims.size, 1);
assert(mempool.getClaim(claim.hash()));

// Confirm the claim in the next block.
// Note: Claim.toTX() creates a coinbase-shaped TX
const cb = claim.toTX(mempool.network, chain.tip.height + 1);
cb.locktime = chain.tip.height + 1;
const [block3, view3] = await getMockBlock(chain, [cb], false);
let entry3;
try {
ownership.ignore = true;
entry3 = await chain.add(block3, VERIFY_BODY);
await mempool._addBlock(entry3, block3.txs, view3);
} finally {
ownership.ignore = false;
}

// Mempool is empty
assert.strictEqual(mempool.claims.size, 0);
assert.strictEqual(mempool.map.size, 0);

// Now the block gets disconnected
await chain.disconnect(entry3);
await mempool._removeBlock(entry3, block3.txs);
await mempool._handleReorg();

// Claim is back in the mempool
assert.strictEqual(mempool.claims.size, 1);
assert(mempool.getClaim(claim.hash()));

// Now remove one more block from the chain, making the tip
// too old for the claim's block commitment.
await chain.disconnect(entry2);
await mempool._removeBlock(entry2, block2.txs);

// Claim is still in the mempool.
assert.strictEqual(mempool.claims.size, 1);
assert(mempool.getClaim(claim.hash()));

// This is normally triggered by 'reorganize' event
await mempool._handleReorg();

// Premature claim has been evicted
assert.strictEqual(mempool.map.size, 0);
assert.strictEqual(mempool.claims.size, 0);
assert(!mempool.getClaim(claim.hash()));
});
});
});

0 comments on commit fb88597

Please sign in to comment.