Skip to content

Commit

Permalink
Merge PR #859 from 'nodech/wallet-lifecycles'
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Oct 20, 2023
2 parents 7bd2078 + 1f2251e commit bb7da60
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 96 deletions.
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

0 comments on commit bb7da60

Please sign in to comment.