Skip to content

Commit

Permalink
walletdb: Add guard for the rescan in the add block.
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Oct 24, 2023
1 parent 3679cd4 commit 29625eb
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 141 deletions.
31 changes: 23 additions & 8 deletions lib/wallet/walletdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ class WalletDB extends EventEmitter {
});

this.client.bind('block connect', async (entry, txs) => {
// If we are rescanning or doing initial sync we ignore
// block connect events. This avoids deadlocks when using
// nodeclient, but also skips unnecessary addBlock calls
// that would just repeat after the txLock is unlocked.
if (this.rescanning)
return;

try {
await this.addBlock(entry, txs);
} catch (e) {
Expand Down Expand Up @@ -385,13 +392,15 @@ class WalletDB extends EventEmitter {

async syncNode() {
const unlock = await this.txLock.lock();
this.rescanning = true;
try {
this.logger.info('Resyncing from server...');
await this.syncInitState();
await this.syncFilter();
await this.syncChain();
await this.resend();
} finally {
this.rescanning = false;
unlock();
}
}
Expand Down Expand Up @@ -457,6 +466,7 @@ class WalletDB extends EventEmitter {

/**
* Connect and sync with the chain server.
* Part of syncNode.
* @private
* @returns {Promise}
*/
Expand All @@ -477,11 +487,13 @@ class WalletDB extends EventEmitter {
height -= 1;
}

// syncNode sets the rescanning to true.
return this.scan(height);
}

/**
* Rescan blockchain from a given height.
* Needs this.rescanning = true to be set from the caller.
* @private
* @param {Number?} height
* @returns {Promise}
Expand All @@ -501,12 +513,7 @@ class WalletDB extends EventEmitter {

const tip = await this.getTip();

try {
this.rescanning = true;
await this.client.rescan(tip.hash);
} finally {
this.rescanning = false;
}
return this.client.rescan(tip.hash);
}

/**
Expand Down Expand Up @@ -600,6 +607,7 @@ class WalletDB extends EventEmitter {

async rescan(height) {
const unlock = await this.txLock.lock();

try {
return await this._rescan(height);
} finally {
Expand All @@ -615,7 +623,13 @@ class WalletDB extends EventEmitter {
*/

async _rescan(height) {
return this.scan(height);
this.rescanning = true;

try {
return await this.scan(height);
} finally {
this.rescanning = false;
}
}

/**
Expand Down Expand Up @@ -2237,6 +2251,7 @@ class WalletDB extends EventEmitter {

async addBlock(entry, txs) {
const unlock = await this.txLock.lock();

try {
return await this._addBlock(entry, txs);
} finally {
Expand Down Expand Up @@ -2274,7 +2289,7 @@ class WalletDB extends EventEmitter {
// processed (in the case of a crash).
this.logger.warning('Already saw WalletDB block (%d).', tip.height);
} else if (tip.height !== this.state.height + 1) {
await this.scan(this.state.height);
await this._rescan(this.state.height);
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions test/wallet-balance-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ describe('Wallet Balance', function() {
await discoverFn(wallet, ahead, opts);

// Final look at full picture.
await wdb.scan(chain.tip.height - 1);
await wdb.rescan(chain.tip.height - 1);
await checks.blockConfirmCheck(wallet, ahead, opts);

if (discoverAt === BEFORE_BLOCK_UNCONFIRM)
Expand All @@ -449,7 +449,7 @@ describe('Wallet Balance', function() {
await checks.blockUnconfirmCheck(wallet, ahead, opts);

// Clean up wallet.
await wdb.scan(chain.tip.height - 1);
await wdb.rescan(chain.tip.height - 1);
await checks.blockFinalConfirmCheck(wallet, ahead, opts);
};
};
Expand Down
188 changes: 57 additions & 131 deletions test/wallet-namestate-rescan-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,77 +21,81 @@ const {
const GNAME_SIZE = 10;

describe('Wallet rescan with namestate transitions', function() {
describe('Only sends OPEN', function() {
// Bob runs a full node with wallet plugin
const node = new FullNode({
let node, wdb;
let alice, aliceAddr;
let bob, bobAddr;

async function mineBlocks(n, addr) {
addr = addr ? addr : new Address().toString('regtest');
const blocks = [];
for (let i = 0; i < n; i++) {
const block = await node.miner.mineBlock(null, addr);
await node.chain.add(block);
blocks.push(block);
}

return blocks;
}

async function sendTXs() {
const aliceTX = await alice.send({
outputs: [{
address: aliceAddr,
value: 20000
}]
});
alice.addTX(aliceTX.toTX());
await node.mempool.addTX(aliceTX.toTX());
await bob.send({
outputs: [{
address: bobAddr,
value: 20000
}]
});
}

const beforeAll = async () => {
node = new FullNode({
network: network.type,
memory: true,
plugins: [require('../lib/wallet/plugin')]
});

node.on('error', (err) => {
assert(false, err);
});

const {wdb} = node.require('walletdb');
let bob, bobAddr;
wdb = node.require('walletdb').wdb;

// Alice is some other wallet on the network
const alice = new MemWallet({ network });
const aliceAddr = alice.getAddress();
alice = new MemWallet({ network });
aliceAddr = alice.getAddress();

// Connect MemWallet to chain as minimally as possible
node.chain.on('connect', (entry, block) => {
alice.addBlock(entry, block.txs);
});

alice.getNameStatus = async (nameHash) => {
assert(Buffer.isBuffer(nameHash));
const height = node.chain.height + 1;
return node.chain.db.getNameStatus(nameHash, height);
};

const NAME = rules.grindName(GNAME_SIZE, 4, network);

// Hash of the FINALIZE transaction
let aliceFinalizeHash;

async function mineBlocks(n, addr) {
addr = addr ? addr : new Address().toString('regtest');
const blocks = [];
for (let i = 0; i < n; i++) {
const block = await node.miner.mineBlock(null, addr);
await node.chain.add(block);
blocks.push(block);
}
await node.open();
bob = await wdb.create();
bobAddr = await bob.receiveAddress();
};

return blocks;
}
const afterAll = async () => {
await node.close();
};

async function sendTXs() {
const aliceTX = await alice.send({
outputs: [{
address: aliceAddr,
value: 20000
}]
});
alice.addTX(aliceTX.toTX());
await node.mempool.addTX(aliceTX.toTX());
await bob.send({
outputs: [{
address: bobAddr,
value: 20000
}]
});
}

before(async () => {
await node.open();
bob = await wdb.create();
bobAddr = await bob.receiveAddress();
});
describe('Only sends OPEN', function() {
const NAME = rules.grindName(GNAME_SIZE, 4, network);
let aliceFinalizeHash;

after(async () => {
await node.close();
});
before(beforeAll);
after(afterAll);

it('should fund wallets', async () => {
const blocks = 10;
Expand Down Expand Up @@ -274,78 +278,12 @@ describe('Wallet rescan with namestate transitions', function() {
});

describe('Bids, loses, shallow rescan', function() {
// Bob runs a full node with wallet plugin
const node = new FullNode({
network: network.type,
memory: true,
plugins: [require('../lib/wallet/plugin')]
});
node.on('error', (err) => {
assert(false, err);
});

const {wdb} = node.require('walletdb');
let bob, bobAddr;

// Alice is some other wallet on the network
const alice = new MemWallet({ network });
const aliceAddr = alice.getAddress();

// Connect MemWallet to chain as minimally as possible
node.chain.on('connect', (entry, block) => {
alice.addBlock(entry, block.txs);
});
alice.getNameStatus = async (nameHash) => {
assert(Buffer.isBuffer(nameHash));
const height = node.chain.height + 1;
return node.chain.db.getNameStatus(nameHash, height);
};

const NAME = rules.grindName(GNAME_SIZE, 4, network);

// Block that confirmed the bids
let bidBlockHash;
// Hash of the FINALIZE transaction
let aliceFinalizeHash;
let bidBlockHash;

async function mineBlocks(n, addr) {
addr = addr ? addr : new Address().toString('regtest');
const blocks = [];
for (let i = 0; i < n; i++) {
const block = await node.miner.mineBlock(null, addr);
await node.chain.add(block);
blocks.push(block);
}

return blocks;
}

async function sendTXs() {
const aliceTX = await alice.send({
outputs: [{
address: aliceAddr,
value: 20000
}]
});
alice.addTX(aliceTX.toTX());
await node.mempool.addTX(aliceTX.toTX());
await bob.send({
outputs: [{
address: bobAddr,
value: 20000
}]
});
}

before(async () => {
await node.open();
bob = await wdb.create();
bobAddr = await bob.receiveAddress();
});

after(async () => {
await node.close();
});
before(beforeAll);
after(afterAll);

it('should fund wallets', async () => {
const blocks = 10;
Expand Down Expand Up @@ -562,26 +500,14 @@ describe('Wallet rescan with namestate transitions', function() {
});

describe('Restore from seed', function() {
const node = new FullNode({
network: network.type,
memory: true,
plugins: [require('../lib/wallet/plugin')]
});

const {wdb} = node.require('walletdb');
let wallet1, wallet2, wallet3;
let addr1;
let heightBeforeReveal;

const name = rules.grindName(4, 4, network);

before(async () => {
await node.open();
});

after(async () => {
await node.close();
});
before(beforeAll);
after(afterAll);

it('should create and fund wallet 1', async () => {
wallet1 = await wdb.create();
Expand Down
Loading

0 comments on commit 29625eb

Please sign in to comment.