chaindb: refactor.

This commit is contained in:
Christopher Jeffrey 2017-12-06 10:25:23 -08:00
parent cb978df380
commit bad028ab67
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 53 additions and 82 deletions

View File

@ -31,19 +31,6 @@ const thresholdStates = common.thresholdStates;
* @property {ChainEntry?} tip * @property {ChainEntry?} tip
* @property {Number} height * @property {Number} height
* @property {DeploymentState} state * @property {DeploymentState} state
* @emits Chain#open
* @emits Chain#error
* @emits Chain#block
* @emits Chain#competitor
* @emits Chain#resolved
* @emits Chain#checkpoint
* @emits Chain#fork
* @emits Chain#reorganize
* @emits Chain#invalid
* @emits Chain#exists
* @emits Chain#connect
* @emits Chain#reconnect
* @emits Chain#disconnect
*/ */
class Chain extends AsyncEmitter { class Chain extends AsyncEmitter {
@ -945,7 +932,7 @@ class Chain extends AsyncEmitter {
'Chain replay from height %d necessary.', 'Chain replay from height %d necessary.',
fork.height); fork.height);
await this.emitAsync('reorganize', tip, competitor); return this.emitAsync('reorganize', tip, competitor);
} }
/** /**
@ -973,7 +960,7 @@ class Chain extends AsyncEmitter {
this.emit('tip', prev); this.emit('tip', prev);
await this.emitAsync('disconnect', entry, block, view); return this.emitAsync('disconnect', entry, block, view);
} }
/** /**
@ -1023,7 +1010,7 @@ class Chain extends AsyncEmitter {
this.emit('tip', entry); this.emit('tip', entry);
this.emit('reconnect', entry, block); this.emit('reconnect', entry, block);
await this.emitAsync('connect', entry, block, view); return this.emitAsync('connect', entry, block, view);
} }
/** /**
@ -1047,10 +1034,8 @@ class Chain extends AsyncEmitter {
// In spv-mode, we reset the // In spv-mode, we reset the
// chain and redownload the blocks. // chain and redownload the blocks.
if (this.options.spv) { if (this.options.spv)
await this.reorganizeSPV(entry); return this.reorganizeSPV(entry);
return;
}
await this.reorganize(entry); await this.reorganize(entry);
} }
@ -1091,7 +1076,7 @@ class Chain extends AsyncEmitter {
this.emit('tip', entry); this.emit('tip', entry);
this.emit('block', block, entry); this.emit('block', block, entry);
await this.emitAsync('connect', entry, block, view); return this.emitAsync('connect', entry, block, view);
} }
/** /**

View File

@ -514,7 +514,7 @@ class ChainDB {
this.logger.info('Writing genesis block to ChainDB.'); this.logger.info('Writing genesis block to ChainDB.');
await this.save(entry, block, new CoinView()); return this.save(entry, block, new CoinView());
} }
/** /**
@ -635,9 +635,9 @@ class ChainDB {
*/ */
saveDeployments() { saveDeployments() {
const batch = this.db.batch(); const b = this.db.batch();
this.writeDeployments(batch); this.writeDeployments(b);
return batch.write(); return b.write();
} }
/** /**
@ -645,7 +645,7 @@ class ChainDB {
* @returns {Promise} * @returns {Promise}
*/ */
writeDeployments(batch) { writeDeployments(b) {
const bw = bio.write(1 + 17 * this.network.deploys.length); const bw = bio.write(1 + 17 * this.network.deploys.length);
bw.writeU8(this.network.deploys.length); bw.writeU8(this.network.deploys.length);
@ -658,7 +658,7 @@ class ChainDB {
bw.writeI32(deployment.window); bw.writeI32(deployment.window);
} }
batch.put(layout.D.build(), bw.render()); b.put(layout.D.build(), bw.render());
} }
/** /**
@ -719,17 +719,17 @@ class ChainDB {
if (invalid.length === 0) if (invalid.length === 0)
return true; return true;
const batch = this.db.batch(); const b = this.db.batch();
for (const bit of invalid) { for (const bit of invalid) {
this.logger.warning('Versionbit deployment params modified.'); this.logger.warning('Versionbit deployment params modified.');
this.logger.warning('Invalidating cache for bit %d.', bit); this.logger.warning('Invalidating cache for bit %d.', bit);
await this.invalidateCache(bit, batch); await this.invalidateCache(bit, b);
} }
this.writeDeployments(batch); this.writeDeployments(b);
await batch.write(); await b.write();
return false; return false;
} }
@ -740,14 +740,14 @@ class ChainDB {
* @returns {Promise} * @returns {Promise}
*/ */
async invalidateCache(bit, batch) { async invalidateCache(bit, b) {
const keys = await this.db.keys({ const keys = await this.db.keys({
gte: layout.v.min(bit), gte: layout.v.min(bit),
lte: layout.v.max(bit) lte: layout.v.max(bit)
}); });
for (const key of keys) for (const key of keys)
batch.del(key); b.del(key);
} }
/** /**
@ -772,7 +772,7 @@ class ChainDB {
const start = pruneAfter + 1; const start = pruneAfter + 1;
const end = height - keepBlocks; const end = height - keepBlocks;
const batch = this.db.batch(); const b = this.db.batch();
for (let i = start; i <= end; i++) { for (let i = start; i <= end; i++) {
const hash = await this.getHash(i); const hash = await this.getHash(i);
@ -780,8 +780,8 @@ class ChainDB {
if (!hash) if (!hash)
throw new Error(`Cannot find hash for ${i}.`); throw new Error(`Cannot find hash for ${i}.`);
batch.del(layout.b.build(hash)); b.del(layout.b.build(hash));
batch.del(layout.u.build(hash)); b.del(layout.u.build(hash));
} }
try { try {
@ -790,9 +790,9 @@ class ChainDB {
const flags = ChainFlags.fromOptions(options); const flags = ChainFlags.fromOptions(options);
assert(flags.prune); assert(flags.prune);
batch.put(layout.O.build(), flags.toRaw()); b.put(layout.O.build(), flags.toRaw());
await batch.write(); await b.write();
} catch (e) { } catch (e) {
options.prune = false; options.prune = false;
throw e; throw e;
@ -1309,6 +1309,7 @@ class ChainDB {
for (let i = 0; i < block.txs.length; i++) { for (let i = 0; i < block.txs.length; i++) {
const tx = block.txs[i]; const tx = block.txs[i];
let found = false; let found = false;
for (let j = 0; j < tx.outputs.length; j++) { for (let j = 0; j < tx.outputs.length; j++) {
@ -1372,7 +1373,7 @@ class ChainDB {
} }
/** /**
* Save an entry without a batch. * Save an entry.
* @private * @private
* @param {ChainEntry} entry * @param {ChainEntry} entry
* @param {Block} block * @param {Block} block
@ -1438,7 +1439,7 @@ class ChainDB {
} }
/** /**
* Reconnect block without a batch. * Reconnect block.
* @private * @private
* @param {ChainEntry} entry * @param {ChainEntry} entry
* @param {Block} block * @param {Block} block
@ -1495,7 +1496,7 @@ class ChainDB {
} }
/** /**
* Disconnect block without a batch. * Disconnect block.
* @private * @private
* @param {ChainEntry} entry * @param {ChainEntry} entry
* @param {Block} block * @param {Block} block
@ -1756,7 +1757,7 @@ class ChainDB {
async connectBlock(entry, block, view) { async connectBlock(entry, block, view) {
if (this.options.spv) if (this.options.spv)
return; return undefined;
const hash = block.hash(); const hash = block.hash();
@ -1764,7 +1765,7 @@ class ChainDB {
// Genesis block's coinbase is unspendable. // Genesis block's coinbase is unspendable.
if (entry.isGenesis()) if (entry.isGenesis())
return; return undefined;
// Update chain state value. // Update chain state value.
for (let i = 0; i < block.txs.length; i++) { for (let i = 0; i < block.txs.length; i++) {
@ -1794,7 +1795,7 @@ class ChainDB {
this.put(layout.u.build(hash), view.undo.commit()); this.put(layout.u.build(hash), view.undo.commit());
// Prune height-288 if pruning is enabled. // Prune height-288 if pruning is enabled.
await this.pruneBlock(entry); return this.pruneBlock(entry);
} }
/** /**
@ -1891,9 +1892,9 @@ class ChainDB {
saveFlags() { saveFlags() {
const flags = ChainFlags.fromOptions(this.options); const flags = ChainFlags.fromOptions(this.options);
const batch = this.db.batch(); const b = this.db.batch();
batch.put(layout.O.build(), flags.toRaw()); b.put(layout.O.build(), flags.toRaw());
return batch.write(); return b.write();
} }
/** /**
@ -1914,8 +1915,7 @@ class ChainDB {
this.put(layout.t.build(hash), meta.toRaw()); this.put(layout.t.build(hash), meta.toRaw());
if (this.options.indexAddress) { if (this.options.indexAddress) {
const hashes = tx.getHashes(view); for (const addr of tx.getHashes(view))
for (const addr of hashes)
this.put(layout.T.build(addr, hash), null); this.put(layout.T.build(addr, hash), null);
} }
} }
@ -1925,12 +1925,16 @@ class ChainDB {
if (!tx.isCoinbase()) { if (!tx.isCoinbase()) {
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
const addr = view.getOutput(prevout).getHash(); const {hash, index} = prevout;
const coin = view.getOutput(prevout);
assert(coin);
const addr = coin.getHash();
if (!addr) if (!addr)
continue; continue;
this.del(layout.C.build(addr, prevout.hash, prevout.index)); this.del(layout.C.build(addr, hash, index));
} }
} }
@ -1958,8 +1962,7 @@ class ChainDB {
if (this.options.indexTX) { if (this.options.indexTX) {
this.del(layout.t.build(hash)); this.del(layout.t.build(hash));
if (this.options.indexAddress) { if (this.options.indexAddress) {
const hashes = tx.getHashes(view); for (const addr of tx.getHashes(view))
for (const addr of hashes)
this.del(layout.T.build(addr, hash)); this.del(layout.T.build(addr, hash));
} }
} }
@ -1969,12 +1972,16 @@ class ChainDB {
if (!tx.isCoinbase()) { if (!tx.isCoinbase()) {
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
const addr = view.getOutput(prevout).getHash(); const {hash, index} = prevout;
const coin = view.getOutput(prevout);
assert(coin);
const addr = coin.getHash();
if (!addr) if (!addr)
continue; continue;
this.put(layout.C.build(addr, prevout.hash, prevout.index), null); this.put(layout.C.build(addr, hash, index), null);
} }
} }
@ -1990,13 +1997,6 @@ class ChainDB {
} }
} }
/**
* Database layout.
* @type {Object}
*/
ChainDB.layout = layout;
/** /**
* ChainFlags * ChainFlags
*/ */

View File

@ -2048,13 +2048,6 @@ class TXDB {
} }
} }
/**
* Database layout.
* @type {Object}
*/
TXDB.layout = layout;
/** /**
* Balance * Balance
* @alias module:wallet.Balance * @alias module:wallet.Balance

View File

@ -219,9 +219,8 @@ class WalletDB extends EventEmitter {
} }
const magic = raw.readUInt32LE(0, true); const magic = raw.readUInt32LE(0, true);
const network = Network.fromMagic(magic);
if (network !== this.network) if (magic !== this.network.magic)
throw new Error('Network mismatch for WalletDB.'); throw new Error('Network mismatch for WalletDB.');
return undefined; return undefined;
@ -585,7 +584,7 @@ class WalletDB extends EventEmitter {
this.logger.warning('Wiped %d txdb records.', total); this.logger.warning('Wiped %d txdb records.', total);
await b.write(); return b.write();
} }
/** /**
@ -2113,17 +2112,10 @@ class WalletDB extends EventEmitter {
if (entry.height > this.state.height) if (entry.height > this.state.height)
throw new Error('WDB: Bad reset height.'); throw new Error('WDB: Bad reset height.');
await this.rollback(entry.height); return this.rollback(entry.height);
} }
} }
/**
* Database layout.
* @type {Object}
*/
WalletDB.layout = layout;
/** /**
* Wallet Options * Wallet Options
* @alias module:wallet.WalletOptions * @alias module:wallet.WalletOptions

View File

@ -3,7 +3,6 @@
const assert = require('assert'); const assert = require('assert');
const bdb = require('bdb'); const bdb = require('bdb');
const layout = require('../lib/blockchain/layout'); const layout = require('../lib/blockchain/layout');
const DUMMY = Buffer.alloc(1, 0x00);
// changes: // changes:
// db version record // db version record
@ -59,7 +58,7 @@ async function migrateKeys(id, from, to) {
let items = 0; let items = 0;
await iter.each(async (key) => { await iter.each(async (key) => {
batch.put(to.build(...from(key)), DUMMY); batch.put(to.build(...from(key)), null);
batch.del(key); batch.del(key);
total += (key.length + 80) * 2; total += (key.length + 80) * 2;

View File

@ -235,6 +235,8 @@ async function updateLookahead() {
await db.close(); await db.close();
} }
updateLookahead;
async function unstate() { async function unstate() {
await db.open(); await db.open();
batch = db.batch(); batch = db.batch();