Skip to content

Commit

Permalink
Merge PR #782 from 'nodech/txdb-updates'
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Oct 20, 2023
2 parents 4a70d70 + 2d5c25a commit fc23f41
Show file tree
Hide file tree
Showing 9 changed files with 3,373 additions and 266 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

## Unreleased

### Wallet API:
**When upgrading to this version of hsd, you must pass `--wallet-migrate=3` when
you run it for the first time.**

### Wallet Changes:

- Add migration that recalculates txdb balances to fix any inconsistencies.
- HTTP Changes:
- All transaction creating endpoints now accept `hardFee` for specifying the
exact fee.
Expand Down
156 changes: 109 additions & 47 deletions lib/wallet/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,97 +10,159 @@ const bdb = require('bdb');

/*
* Wallet Database Layout:
* WDB State
* ---------
* V -> db version
* O -> flags
* R -> chain sync state
* D -> wallet id depth
* p[addr-hash] -> wallet ids
* P[wid][addr-hash] -> path data
* r[wid][index][hash] -> path account index
* M -> migration state
*
* Chain Sync
* ----------
* R -> chain sync state
* h[height] -> block hash
*
* WID mappings
* --------
* b[height] -> block->wid map
* T[tx-hash] -> tx->wid map
* o[tx-hash][index] -> outpoint->wid map
* p[addr-hash] -> address->wid map
* N[name-hash] -> name->wid map
*
* Wallet
* ------
* l[id] -> wid
* w[wid] -> wallet
* W[wid] -> wallet id
* l[id] -> wid
*
* Wallet Account
* --------------
* a[wid][index] -> account
* i[wid][name] -> account index
* n[wid][index] -> account name
* h[height] -> recent block hash
* b[height] -> block->wid map
* o[hash][index] -> outpoint->wid map
* T[hash] -> tx->wid map
*
* Wallet Path
* -----------
* P[wid][addr-hash] -> path data
* r[wid][index][addr-hash] -> dummy (addr by account)
*
* TXDB
* ----
* t[wid]* -> txdb
* N[hash256] -> name map
* M -> migration state
*/

exports.wdb = {
// WDB State
V: bdb.key('V'),
O: bdb.key('O'),
R: bdb.key('R'),
D: bdb.key('D'),
M: bdb.key('M'),

// Chain Sync
R: bdb.key('R'),
h: bdb.key('h', ['uint32']),

// WID Mappings
b: bdb.key('b', ['uint32']),
T: bdb.key('T', ['hash256']),
p: bdb.key('p', ['hash']),
P: bdb.key('P', ['uint32', 'hash']),
r: bdb.key('r', ['uint32', 'uint32', 'hash']),
o: bdb.key('o', ['hash256', 'uint32']),
N: bdb.key('N', ['hash256']),

// Wallet
l: bdb.key('l', ['ascii']),
w: bdb.key('w', ['uint32']),
W: bdb.key('W', ['uint32']),
l: bdb.key('l', ['ascii']),

// Wallet Account
a: bdb.key('a', ['uint32', 'uint32']),
i: bdb.key('i', ['uint32', 'ascii']),
n: bdb.key('n', ['uint32', 'uint32']),
h: bdb.key('h', ['uint32']),
b: bdb.key('b', ['uint32']),
o: bdb.key('o', ['hash256', 'uint32']),
T: bdb.key('T', ['hash256']),
t: bdb.key('t', ['uint32']),
N: bdb.key('N', ['hash256']),
M: bdb.key('M')

// Wallet Path
P: bdb.key('P', ['uint32', 'hash']),
r: bdb.key('r', ['uint32', 'uint32', 'hash']),

// TXDB
t: bdb.key('t', ['uint32'])
};

/*
* TXDB Database Layout:
* Balance
* -------
* R -> wallet balance
* r[account] -> account balance
* t[hash] -> extended tx
* c[hash][index] -> coin
* d[hash][index] -> undo coin
* s[hash][index] -> spent by hash
* p[hash] -> dummy (pending flag)
* m[time][hash] -> dummy (tx by time)
* h[height][hash] -> dummy (tx by height)
* T[account][hash] -> dummy (tx by account)
* P[account][hash] -> dummy (pending tx by account)
* M[account][time][hash] -> dummy (tx by time + account)
* H[account][height][hash] -> dummy (tx by height + account)
* C[account][hash][index] -> dummy (coin by account)
*
* Coin
* ----
* c[tx-hash][index] -> coin
* C[account][tx-hash][index] -> dummy (coin by account)
* d[tx-hash][index] -> undo coin
* s[tx-hash][index] -> spent by hash
*
* Transaction
* -----------
* t[tx-hash] -> extended tx
* T[account][tx-hash] -> dummy (tx by account)
* m[time][tx-hash] -> dummy (tx by time)
* M[account][time][tx-hash] -> dummy (tx by time + account)
*
* Confirmed
* ---------
* b[height] -> block record
* h[height][tx-hash] -> dummy (tx by height)
* H[account][height][tx-hash] -> dummy (tx by height + account)
*
* Unconfirmed
* -----------
* p[hash] -> dummy (pending tx)
* P[account][tx-hash] -> dummy (pending tx by account)
*
* Names
* -----
* A[name-hash] -> name record (name record by name hash)
* U[tx-hash] -> name undo record (name undo record by tx hash)
* i[name-hash][tx-hash][index] -> bid (BlindBid by name + tx + index)
* B[name-hash][tx-hash][index] -> reveal (BidReveal by name + tx + index)
* v[blind-hash] -> blind (Blind Value by blind hash)
* o[name-hash] -> tx hash OPEN only (tx hash by name hash)
*/

exports.txdb = {
prefix: bdb.key('t', ['uint32']),

// Balance
R: bdb.key('R'),
r: bdb.key('r', ['uint32']),
t: bdb.key('t', ['hash256']),

// Coin
c: bdb.key('c', ['hash256', 'uint32']),
C: bdb.key('C', ['uint32', 'hash256', 'uint32']),
d: bdb.key('d', ['hash256', 'uint32']),
s: bdb.key('s', ['hash256', 'uint32']),
p: bdb.key('p', ['hash256']),
m: bdb.key('m', ['uint32', 'hash256']),
h: bdb.key('h', ['uint32', 'hash256']),

// Transaction
t: bdb.key('t', ['hash256']),
T: bdb.key('T', ['uint32', 'hash256']),
P: bdb.key('P', ['uint32', 'hash256']),
m: bdb.key('m', ['uint32', 'hash256']),
M: bdb.key('M', ['uint32', 'uint32', 'hash256']),
H: bdb.key('H', ['uint32', 'uint32', 'hash256']),
C: bdb.key('C', ['uint32', 'hash256', 'uint32']),

// Confirmed
b: bdb.key('b', ['uint32']),
// Name records
h: bdb.key('h', ['uint32', 'hash256']),
H: bdb.key('H', ['uint32', 'uint32', 'hash256']),

// Unconfirmed
p: bdb.key('p', ['hash256']),
P: bdb.key('P', ['uint32', 'hash256']),

// Names
A: bdb.key('A', ['hash256']),
// Name undo records
U: bdb.key('U', ['hash256']),
// Bids
i: bdb.key('i', ['hash256', 'hash256', 'uint32']),
// Reveals
B: bdb.key('B', ['hash256', 'hash256', 'uint32']),
// Blinds
v: bdb.key('v', ['hash256']),
// Opens
o: bdb.key('o', ['hash256'])
};
54 changes: 48 additions & 6 deletions lib/wallet/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ class MigrateChangeAddress extends AbstractMigration {
*/

async migrate(b, pending) {
const wids = await this.ldb.keys({
gte: layout.W.min(),
lte: layout.W.max(),
parse: key => layout.W.decode(key)[0]
});
const wids = await this.db.getWallets();

let total = 0;
for (const wid of wids) {
Expand Down Expand Up @@ -249,6 +245,50 @@ class MigrateAccountLookahead extends AbstractMigration {
}
}

class MigrateTXDBBalances extends AbstractMigration {
/**
* Create TXDB Balance migration object.
* @param {WalletMigratorOptions} options
* @constructor
*/

constructor(options) {
super(options);

this.options = options;
this.logger = options.logger.context('txdb-balance-migration');
this.db = options.db;
this.ldb = options.ldb;
}

/**
* We always migrate.
* @returns {Promise}
*/

async check() {
return types.MIGRATE;
}

/**
* Actual migration
* @param {Batch} b
* @param {WalletMigrationResult} pending
* @returns {Promise}
*/

async migrate(b, pending) {
await this.db.recalculateBalances();
}

static info() {
return {
name: 'TXDB balance refresh',
description: 'Refresh balances for TXDB after txdb updates'
};
}
}

/**
* Wallet migration results.
* @alias module:blockchain.WalletMigrationResult
Expand Down Expand Up @@ -382,12 +422,14 @@ exports.WalletMigrationResult = WalletMigrationResult;
exports.migrations = {
0: MigrateMigrations,
1: MigrateChangeAddress,
2: MigrateAccountLookahead
2: MigrateAccountLookahead,
3: MigrateTXDBBalances
};

// Expose migrations
exports.MigrateChangeAddress = MigrateChangeAddress;
exports.MigrateMigrations = MigrateMigrations;
exports.MigrateAccountLookahead = MigrateAccountLookahead;
exports.MigrateTXDBBalances = MigrateTXDBBalances;

module.exports = exports;
Loading

0 comments on commit fc23f41

Please sign in to comment.