Skip to content

Commit

Permalink
Merge PR #870 from 'nodech/wallet-test-chainstate'
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Dec 4, 2023
2 parents 7999477 + 2601f3c commit 5955e91
Show file tree
Hide file tree
Showing 4 changed files with 656 additions and 84 deletions.
50 changes: 20 additions & 30 deletions lib/wallet/walletdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1857,13 +1857,24 @@ class WalletDB extends EventEmitter {
/**
* Sync the current chain state to tip.
* @param {BlockMeta} tip
* @param {Boolean} checkMark - should we check startHeight/mark. This should
* only happen if we are progressing forward in history and have txs.
* @returns {Promise}
*/

async setTip(tip) {
async setTip(tip, checkMark = false) {
const b = this.db.batch();
const state = this.state.clone();

// mark state if state has not been marked, we are moving forward
// and we have txs. If state is marked, it means we already found
// first tx for the whole wdb, so no longer move it forward.
if (checkMark && !state.marked) {
state.startHeight = tip.height;
state.startHash = tip.hash;
state.marked = true;
}

if (tip.height < state.height) {
// Hashes ahead of our new tip
// that we need to delete.
Expand Down Expand Up @@ -1908,26 +1919,6 @@ class WalletDB extends EventEmitter {
return height;
}

/**
* Mark current state.
* @param {BlockMeta} block
* @returns {Promise}
*/

async markState(block) {
const state = this.state.clone();
state.startHeight = block.height;
state.startHash = block.hash;
state.marked = true;

const b = this.db.batch();
b.put(layout.R.encode(), state.encode());
await b.write();

this.state = state;
this.height = state.height;
}

/**
* Get a wallet map.
* @param {Buffer} key
Expand Down Expand Up @@ -2160,7 +2151,7 @@ class WalletDB extends EventEmitter {
/**
* Get a wallet block meta.
* @param {Hash} hash
* @returns {Promise}
* @returns {Promise<BlockMeta?>}
*/

async getBlock(height) {
Expand All @@ -2175,7 +2166,7 @@ class WalletDB extends EventEmitter {
/**
* Get wallet tip.
* @param {Hash} hash
* @returns {Promise}
* @returns {Promise<BlockMeta>}
*/

async getTip() {
Expand Down Expand Up @@ -2227,7 +2218,7 @@ class WalletDB extends EventEmitter {
assert(tip);

await this.revert(tip.height);
await this.setTip(tip);
await this.setTip(tip, false);
}

/**
Expand Down Expand Up @@ -2319,14 +2310,16 @@ class WalletDB extends EventEmitter {
// increment by one until the block is fully
// added and the height is updated.
this.confirming = true;

for (const tx of txs) {
if (await this._addTX(tx, tip)) {
walletTxs.push(tx);
}
}

// Sync the state to the new tip.
await this.setTip(tip);
// If we encountered wallet txs, we also trigger mark check.
await this.setTip(tip, walletTxs.length > 0);
} finally {
this.confirming = false;
}
Expand Down Expand Up @@ -2387,7 +2380,7 @@ class WalletDB extends EventEmitter {
const map = await this.getBlockMap(tip.height);

if (!map) {
await this.setTip(prev);
await this.setTip(prev, false);
this.emit('block disconnect', entry);
return 0;
}
Expand All @@ -2401,7 +2394,7 @@ class WalletDB extends EventEmitter {
}

// Sync the state to the previous tip.
await this.setTip(prev);
await this.setTip(prev, false);

this.logger.warning('Disconnected wallet block %x (tx=%d).',
tip.hash, total);
Expand Down Expand Up @@ -2471,9 +2464,6 @@ class WalletDB extends EventEmitter {
if (!wids)
return null;

if (block && !this.state.marked)
await this.markState(block);

this.logger.info(
'Incoming transaction for %d wallets in WalletDB (%s).',
wids.size, tx.txid());
Expand Down
61 changes: 61 additions & 0 deletions test/util/wallet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

const blake2b = require('bcrypto/lib/blake2b');
const random = require('bcrypto/lib/random');
const Block = require('../../lib/primitives/block');
const ChainEntry = require('../../lib/blockchain/chainentry');
const Input = require('../../lib/primitives/input');
const Outpoint = require('../../lib/primitives/outpoint');

const walletUtils = exports;

walletUtils.fakeBlock = (height) => {
const prev = blake2b.digest(fromU32((height - 1) >>> 0));
const hash = blake2b.digest(fromU32(height >>> 0));
const root = blake2b.digest(fromU32((height | 0x80000000) >>> 0));

return {
hash: hash,
prevBlock: prev,
merkleRoot: root,
time: 500000000 + (height * (10 * 60)),
bits: 0,
nonce: 0,
height: height,
version: 0,
witnessRoot: Buffer.alloc(32),
treeRoot: Buffer.alloc(32),
reservedRoot: Buffer.alloc(32),
extraNonce: Buffer.alloc(24),
mask: Buffer.alloc(32)
};
};

walletUtils.dummyInput = () => {
const hash = random.randomBytes(32);
return Input.fromOutpoint(new Outpoint(hash, 0));
};

walletUtils.nextBlock = (wdb) => {
return walletUtils.fakeBlock(wdb.state.height + 1);
};

walletUtils.curBlock = (wdb) => {
return walletUtils.fakeBlock(wdb.state.height);
};

walletUtils.nextEntry = (wdb) => {
const cur = walletUtils.curEntry(wdb);
const next = new Block(walletUtils.nextBlock(wdb));
return ChainEntry.fromBlock(next, cur);
};

walletUtils.curEntry = (wdb) => {
return new ChainEntry(walletUtils.curBlock(wdb));
};

function fromU32(num) {
const data = Buffer.allocUnsafe(4);
data.writeUInt32LE(num, 0, true);
return data;
}
Loading

0 comments on commit 5955e91

Please sign in to comment.