Skip to content

Commit

Permalink
txdb: fix conflict event bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Sep 28, 2023
1 parent 4e87fb1 commit 4527ff6
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 9 deletions.
9 changes: 6 additions & 3 deletions lib/wallet/txdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ class TXDB {
* database. Disconnect inputs.
* @private
* @param {TXRecord} wtx
* @returns {Promise}
* @returns {Promise<Details?>}
*/

async erase(wtx, block) {
Expand Down Expand Up @@ -1420,7 +1420,7 @@ class TXDB {
* remove all of its spenders.
* @private
* @param {TXRecord} wtx
* @returns {Promise}
* @returns {Promise<Details?>}
*/

async removeRecursive(wtx) {
Expand Down Expand Up @@ -1632,7 +1632,7 @@ class TXDB {
* @private
* @param {Hash} hash
* @param {TX} ref - Reference tx, the tx that double-spent.
* @returns {Promise} - Returns Boolean.
* @returns {Promise<Details?>} - Returns Boolean.
*/

async removeConflict(wtx) {
Expand All @@ -1642,6 +1642,9 @@ class TXDB {

const details = await this.removeRecursive(wtx);

if (!details)
return null;

this.logger.warning('Removed conflict: %x.', tx.hash());

// Emit the _removed_ transaction.
Expand Down
138 changes: 132 additions & 6 deletions test/wallet-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,16 +361,16 @@ describe('Wallet', function() {
await wdb.addTX(t1.toTX());
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);

let conflict = false;
let conflict = 0;
wallet.on('conflict', () => {
conflict = true;
conflict += 1;
});

const t2 = new MTX();
t2.addInput(input);
t2.addOutput(new Address(), 5000);
await wdb.addTX(t2.toTX());
assert(conflict);
assert.strictEqual(conflict, 1);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 0);
});

Expand All @@ -389,9 +389,9 @@ describe('Wallet', function() {
await wdb.addTX(txa.toTX());
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);

let conflict = false;
let conflict = 0;
wallet.on('conflict', () => {
conflict = true;
conflict += 1;
});

const txb = new MTX();
Expand All @@ -400,10 +400,96 @@ describe('Wallet', function() {
txb.addOutput(address, 49000);
await wdb.addTX(txb.toTX());

assert(conflict);
assert.strictEqual(conflict, 1);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 49000);
});

it('should handle double-spend (with block)', async () => {
const wallet = await wdb.create();
const address = await wallet.receiveAddress();

const hash = random.randomBytes(32);
const input0 = Input.fromOutpoint(new Outpoint(hash, 0));
const input1 = Input.fromOutpoint(new Outpoint(hash, 1));

const txa = new MTX();
txa.addInput(input0);
txa.addInput(input1);
txa.addOutput(address, 50000);
await wdb.addTX(txa.toTX());
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);

let conflict = 0;
wallet.on('conflict', () => {
conflict += 1;
});

const txb = new MTX();
txb.addInput(input0);
txb.addInput(input1);
txb.addOutput(address, 49000);

await wdb.addBlock(nextBlock(wdb), [txb.toTX()]);
assert.strictEqual(conflict, 1);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 49000);
assert.strictEqual((await wallet.getBalance()).confirmed, 49000);
});

it('should recover from interrupt when removing conflict', async () => {
const wallet = await wdb.create();
const address = await wallet.receiveAddress();

const hash = random.randomBytes(32);
const input0 = Input.fromOutpoint(new Outpoint(hash, 0));
const input1 = Input.fromOutpoint(new Outpoint(hash, 1));

const txa = new MTX();
txa.addInput(input0);
txa.addInput(input1);
txa.addOutput(address, 50000);

await wdb.addTX(txa.toTX());
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);
assert.strictEqual((await wallet.getBalance()).confirmed, 0);

let conflict = 0;
wallet.on('conflict', () => {
conflict += 1;
});

const txb = new MTX();
txb.addInput(input0);
txb.addInput(input1);
txb.addOutput(address, 49000);

const removeConflict = wallet.txdb.removeConflict;

wallet.txdb.removeConflict = async () => {
throw new Error('Unexpected interrupt.');
};

const entry = nextBlock(wdb);

await assert.rejects(async () => {
await wdb.addBlock(entry, [txb.toTX()]);
}, {
name: 'Error',
message: 'Unexpected interrupt.'
});

wallet.txdb.removeConflict = removeConflict;

assert.strictEqual(conflict, 0);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);
assert.strictEqual((await wallet.getBalance()).confirmed, 0);

await wdb.addBlock(entry, [txb.toTX()]);

assert.strictEqual(conflict, 1);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 49000);
assert.strictEqual((await wallet.getBalance()).confirmed, 49000);
});

it('should handle more missed txs', async () => {
const alice = await wdb.create();
const bob = await wdb.create();
Expand Down Expand Up @@ -2750,6 +2836,46 @@ describe('Wallet', function() {
assert.equal(txCount, 1);
assert.equal(confirmedCount, 1);
});

it('should emit conflict event (multiple inputs)', async () => {
const wallet = await wdb.create({id: 'test2'});
const address = await wallet.receiveAddress();

const wclient = new WalletClient({port: ports.wallet});
await wclient.open();

const cwallet = wclient.wallet(wallet.id, wallet.token);
await cwallet.open();

try {
const hash = random.randomBytes(32);
const input0 = Input.fromOutpoint(new Outpoint(hash, 0));
const input1 = Input.fromOutpoint(new Outpoint(hash, 1));

const txa = new MTX();
txa.addInput(input0);
txa.addInput(input1);
txa.addOutput(address, 50000);
await wdb.addTX(txa.toTX());
assert.strictEqual((await wallet.getBalance()).unconfirmed, 50000);

let conflict = 0;
cwallet.on('conflict', () => {
conflict += 1;
});

const txb = new MTX();
txb.addInput(input0);
txb.addInput(input1);
txb.addOutput(address, 49000);
await wdb.addTX(txb.toTX());

assert.strictEqual(conflict, 1);
assert.strictEqual((await wallet.getBalance()).unconfirmed, 49000);
} finally {
await wclient.close();
}
});
});

describe('Wallet Name Claims', function() {
Expand Down

0 comments on commit 4527ff6

Please sign in to comment.