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

Fix the wallet double open bug #4

Merged
merged 3 commits into from
Aug 10, 2019
Merged
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
15 changes: 13 additions & 2 deletions lib/wallet/txdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -827,9 +827,20 @@ class TXDB {

const nameHash = covenant.getHash(0);
const key = layout.o.encode(nameHash);
const hash = await this.bucket.get(key);

if (await this.bucket.has(key))
return true;
// Allow a double open if previous auction period has expired
// this is not a complete check for name availability or status!
if (hash) {
const names = this.wdb.network.names;
const period = names.biddingPeriod + names.revealPeriod;
const oldTX = await this.getTX(hash);
if (oldTX.height !== -1 && oldTX.height + period < this.wdb.height) {
return false;
} else {
return true;
}
}
}

return false;
Expand Down
191 changes: 191 additions & 0 deletions test/wallet-auction-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/* eslint-env mocha */
/* eslint prefer-arrow-callback: "off" */
/* eslint no-return-assign: "off" */

'use strict';

const assert = require('bsert');
const Chain = require('../lib/blockchain/chain');
const WorkerPool = require('../lib/workers/workerpool');
const Miner = require('../lib/mining/miner');
const WalletDB = require('../lib/wallet/walletdb');
const Network = require('../lib/protocol/network');
const rules = require('../lib/covenants/rules');

const network = Network.get('regtest');
const NAME1 = rules.grindName(10, 20, network);

const workers = new WorkerPool({
enabled: false
});

const chain = new Chain({
memory: true,
network,
workers
});

const miner = new Miner({
chain,
workers
});

const cpu = miner.cpu;

const wdb = new WalletDB({
network: network,
workers: workers
});

describe('Wallet Auction', function() {
this.timeout(15000);

let winner;
const currentCBMaturity = network.coinbaseMaturity;

before(() => {
network.coinbaseMaturity = 1;
});

after(() => {
network.coinbaseMaturity = currentCBMaturity;
});

it('should open chain, miner and wallet', async () => {
await chain.open();
await miner.open();
await wdb.open();

winner = await wdb.create();

chain.on('connect', async (entry, block) => {
await wdb.addBlock(entry, block.txs);
});
});

it('should add addrs to miner', async () => {
const addr = await winner.createReceive();
miner.addresses = [addr.getAddress().toString(network)];
});

it('should mine 20 blocks', async () => {
for (let i = 0; i < 20; i++) {
const block = await cpu.mineBlock();
assert(block);
assert(await chain.add(block));
}
});

let openAuctionMTX;
it('should open auction', async () => {
openAuctionMTX = await winner.createOpen(NAME1, false);
await winner.sign(openAuctionMTX);
const tx = openAuctionMTX.toTX();
await wdb.addTX(tx);
});

it('should fail to create duplicate open', async () => {
let err;
try {
await winner.createOpen(NAME1, false);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.message, `Already sent an open for: ${NAME1}.`);
});

it('should mine 1 block', async () => {
const job = await cpu.createJob();
job.addTX(openAuctionMTX.toTX(), openAuctionMTX.view);
job.refresh();

const block = await job.mineAsync();

assert(await chain.add(block));
});

it('should fail to re-open auction during OPEN phase', async () => {
let err;
try {
await winner.createOpen(NAME1, false);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.message, 'Name is already opening.');
});

it('should mine enough blocks to enter BIDDING phase', async () => {
for (
let i = 0;
i < network.names.treeInterval;
i++
) {
const block = await cpu.mineBlock();
assert(block);
assert(await chain.add(block));
}
});

it('should fail to re-open auction during BIDDING phase', async () => {
let err;
try {
await winner.createOpen(NAME1, false);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.message, 'Name is not available.');
});

it('should mine enough blocks to expire auction', async () => {
for (
let i = 0;
i < network.names.biddingPeriod + network.names.revealPeriod;
i++
) {
const block = await cpu.mineBlock();
assert(block);
assert(await chain.add(block));
}
});

let openAuctionMTX2;
it('should open auction (again)', async () => {
openAuctionMTX2 = await winner.createOpen(NAME1, false);
await winner.sign(openAuctionMTX2);
const tx = openAuctionMTX2.toTX();
await wdb.addTX(tx);
});

it('should fail to create duplicate open (again)', async () => {
let err;
try {
await winner.createOpen(NAME1, false);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.message, `Already sent an open for: ${NAME1}.`);
});

it('should mine 1 block', async () => {
const job = await cpu.createJob();
job.addTX(openAuctionMTX2.toTX(), openAuctionMTX2.view);
job.refresh();

const block = await job.mineAsync();

assert(await chain.add(block));
});

it('should cleanup', async () => {
await miner.close();
await chain.close();
});
});