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

Wallet: Add open/close and connect/disconnect events. #859

Merged
merged 3 commits into from
Oct 20, 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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,21 @@
you run it for the first time.**

### Wallet Changes:
#### Configuration
Wallet now has option `wallet-migrate-no-rescan`/`migrate-no-rescan` if you
want to disable rescan when migration recommends it. It may result in the
incorrect txdb state, but can be useful if you know the issue does not affect
your wallet or is not critical.

#### Wallet API

- Add migration that recalculates txdb balances to fix any inconsistencies.
- WalletDB Now emits events for: `open`, `close`, `connect`, `disconnect`.
- WalletDB
- `open()` no longer calls `connect` and needs separate call `connect`.
- `open()` no longer calls scan, instead only rollbacks and waits for
sync to do the rescan.
- emits events for: `open`, `close`, `connect`, `disconnect`, `sync done`.
- HTTP Changes:
- All transaction creating endpoints now accept `hardFee` for specifying the
exact fee.
Expand Down
3 changes: 3 additions & 0 deletions lib/wallet/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class WalletNode extends Node {
wipeNoReally: this.config.bool('wipe-no-really'),
spv: this.config.bool('spv'),
walletMigrate: this.config.uint('migrate'),
migrateNoRescan: this.config.bool('migrate-no-rescan', false),
icannlockup: this.config.bool('icannlockup', false)
});

Expand Down Expand Up @@ -107,6 +108,7 @@ class WalletNode extends Node {
await this.openPlugins();

await this.http.open();
await this.wdb.connect();
await this.handleOpen();

this.logger.info('Wallet node is loaded.');
Expand All @@ -128,6 +130,7 @@ class WalletNode extends Node {

this.rpc.wallet = null;

await this.wdb.disconnect();
await this.wdb.close();
await this.handleClose();
}
Expand Down
3 changes: 3 additions & 0 deletions lib/wallet/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Plugin extends EventEmitter {
wipeNoReally: this.config.bool('wipe-no-really'),
spv: node.spv,
walletMigrate: this.config.uint('migrate'),
migrateNoRescan: this.config.bool('migrate-no-rescan', false),
icannlockup: this.config.bool('icannlockup', false)
});

Expand Down Expand Up @@ -90,11 +91,13 @@ class Plugin extends EventEmitter {
await this.wdb.open();
this.rpc.wallet = this.wdb.primary;
await this.http.open();
await this.wdb.connect();
}

async close() {
await this.http.close();
this.rpc.wallet = null;
await this.wdb.disconnect();
await this.wdb.close();
}
}
Expand Down
71 changes: 55 additions & 16 deletions lib/wallet/walletdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,18 @@ class WalletDB extends EventEmitter {
this.name = 'wallet';
this.version = 2;

this.primary = null;
// chain state.
this.hasStateCache = false;
this.state = new ChainState();
this.confirming = false;
this.height = 0;

// wallets
this.primary = null;
this.wallets = new Map();
this.depth = 0;

// guards
this.confirming = false;
this.rescanning = false;
this.filterSent = false;

Expand Down Expand Up @@ -122,6 +128,7 @@ class WalletDB extends EventEmitter {
});

this.client.on('connect', async () => {
this.emit('connect');
try {
await this.syncNode();
this.emit('sync done', this.state);
Expand All @@ -131,6 +138,7 @@ class WalletDB extends EventEmitter {
});

this.client.on('disconnect', async () => {
this.emit('disconnect');
this.filterSent = false;
});

Expand Down Expand Up @@ -201,7 +209,7 @@ class WalletDB extends EventEmitter {
await this.wipe();

await this.watch();
await this.connect();
await this.loadState();

this.logger.info(
'WalletDB loaded (depth=%d, height=%d, start=%d).',
Expand All @@ -222,9 +230,17 @@ class WalletDB extends EventEmitter {
this.primary = wallet;

if (migrationResult.rescan) {
this.logger.info('Rescanning...');
await this.scan(0);
if (!this.options.migrateNoRescan) {
this.logger.info('Migration rollback...');
await this.rollback(0);
} else {
this.logger.warning(
'Migration rescan skipped, state may be incorrect.');
}
}

this.logger.info('WalletDB opened.');
this.emit('open');
}

/**
Expand Down Expand Up @@ -270,14 +286,17 @@ class WalletDB extends EventEmitter {
*/

async close() {
await this.disconnect();
if (this.client.opened)
await this.disconnect();

for (const wallet of this.wallets.values()) {
await wallet.destroy();
this.unregister(wallet);
}

return this.db.close();
await this.db.close();
this.logger.info('WalletDB Closed.');
this.emit('close');
}

/**
Expand Down Expand Up @@ -368,7 +387,7 @@ class WalletDB extends EventEmitter {
const unlock = await this.txLock.lock();
try {
this.logger.info('Resyncing from server...');
await this.syncState();
await this.syncInitState();
await this.syncFilter();
await this.syncChain();
await this.resend();
Expand All @@ -378,18 +397,31 @@ class WalletDB extends EventEmitter {
}

/**
* Initialize and write initial sync state.
* Recover state from the cache.
* @returns {Promise}
*/

async syncState() {
async loadState() {
const cache = await this.getState();

if (cache) {
this.state = cache;
this.height = cache.height;
return undefined;
}
if (!cache)
return;

this.logger.info('Initialized chain state from the database.');
this.hasStateCache = true;
this.state = cache;
this.height = cache.height;
}

/**
* Initialize and write initial sync state.
* @returns {Promise}
*/

async syncInitState() {
// We have recovered from the cache.
if (this.hasStateCache)
return;

this.logger.info('Initializing database state from server.');

Expand Down Expand Up @@ -420,7 +452,7 @@ class WalletDB extends EventEmitter {
this.state = state;
this.height = state.height;

return undefined;
return;
}

/**
Expand Down Expand Up @@ -2185,6 +2217,7 @@ class WalletDB extends EventEmitter {
await iter.each(async (key, value) => {
const [height] = layout.b.decode(key);
const block = MapRecord.decode(value);
this.logger.info('Reverting block: %d', height);

for (const wid of block.wids) {
const wallet = await this.get(wid);
Expand Down Expand Up @@ -2494,6 +2527,7 @@ class WalletOptions {
this.spv = false;
this.wipeNoReally = false;
this.walletMigrate = -1;
this.migrateNoRescan = false;
this.icannlockup = false;

if (options)
Expand Down Expand Up @@ -2582,6 +2616,11 @@ class WalletOptions {
this.icannlockup = options.icannlockup;
}

if (options.migrateNoRescan != null) {
assert(typeof options.migrateNoRescan === 'boolean');
this.migrateNoRescan = options.migrateNoRescan;
}

return this;
}

Expand Down
6 changes: 6 additions & 0 deletions test/mempool-reorg-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const plugin = require('../lib/wallet/plugin');
const Coin = require('../lib/primitives/coin');
const Address = require('../lib/primitives/address');
const MTX = require('../lib/primitives/mtx');
const {forEvent} = require('./util/common');

const network = Network.get('regtest');
const {
Expand All @@ -25,8 +26,13 @@ describe('Mempool Covenant Reorg', function () {
let wallet, name;

before(async () => {
const wdb = node.require('walletdb').wdb;
const syncDone = forEvent(wdb, 'sync done');
await node.open();

wallet = node.get('walletdb').wdb.primary;

await syncDone;
});

after(async () => {
Expand Down
2 changes: 2 additions & 0 deletions test/wallet-auction-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe('Wallet Auction', function() {
await chain.open();
await miner.open();
await wdb.open();
await wdb.connect();

// Set up wallet
winner = await wdb.create();
Expand All @@ -81,6 +82,7 @@ describe('Wallet Auction', function() {
});

after(async () => {
await wdb.disconnect();
await wdb.close();
await miner.close();
await chain.close();
Expand Down
Loading