db refactoring.
This commit is contained in:
parent
849f1d842e
commit
4b20a87b4f
@ -18,9 +18,9 @@ var VerifyError = utils.VerifyError;
|
||||
* Chain
|
||||
*/
|
||||
|
||||
function Chain(node, options) {
|
||||
function Chain(options) {
|
||||
if (!(this instanceof Chain))
|
||||
return new Chain(node, options);
|
||||
return new Chain(options);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
@ -29,9 +29,7 @@ function Chain(node, options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.node = node;
|
||||
this.loaded = false;
|
||||
this.mempool = node.mempool;
|
||||
this.db = new bcoin.chaindb(this, options);
|
||||
this.total = 0;
|
||||
this.orphanLimit = options.orphanLimit || (20 << 20);
|
||||
@ -43,7 +41,6 @@ function Chain(node, options) {
|
||||
this.tip = null;
|
||||
this.height = -1;
|
||||
this.segwitActive = null;
|
||||
this.spv = !!options.spv;
|
||||
|
||||
this.orphan = {
|
||||
map: {},
|
||||
@ -52,8 +49,6 @@ function Chain(node, options) {
|
||||
size: 0
|
||||
};
|
||||
|
||||
Chain.global = this;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
@ -63,17 +58,7 @@ Chain.prototype._init = function _init() {
|
||||
var self = this;
|
||||
|
||||
function getHost() {
|
||||
var peer;
|
||||
|
||||
if (!self.node || !self.node.pool)
|
||||
return;
|
||||
|
||||
peer = self.node.pool.peers.load;
|
||||
|
||||
if (!peer)
|
||||
return 'unknown';
|
||||
|
||||
return peer.host;
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
// Hook into events for debugging
|
||||
@ -242,7 +227,7 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
if (!this.options.preload)
|
||||
return callback();
|
||||
|
||||
if (!this.spv)
|
||||
if (!this.options.spv)
|
||||
return callback();
|
||||
|
||||
if (network.type !== 'main')
|
||||
@ -592,7 +577,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
||||
var self = this;
|
||||
var height = prev.height + 1;
|
||||
|
||||
if (this.spv || block.type !== 'block')
|
||||
if (this.options.spv || block.type !== 'block')
|
||||
return callback();
|
||||
|
||||
if (block.isGenesis())
|
||||
@ -629,7 +614,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
||||
var scriptCheck = true;
|
||||
var historical = false;
|
||||
|
||||
if (this.spv || block.type !== 'block')
|
||||
if (this.options.spv || block.type !== 'block')
|
||||
return callback();
|
||||
|
||||
if (block.isGenesis())
|
||||
|
||||
@ -27,19 +27,12 @@ function ChainDB(chain, options) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.options = options;
|
||||
this.node = chain.node;
|
||||
this.network = chain.node.network;
|
||||
this.chain = chain;
|
||||
|
||||
this.queue = {};
|
||||
this.queueSize = 0;
|
||||
this.size = 0;
|
||||
this.fd = null;
|
||||
this.loaded = false;
|
||||
|
||||
this.keepBlocks = options.keepBlocks || 288;
|
||||
this.prune = !!options.prune;
|
||||
this.spv = !!options.spv;
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
// Need to cache up to the retarget interval
|
||||
// if we're going to be checking the damn
|
||||
@ -66,7 +59,9 @@ ChainDB.prototype._init = function _init() {
|
||||
if (this.loaded)
|
||||
return;
|
||||
|
||||
this.db = bcoin.ldb(this.spv ? 'spvchain' : 'chain', {
|
||||
this.db = bcoin.ldb({
|
||||
name: this.options.name || (this.options.spv ? 'spvchain' : 'chain'),
|
||||
location: this.options.location,
|
||||
compression: true,
|
||||
cacheSize: 16 << 20,
|
||||
writeBufferSize: 8 << 20
|
||||
@ -82,10 +77,10 @@ ChainDB.prototype._init = function _init() {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
utils.debug('Chain successfully loaded.');
|
||||
|
||||
self.loaded = true;
|
||||
self.emit('open');
|
||||
|
||||
utils.debug('Chain successfully loaded.');
|
||||
}
|
||||
|
||||
self.db.get('c/b/' + network.genesis.hash, function(err, exists) {
|
||||
@ -578,7 +573,7 @@ ChainDB.prototype.has = function has(height, callback) {
|
||||
};
|
||||
|
||||
ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) {
|
||||
if (this.spv)
|
||||
if (this.options.spv)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
batch.put('b/b/' + block.hash('hex'), block.toCompact());
|
||||
@ -596,7 +591,7 @@ ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback
|
||||
ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.spv)
|
||||
if (this.options.spv)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this._ensureHistory(hash, function(err, block) {
|
||||
@ -619,7 +614,7 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
|
||||
ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.spv) {
|
||||
if (this.options.spv) {
|
||||
self.emit('add block', block);
|
||||
return utils.nextTick(callback);
|
||||
}
|
||||
@ -690,7 +685,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.spv)
|
||||
if (this.options.spv)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this._ensureHistory(hash, function(err, block) {
|
||||
@ -1258,7 +1253,7 @@ ChainDB.prototype._getTX = function _getTX(hash, callback) {
|
||||
ChainDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) {
|
||||
return callback(null, false);
|
||||
|
||||
if (this.spv)
|
||||
if (this.options.spv)
|
||||
return callback(null, false);
|
||||
|
||||
return this.isSpentTX(hash, function(err, spent) {
|
||||
@ -1300,7 +1295,7 @@ ChainDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
|
||||
ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
|
||||
var futureHeight;
|
||||
|
||||
if (this.spv)
|
||||
if (this.options.spv)
|
||||
return callback();
|
||||
|
||||
if (!this.prune)
|
||||
|
||||
@ -23,8 +23,6 @@ function Fullnode(options) {
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
Fullnode.global = this;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
@ -36,15 +34,16 @@ Fullnode.prototype._init = function _init() {
|
||||
|
||||
this.wallet = null;
|
||||
|
||||
this.chain = new bcoin.chain(this, {
|
||||
this.chain = new bcoin.chain({
|
||||
preload: false,
|
||||
spv: false,
|
||||
prune: this.options.prune,
|
||||
useCheckpoints: this.options.useCheckpoints
|
||||
});
|
||||
|
||||
// Mempool needs access to blockdb.
|
||||
this.mempool = new bcoin.mempool(this, {
|
||||
// Mempool needs access to the chain.
|
||||
this.mempool = new bcoin.mempool({
|
||||
chain: this.chain,
|
||||
limitFree: this.options.limitFree,
|
||||
limitFreeRelay: this.options.limitFreeRelay,
|
||||
requireStandard: this.options.requireStandard,
|
||||
@ -52,26 +51,31 @@ Fullnode.prototype._init = function _init() {
|
||||
replaceByFee: this.options.replaceByFee
|
||||
});
|
||||
|
||||
// Pool needs access to the chain.
|
||||
this.pool = new bcoin.pool(this, {
|
||||
// Pool needs access to the chain and mempool.
|
||||
this.pool = new bcoin.pool({
|
||||
chain: this.chain,
|
||||
mempool: this.mempool,
|
||||
witness: this.network.witness,
|
||||
listen: this.options.listen,
|
||||
selfish: this.options.selfish,
|
||||
spv: false
|
||||
});
|
||||
|
||||
// Miner needs access to the mempool.
|
||||
this.miner = new bcoin.miner(this, {
|
||||
// Miner needs access to the chain and mempool.
|
||||
this.miner = new bcoin.miner({
|
||||
chain: this.chain,
|
||||
mempool: this.mempool,
|
||||
address: this.options.payoutAddress,
|
||||
coinbaseFlags: this.options.coinbaseFlags
|
||||
});
|
||||
|
||||
// WalletDB needs access to the network type.
|
||||
this.walletdb = new bcoin.walletdb(this);
|
||||
this.walletdb = new bcoin.walletdb({
|
||||
verify: false
|
||||
});
|
||||
|
||||
// HTTP needs access to the mempool
|
||||
// and blockdb.
|
||||
this.http = new bcoin.http.server(this, {
|
||||
// HTTP needs access to the node.
|
||||
this.http = new bcoin.http.server({
|
||||
node: this,
|
||||
key: this.options.sslKey,
|
||||
cert: this.options.sslCert,
|
||||
port: this.options.httpPort || 8080,
|
||||
@ -141,6 +145,10 @@ Fullnode.prototype._init = function _init() {
|
||||
});
|
||||
});
|
||||
|
||||
this.miner.on('block', function(block) {
|
||||
self.pool.sendBlock(block);
|
||||
});
|
||||
|
||||
function load(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
@ -16,14 +16,17 @@ var assert = utils.assert;
|
||||
* NodeServer
|
||||
*/
|
||||
|
||||
function NodeServer(node, options) {
|
||||
function NodeServer(options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
this.options = options;
|
||||
this.node = node;
|
||||
this.walletdb = node.walletdb;
|
||||
this.pool = node.pool;
|
||||
this.node = options.node;
|
||||
|
||||
assert(this.node, 'HTTP requires a Node.');
|
||||
|
||||
this.walletdb = this.node.walletdb;
|
||||
this.pool = this.node.pool;
|
||||
this.loaded = false;
|
||||
|
||||
this.server = new HTTPServer(options);
|
||||
@ -145,7 +148,7 @@ NodeServer.prototype._init = function _init() {
|
||||
this.get('/', function(req, res, next, send) {
|
||||
send(200, {
|
||||
version: constants.userAgent,
|
||||
network: self.node.network.type
|
||||
network: network.type
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -14,8 +14,8 @@ var db = {};
|
||||
* LDB
|
||||
*/
|
||||
|
||||
function ldb(name, options) {
|
||||
var file = getLocation(name);
|
||||
function ldb(options) {
|
||||
var file = getLocation(options);
|
||||
|
||||
if (!db[file]) {
|
||||
if (!options)
|
||||
@ -49,8 +49,10 @@ function ldb(name, options) {
|
||||
return db[file];
|
||||
}
|
||||
|
||||
function getLocation(name) {
|
||||
return bcoin.prefix + '/' + name + '-' + network.type + '.db';
|
||||
function getLocation(options) {
|
||||
if (options.location)
|
||||
return options.location;
|
||||
return bcoin.prefix + '/' + options.name + '-' + network.type + '.db';
|
||||
}
|
||||
|
||||
function getBackend(backend) {
|
||||
@ -77,15 +79,9 @@ function getBackend(backend) {
|
||||
return require(backend);
|
||||
}
|
||||
|
||||
function destroy(name, backend, callback) {
|
||||
var file = getLocation(name);
|
||||
|
||||
if (!callback) {
|
||||
callback = backend;
|
||||
backend = null;
|
||||
}
|
||||
|
||||
backend = getBackend(backend);
|
||||
function destroy(options, callback) {
|
||||
var file = getLocation(options);
|
||||
var backend = getBackend(options.db);
|
||||
|
||||
if (!backend.destroy)
|
||||
return utils.nextTick(callback);
|
||||
@ -93,15 +89,9 @@ function destroy(name, backend, callback) {
|
||||
backend.destroy(file, callback);
|
||||
}
|
||||
|
||||
function repair(name, backend, callback) {
|
||||
var file = getLocation(name);
|
||||
|
||||
if (!callback) {
|
||||
callback = backend;
|
||||
backend = null;
|
||||
}
|
||||
|
||||
backend = getBackend(backend);
|
||||
function repair(options, callback) {
|
||||
var file = getLocation(options);
|
||||
var backend = getBackend(options.db);
|
||||
|
||||
if (!backend.repair)
|
||||
return utils.asyncify(callback)(new Error('Cannot repair.'));
|
||||
|
||||
@ -15,14 +15,16 @@ var assert = utils.assert;
|
||||
var BufferWriter = require('./writer');
|
||||
var BufferReader = require('./reader');
|
||||
var VerifyError = utils.VerifyError;
|
||||
var pad32 = utils.pad32;
|
||||
var DUMMY = new Buffer([0]);
|
||||
|
||||
/**
|
||||
* Mempool
|
||||
*/
|
||||
|
||||
function Mempool(node, options) {
|
||||
function Mempool(options) {
|
||||
if (!(this instanceof Mempool))
|
||||
return new Mempool(node, options);
|
||||
return new Mempool(options);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
@ -30,12 +32,14 @@ function Mempool(node, options) {
|
||||
options = {};
|
||||
|
||||
this.options = options;
|
||||
this.node = node;
|
||||
this.chain = node.chain;
|
||||
this.chain = options.chain;
|
||||
|
||||
assert(this.chain, 'Mempool requires a blockchain.');
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
this.locker = new bcoin.locker(this, this.addTX, 20 << 20);
|
||||
this.writeLock = new bcoin.locker(this);
|
||||
|
||||
this.db = null;
|
||||
this.tx = null;
|
||||
@ -55,8 +59,6 @@ function Mempool(node, options) {
|
||||
// Use an in-memory binary search tree by default
|
||||
this.backend = this.options.memory === false ? 'leveldb' : 'memory';
|
||||
|
||||
Mempool.global = this;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
@ -82,6 +84,11 @@ Mempool.prototype.purgePending = function purgePending() {
|
||||
Mempool.prototype._init = function _init() {
|
||||
var self = this;
|
||||
var unlock = this._lock(utils.nop, []);
|
||||
var options = {
|
||||
name: this.options.name || 'mempool',
|
||||
location: this.options.location,
|
||||
db: this.backend
|
||||
};
|
||||
|
||||
assert(unlock);
|
||||
|
||||
@ -89,22 +96,16 @@ Mempool.prototype._init = function _init() {
|
||||
// reason for using an on-disk db for the mempool
|
||||
// is not for persistence, but to keep ~300mb of
|
||||
// txs out of main memory.
|
||||
bcoin.ldb.destroy('mempool', this.backend, function(err) {
|
||||
bcoin.ldb.destroy(options, function(err) {
|
||||
if (err) {
|
||||
unlock();
|
||||
return self.emit('error', err);
|
||||
}
|
||||
|
||||
self.db = bcoin.ldb('mempool', {
|
||||
db: self.backend
|
||||
});
|
||||
self.db = bcoin.ldb(options);
|
||||
|
||||
self.tx = new bcoin.txdb('m', self.db, {
|
||||
indexExtra: false,
|
||||
indexAddress: false,
|
||||
mapAddress: false,
|
||||
verify: false
|
||||
});
|
||||
// Use the txdb object for its get methods.
|
||||
self.tx = new bcoin.txdb('m', self.db);
|
||||
|
||||
self.db.open(function(err) {
|
||||
if (err) {
|
||||
@ -456,7 +457,7 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
|
||||
Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) {
|
||||
var self = this;
|
||||
this.tx.addUnchecked(tx, function(err) {
|
||||
this._addUnchecked(tx, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -466,9 +467,6 @@ Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) {
|
||||
|
||||
utils.debug('Added tx %s to the mempool.', tx.rhash);
|
||||
|
||||
if (self.options.relay)
|
||||
self.node.broadcast(tx);
|
||||
|
||||
self.resolveOrphans(tx, function(err, resolved) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -509,7 +507,7 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(tx, callback) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.tx.removeUnchecked(tx, function(err) {
|
||||
self._removeUnchecked(tx, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.size -= tx.getSize();
|
||||
@ -1088,6 +1086,137 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) {
|
||||
var self = this;
|
||||
var prefix = 'm/';
|
||||
var hash = tx.hash('hex');
|
||||
var batch;
|
||||
|
||||
var unlock = this.writeLock.lock(addUnchecked, [tx, callback], force);
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
batch = this.db.batch();
|
||||
|
||||
batch.put(prefix + 't/t/' + hash, tx.toExtended());
|
||||
batch.put(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash, DUMMY);
|
||||
|
||||
tx.getAddresses().forEach(function(address) {
|
||||
batch.put(prefix + 't/a/' + address + '/' + hash, DUMMY);
|
||||
});
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return;
|
||||
|
||||
assert(input.coin);
|
||||
address = input.getAddress();
|
||||
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
batch.put(prefix + 's/t/' + key, tx.hash());
|
||||
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
});
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address = output.getAddress();
|
||||
var coin = bcoin.coin(tx, i).toRaw();
|
||||
|
||||
batch.put(prefix + 'u/t/' + key, coin);
|
||||
|
||||
if (address)
|
||||
batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY);
|
||||
});
|
||||
|
||||
return batch.write(callback);
|
||||
};
|
||||
|
||||
Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, force) {
|
||||
var self = this;
|
||||
var prefix = 'm/';
|
||||
var batch;
|
||||
|
||||
var unlock = this.writeLock.lock(removeUnchecked, [hash, callback], force);
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
this.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!tx)
|
||||
return callback();
|
||||
|
||||
batch = self.db.batch();
|
||||
|
||||
batch.del(prefix + 't/t/' + hash);
|
||||
batch.del(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash);
|
||||
|
||||
tx.getAddresses().forEach(function(address) {
|
||||
batch.del(prefix + 't/a/' + address + '/' + hash);
|
||||
});
|
||||
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return next();
|
||||
|
||||
if (!input.coin)
|
||||
return next();
|
||||
|
||||
address = input.getAddress();
|
||||
|
||||
batch.del(prefix + 's/t/' + key);
|
||||
|
||||
self.hasTX(input.prevout.hash, function(err, result) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (result) {
|
||||
batch.put(prefix + 'u/t/' + key, input.coin.toRaw());
|
||||
if (address)
|
||||
batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY);
|
||||
} else {
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address = output.getAddress();
|
||||
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
});
|
||||
|
||||
return batch.write(callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -17,9 +17,9 @@ var EventEmitter = require('events').EventEmitter;
|
||||
* Miner
|
||||
*/
|
||||
|
||||
function Miner(node, options) {
|
||||
function Miner(options) {
|
||||
if (!(this instanceof Miner))
|
||||
return new Miner(node, options);
|
||||
return new Miner(options);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
@ -34,10 +34,11 @@ function Miner(node, options) {
|
||||
// wants to pass in a faster linked in function.
|
||||
this.dsha256 = this.options.dsha256 || utils.dsha256;
|
||||
|
||||
this.node = node;
|
||||
this.pool = node.pool;
|
||||
this.chain = node.chain;
|
||||
this.mempool = node.mempool;
|
||||
this.pool = options.pool;
|
||||
this.chain = options.chain;
|
||||
this.mempool = options.mempool;
|
||||
|
||||
assert(this.chain, 'Miner requires a blockchain.');
|
||||
|
||||
this.running = false;
|
||||
this.timeout = null;
|
||||
@ -69,7 +70,7 @@ Miner.prototype._init = function _init() {
|
||||
return;
|
||||
self.addTX(tx);
|
||||
});
|
||||
} else {
|
||||
} else if (this.pool) {
|
||||
this.pool.on('tx', function(tx) {
|
||||
if (!self.running)
|
||||
return;
|
||||
@ -93,7 +94,6 @@ Miner.prototype._init = function _init() {
|
||||
block.hash('hex'));
|
||||
// Emit the block hex as a failsafe (in case we can't send it)
|
||||
utils.debug('Raw: %s', utils.toHex(block.render()));
|
||||
self.pool.sendBlock(block);
|
||||
});
|
||||
|
||||
this.on('status', function(stat) {
|
||||
|
||||
@ -39,8 +39,6 @@ function Node(options) {
|
||||
this.chain = null;
|
||||
this.miner = null;
|
||||
this.walletdb = null;
|
||||
|
||||
Node.global = this;
|
||||
}
|
||||
|
||||
utils.inherits(Node, EventEmitter);
|
||||
|
||||
@ -637,7 +637,7 @@ Peer.prototype._handleGetHeaders = function _handleGetHeaders(payload) {
|
||||
if (this.chain.db.options.spv)
|
||||
return;
|
||||
|
||||
if (this.chain.db.prune)
|
||||
if (this.chain.db.options.prune)
|
||||
return;
|
||||
|
||||
function collect(err, hash) {
|
||||
@ -705,7 +705,7 @@ Peer.prototype._handleGetBlocks = function _handleGetBlocks(payload) {
|
||||
if (this.chain.db.options.spv)
|
||||
return;
|
||||
|
||||
if (this.chain.db.prune)
|
||||
if (this.chain.db.options.prune)
|
||||
return;
|
||||
|
||||
function done(err) {
|
||||
@ -907,7 +907,7 @@ Peer.prototype._handleGetData = function handleGetData(items) {
|
||||
notfound.push({ type: constants.inv.block, hash: hash });
|
||||
return next();
|
||||
}
|
||||
if (self.chain.db.prune) {
|
||||
if (self.chain.db.options.prune) {
|
||||
notfound.push({ type: constants.inv.block, hash: hash });
|
||||
return;
|
||||
}
|
||||
@ -944,7 +944,7 @@ Peer.prototype._handleGetData = function handleGetData(items) {
|
||||
notfound.push({ type: constants.inv.block, hash: hash });
|
||||
return next();
|
||||
}
|
||||
if (self.chain.db.prune) {
|
||||
if (self.chain.db.options.prune) {
|
||||
notfound.push({ type: constants.inv.block, hash: hash });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -16,12 +16,12 @@ var constants = bcoin.protocol.constants;
|
||||
* Pool
|
||||
*/
|
||||
|
||||
function Pool(node, options) {
|
||||
function Pool(options) {
|
||||
var self = this;
|
||||
var seeds;
|
||||
|
||||
if (!(this instanceof Pool))
|
||||
return new Pool(node, options);
|
||||
return new Pool(options);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
@ -29,7 +29,10 @@ function Pool(node, options) {
|
||||
options = {};
|
||||
|
||||
this.options = options;
|
||||
this.network = node.network;
|
||||
this.chain = options.chain;
|
||||
this.mempool = options.mempool;
|
||||
|
||||
assert(this.chain, 'Pool requires a blockchain.');
|
||||
|
||||
if (options.relay == null) {
|
||||
if (options.spv)
|
||||
@ -54,9 +57,6 @@ function Pool(node, options) {
|
||||
this.size = options.size || 8;
|
||||
this.connected = false;
|
||||
|
||||
this.chain = node.chain;
|
||||
this.mempool = node.mempool;
|
||||
|
||||
if (options.spv) {
|
||||
if (options.headers == null)
|
||||
options.headers = true;
|
||||
@ -138,8 +138,6 @@ function Pool(node, options) {
|
||||
timeout: options.invTimeout || 60000
|
||||
};
|
||||
|
||||
Pool.global = this;
|
||||
|
||||
this.chain.open(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
@ -161,11 +159,19 @@ Pool.prototype.open = function open(callback) {
|
||||
};
|
||||
|
||||
Pool.prototype.connect = function connect() {
|
||||
var self = this;
|
||||
|
||||
assert(this.loaded, 'Pool is not loaded.');
|
||||
|
||||
if (this.connected)
|
||||
return;
|
||||
|
||||
if (this.mempool && this.options.broadcast) {
|
||||
this.mempool.on('tx', function(tx) {
|
||||
self.broadcast(tx);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.originalSeeds.length > 0) {
|
||||
this._addLoader();
|
||||
|
||||
|
||||
@ -23,8 +23,6 @@ function SPVNode(options) {
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
SPVNode.global = this;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
@ -36,24 +34,26 @@ SPVNode.prototype._init = function _init() {
|
||||
|
||||
this.wallet = null;
|
||||
|
||||
this.chain = new bcoin.chain(this, {
|
||||
this.chain = new bcoin.chain({
|
||||
preload: this.options.preload,
|
||||
spv: true,
|
||||
useCheckpoints: this.options.useCheckpoints
|
||||
useCheckpoints: this.options.useCheckpoints,
|
||||
spv: true
|
||||
});
|
||||
|
||||
// Pool needs access to the chain.
|
||||
this.pool = new bcoin.pool(this, {
|
||||
this.pool = new bcoin.pool({
|
||||
chain: this.chain,
|
||||
witness: this.network.witness,
|
||||
selfish: true,
|
||||
listen: false,
|
||||
spv: true
|
||||
});
|
||||
|
||||
// WalletDB needs access to the network type.
|
||||
this.walletdb = new bcoin.walletdb(this);
|
||||
this.walletdb = new bcoin.walletdb({
|
||||
verify: true
|
||||
});
|
||||
|
||||
this.http = new bcoin.http.server(this, {
|
||||
this.http = new bcoin.http.server({
|
||||
node: this,
|
||||
key: this.options.sslKey,
|
||||
cert: this.options.sslCert,
|
||||
port: this.options.httpPort || 8080,
|
||||
|
||||
@ -1621,146 +1621,6 @@ TXPool.prototype.getBalanceByAddress = function getBalanceByAddress(address, cal
|
||||
return this.getBalance(address, callback);
|
||||
};
|
||||
|
||||
TXPool.prototype.addUnchecked = function addUnchecked(tx, callback, force) {
|
||||
var self = this;
|
||||
var prefix = this.prefix + '/';
|
||||
var hash = tx.hash('hex');
|
||||
var batch;
|
||||
|
||||
var unlock = this._lock(addUnchecked, [tx, callback], force);
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
batch = this.db.batch();
|
||||
|
||||
batch.put(prefix + 't/t/' + hash, tx.toExtended());
|
||||
batch.put(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash, DUMMY);
|
||||
|
||||
tx.getAddresses().forEach(function(address) {
|
||||
batch.put(prefix + 't/a/' + address + '/' + hash, DUMMY);
|
||||
});
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return;
|
||||
|
||||
assert(input.coin);
|
||||
address = input.getAddress();
|
||||
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
batch.put(prefix + 's/t/' + key, tx.hash());
|
||||
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
});
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address = output.getAddress();
|
||||
var coin = bcoin.coin(tx, i).toRaw();
|
||||
batch.put(prefix + 'u/t/' + key, coin);
|
||||
|
||||
if (address)
|
||||
batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY);
|
||||
});
|
||||
|
||||
return batch.write(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.emit('add tx', tx);
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
TXPool.prototype.removeUnchecked = function removeUnchecked(hash, callback, force) {
|
||||
var self = this;
|
||||
var prefix = this.prefix + '/';
|
||||
var batch;
|
||||
|
||||
var unlock = this._lock(removeUnchecked, [hash, callback], force);
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
this.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!tx)
|
||||
return callback();
|
||||
|
||||
batch = self.db.batch();
|
||||
|
||||
batch.del(prefix + 't/t/' + hash);
|
||||
batch.del(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash);
|
||||
|
||||
tx.getAddresses().forEach(function(address) {
|
||||
batch.del(prefix + 't/a/' + address + '/' + hash);
|
||||
});
|
||||
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return next();
|
||||
|
||||
if (!input.coin)
|
||||
return next();
|
||||
|
||||
address = input.getAddress();
|
||||
|
||||
batch.del(prefix + 's/t/' + key);
|
||||
|
||||
self.hasTX(input.prevout.hash, function(err, result) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (result) {
|
||||
batch.put(prefix + 'u/t/' + key, input.coin.toRaw());
|
||||
if (address)
|
||||
batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY);
|
||||
} else {
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address = output.getAddress();
|
||||
|
||||
batch.del(prefix + 'u/t/' + key);
|
||||
|
||||
if (address)
|
||||
batch.del(prefix + 'u/a/' + address + '/' + key);
|
||||
});
|
||||
|
||||
batch.write(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.emit('remove tx', tx);
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TXPool.prototype.zap = function zap(address, now, age, callback, force) {
|
||||
var self = this;
|
||||
|
||||
|
||||
@ -15,31 +15,23 @@ var DUMMY = new Buffer([0]);
|
||||
* WalletDB
|
||||
*/
|
||||
|
||||
function WalletDB(node, options) {
|
||||
function WalletDB(options) {
|
||||
if (!(this instanceof WalletDB))
|
||||
return new WalletDB(node, options);
|
||||
|
||||
if (WalletDB.global)
|
||||
return WalletDB.global;
|
||||
return new WalletDB(options);
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.node = node;
|
||||
this.options = options;
|
||||
this.loaded = false;
|
||||
|
||||
WalletDB.global = this;
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
utils.inherits(WalletDB, EventEmitter);
|
||||
|
||||
WalletDB._db = {};
|
||||
|
||||
WalletDB.prototype.dump = function dump(callback) {
|
||||
var records = {};
|
||||
|
||||
@ -84,7 +76,9 @@ WalletDB.prototype._init = function _init() {
|
||||
if (this.loaded)
|
||||
return;
|
||||
|
||||
this.db = bcoin.ldb('wallet', {
|
||||
this.db = bcoin.ldb({
|
||||
name: this.options.name || 'wallet',
|
||||
location: this.options.location,
|
||||
cacheSize: 8 << 20,
|
||||
writeBufferSize: 4 << 20
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user