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

Cover reorg for double open index #875

Merged
merged 3 commits into from
Dec 11, 2023
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
4 changes: 4 additions & 0 deletions lib/wallet/records.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,10 @@ class MapRecord extends bio.Struct {
return this.wids.delete(wid);
}

has(wid) {
return this.wids.has(wid);
}

write(bw) {
bw.writeU32(this.wids.size);

Expand Down
49 changes: 44 additions & 5 deletions lib/wallet/txdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,6 @@ class TXDB {

/**
* Add transaction without a batch.
* @private
* @param {TX} tx
* @param {BlockMeta} [block]
* @returns {Promise<Details?>}
Expand Down Expand Up @@ -880,6 +879,11 @@ class TXDB {
if (!hash)
continue;

const wtx = await this.getTX(hash);

if (wtx.height !== -1)
return;

await this.remove(hash);
}
}
Expand Down Expand Up @@ -1041,6 +1045,7 @@ class TXDB {
}

await this.saveCredit(b, credit, path);
await this.watchOpensEarly(b, output);
}

// Handle names.
Expand Down Expand Up @@ -1278,6 +1283,8 @@ class TXDB {
// Commit the new state. The balance has updated.
const balance = await this.updateBalance(b, state);

this.unindexOpens(b, tx);

await b.write();

this.unlockTX(tx);
Expand Down Expand Up @@ -1533,6 +1540,14 @@ class TXDB {
if (tx.isCoinbase())
return this.removeRecursive(wtx);

// On unconfirm, if we already have OPEN txs in the pending list we
// remove transaction and it's descendants instead of storing them in
// the pending list. This follows the mempool behaviour where the first
// entries in the mempool will be the ones left, instead of txs coming
// from the block. This ensures consistency with the double open rules.
if (await this.isDoubleOpen(tx))
return this.removeRecursive(wtx);

return this.disconnect(wtx, wtx.getBlock());
}

Expand Down Expand Up @@ -1650,6 +1665,10 @@ class TXDB {
await this.saveCredit(b, credit, path);
}

// Unconfirm will also index OPENs as the transaction is now part of the
// wallet pending transactions.
this.indexOpens(b, tx);

// Undo name state.
await this.undoNameState(b, tx);

Expand Down Expand Up @@ -1834,12 +1853,33 @@ class TXDB {
}
}

/**
* Start tracking OPENs right away.
* This does not check if the name is owned by the wallet.
* @private
* @param {Batch} b
* @param {Output} tx
* @param {Path} path
* @returns {Promise}
*/

async watchOpensEarly(b, output) {
const {covenant} = output;

if (!covenant.isOpen())
return;

const nameHash = covenant.getHash(0);

if (!await this.wdb.hasNameMap(nameHash, this.wid))
await this.addNameMap(b, nameHash);
}

/**
* Handle incoming covenant.
* @param {Object} b
* @param {TX} tx
* @param {Number} i
* @param {Path} path
* @param {CoinView} view
* @param {Number} height
* @returns {Promise<Boolean>} updated
*/
Expand Down Expand Up @@ -1898,8 +1938,7 @@ class TXDB {
case types.OPEN: {
if (!path) {
// Are we "watching" this name?
const map = await this.wdb.getNameMap(nameHash);
if (!map || !map.wids.has(this.wid))
if (!await this.wdb.hasNameMap(nameHash, this.wid))
break;

const name = covenant.get(2);
Expand Down
30 changes: 29 additions & 1 deletion lib/wallet/walletdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,22 @@ class WalletDB extends EventEmitter {
return MapRecord.decode(data);
}

/**
* Does wdb have wallet map.
* @param {Buffer} key
* @param {Number} wid
* @returns {Promise<Boolean>}
*/

async hasMap(key, wid) {
const map = await this.getMap(key);

if (!map)
return false;

return map.has(wid);
}

/**
* Add wid to a wallet map.
* @param {Wallet} wallet
Expand Down Expand Up @@ -2116,6 +2132,17 @@ class WalletDB extends EventEmitter {
return this.getMap(layout.N.encode(nameHash));
}

/**
* Has wid in the wallet map.
* @param {Buffer} nameHash
* @param {Number} wid
* @returns {Promise<Boolean>}
*/

async hasNameMap(nameHash, wid) {
return this.hasMap(layout.N.encode(nameHash), wid);
}

/**
* Add wid to a wallet map.
* @param {Wallet} wallet
Expand Down Expand Up @@ -2215,7 +2242,7 @@ class WalletDB extends EventEmitter {
/**
* Revert TXDB to an older state.
* @param {Number} target
* @returns {Promise}
* @returns {Promise<Number>}
*/

async revert(target) {
Expand All @@ -2241,6 +2268,7 @@ class WalletDB extends EventEmitter {
});

this.logger.info('Rolled back %d WalletDB transactions.', total);
return total;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions test/mempool-invalidation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ describe('Mempool Invalidation', function() {
assert.strictEqual(await getNameState(name), states.OPENING);

assert.strictEqual(node.mempool.map.size, 0);
// we don't want coins to get stuck in the wallet.
wallet2.abandon(memopen.hash());
const pending = await wallet2.getPending();
assert.strictEqual(pending.length, 0);
});

it('should invalidate bids', async () => {
Expand Down
Loading
Loading