more node improvements.
This commit is contained in:
parent
00b8f8950b
commit
45292df44d
@ -22,11 +22,6 @@ function BlockDB(node, options) {
|
|||||||
if (!(this instanceof BlockDB))
|
if (!(this instanceof BlockDB))
|
||||||
return new BlockDB(node, options);
|
return new BlockDB(node, options);
|
||||||
|
|
||||||
if (!(node instanceof bcoin.node)) {
|
|
||||||
options = node;
|
|
||||||
node = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some lazy loading
|
// Some lazy loading
|
||||||
levelup = require('levelup');
|
levelup = require('levelup');
|
||||||
|
|
||||||
@ -45,7 +40,7 @@ function BlockDB(node, options) {
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.data = new BlockData(options);
|
this.data = new BlockData(node, this, options);
|
||||||
|
|
||||||
this.cache = {
|
this.cache = {
|
||||||
unspent: new bcoin.lru(32 * 1024 * 1024),
|
unspent: new bcoin.lru(32 * 1024 * 1024),
|
||||||
@ -1039,13 +1034,15 @@ BlockDB.prototype._getEntry = function _getEntry(height, callback) {
|
|||||||
* BlockData
|
* BlockData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function BlockData(options) {
|
function BlockData(node, blockdb, options) {
|
||||||
if (!(this instanceof BlockData))
|
if (!(this instanceof BlockData))
|
||||||
return new BlockData(options);
|
return new BlockData(node, blockdb, options);
|
||||||
|
|
||||||
if (!options)
|
if (!options)
|
||||||
options = {};
|
options = {};
|
||||||
|
|
||||||
|
this.node = node;
|
||||||
|
this.blockdb = blockdb;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.file = options.blockFile;
|
this.file = options.blockFile;
|
||||||
|
|
||||||
|
|||||||
@ -32,12 +32,12 @@ function Chain(node, options) {
|
|||||||
if (this.options.debug)
|
if (this.options.debug)
|
||||||
bcoin.debug = this.options.debug;
|
bcoin.debug = this.options.debug;
|
||||||
|
|
||||||
this.db = new bcoin.chaindb(this);
|
this.node = node;
|
||||||
this.request = new utils.RequestCache();
|
this.request = new utils.RequestCache();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.node = node;
|
|
||||||
this.mempool = node.mempool;
|
this.mempool = node.mempool;
|
||||||
this.blockdb = node.blockdb;
|
this.blockdb = node.blockdb;
|
||||||
|
this.db = new bcoin.chaindb(node, this);
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
this.jobs = [];
|
this.jobs = [];
|
||||||
this.pending = [];
|
this.pending = [];
|
||||||
@ -132,17 +132,6 @@ Chain.prototype._init = function _init() {
|
|||||||
utils.debug('Warning: %d (%dmb) orphans cleared!', count, utils.mb(size));
|
utils.debug('Warning: %d (%dmb) orphans cleared!', count, utils.mb(size));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the mempool.
|
|
||||||
this.on('add block', function(block) {
|
|
||||||
if (self.mempool)
|
|
||||||
self.mempool.addBlock(block);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('remove block', function(block) {
|
|
||||||
if (self.mempool)
|
|
||||||
self.mempool.removeBlock(block);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
utils.debug('Chain is loading.');
|
utils.debug('Chain is loading.');
|
||||||
|
|||||||
@ -20,9 +20,9 @@ var BLOCK_SIZE = bcoin.chainblock.BLOCK_SIZE;
|
|||||||
* ChainDB
|
* ChainDB
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ChainDB(chain, options) {
|
function ChainDB(node, chain, options) {
|
||||||
if (!(this instanceof ChainDB))
|
if (!(this instanceof ChainDB))
|
||||||
return new ChainDB(chain, options);
|
return new ChainDB(node, chain, options);
|
||||||
|
|
||||||
if (!options)
|
if (!options)
|
||||||
options = {};
|
options = {};
|
||||||
@ -30,6 +30,8 @@ function ChainDB(chain, options) {
|
|||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.node = node;
|
||||||
|
this.network = node.network;
|
||||||
this.chain = chain;
|
this.chain = chain;
|
||||||
this.file = options.file;
|
this.file = options.file;
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,10 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.get('/', function(req, res, next, send) {
|
this.get('/', function(req, res, next, send) {
|
||||||
send(200, { version: require('../../package.json').version });
|
send(200, {
|
||||||
|
version: require('../../package.json').version,
|
||||||
|
network: self.node.network.type
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// UTXO by address
|
// UTXO by address
|
||||||
|
|||||||
@ -28,17 +28,6 @@ function Fullnode(options) {
|
|||||||
|
|
||||||
bcoin.node.call(this, options);
|
bcoin.node.call(this, options);
|
||||||
|
|
||||||
this.options.http = {};
|
|
||||||
|
|
||||||
if (!this.options.wallet)
|
|
||||||
this.options.wallet = {};
|
|
||||||
|
|
||||||
if (!this.options.wallet.id)
|
|
||||||
this.options.wallet.id = 'primary';
|
|
||||||
|
|
||||||
if (!this.options.wallet.passphrase)
|
|
||||||
this.options.wallet.passphrase = 'node';
|
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
Fullnode.global = this;
|
Fullnode.global = this;
|
||||||
@ -50,35 +39,52 @@ utils.inherits(Fullnode, bcoin.node);
|
|||||||
|
|
||||||
Fullnode.prototype._init = function _init() {
|
Fullnode.prototype._init = function _init() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var pending = 3;
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
// BlockDB and Mempool need to be instantiated
|
// BlockDB technically needs access to the
|
||||||
// first because the chain needs access to them.
|
// chain, but that's only once it's being
|
||||||
|
// used for tx retrieval.
|
||||||
this.blockdb = new bcoin.blockdb(this, {
|
this.blockdb = new bcoin.blockdb(this, {
|
||||||
cache: false
|
cache: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mempool = new bcoin.mempool(this);
|
// Mempool needs access to blockdb.
|
||||||
|
this.mempool = new bcoin.mempool(this, {
|
||||||
|
rbf: false
|
||||||
|
});
|
||||||
|
|
||||||
// Chain is instantiated next. The pool needs it.
|
// Chain needs access to blockdb.
|
||||||
this.chain = new bcoin.chain(this, {
|
this.chain = new bcoin.chain(this, {
|
||||||
preload: false
|
preload: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pool needs access to the chain.
|
||||||
this.pool = new bcoin.pool(this, {
|
this.pool = new bcoin.pool(this, {
|
||||||
witness: this.network.type === 'segnet',
|
witness: this.network.type === 'segnet',
|
||||||
spv: false
|
spv: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.miner = new bcoin.miner(this, this.options.miner);
|
// Miner needs access to the mempool.
|
||||||
this.walletdb = new bcoin.walletdb(this, this.options.walletdb);
|
this.miner = new bcoin.miner(this, {
|
||||||
|
address: this.options.payoutAddress,
|
||||||
|
coinbaseFlags: this.options.coinbaseFlags
|
||||||
|
});
|
||||||
|
|
||||||
if (this.options.http && bcoin.http) {
|
// WalletDB needs access to the network type.
|
||||||
this.http = new bcoin.http(this, this.options.http);
|
this.walletdb = new bcoin.walletdb(this, {
|
||||||
this.http.listen(this.options.http.port || 8080);
|
type: this.options.walletdb
|
||||||
}
|
});
|
||||||
|
|
||||||
|
// HTTP needs access to the mempool
|
||||||
|
// and blockdb.
|
||||||
|
this.http = new bcoin.http(this, {
|
||||||
|
key: this.options.httpKey,
|
||||||
|
cert: this.options.httpCert
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind to errors
|
||||||
this.mempool.on('error', function(err) {
|
this.mempool.on('error', function(err) {
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
});
|
});
|
||||||
@ -87,15 +93,23 @@ Fullnode.prototype._init = function _init() {
|
|||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.chain.on('error', function(err) {
|
||||||
|
self.emit('error', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit events for any TX we see that's
|
||||||
|
// is relevant to one of our wallets.
|
||||||
this.on('tx', function(tx) {
|
this.on('tx', function(tx) {
|
||||||
self.walletdb.ownTX(tx, function(err, input, output) {
|
self.walletdb.ownTX(tx, function(err, input, output) {
|
||||||
if (err)
|
if (err)
|
||||||
return self.emit('error', err);
|
return self.emit('error', err);
|
||||||
|
|
||||||
self.emit('own tx', tx, input, output);
|
if (input || output)
|
||||||
|
self.emit('wallet tx', tx, input || [], output || []);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Emit events for valid blocks and TXs.
|
||||||
this.chain.on('block', function(block) {
|
this.chain.on('block', function(block) {
|
||||||
self.emit('block', block);
|
self.emit('block', block);
|
||||||
block.txs.forEach(function(tx) {
|
block.txs.forEach(function(tx) {
|
||||||
@ -107,7 +121,17 @@ Fullnode.prototype._init = function _init() {
|
|||||||
self.emit('tx', tx);
|
self.emit('tx', tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle forks
|
// Update the mempool.
|
||||||
|
this.chain.on('add block', function(block) {
|
||||||
|
self.mempool.addBlock(block);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.chain.on('remove block', function(block) {
|
||||||
|
self.mempool.removeBlock(block);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle forks by unconfirming txs
|
||||||
|
// in our wallets' tx pools.
|
||||||
this.chain.on('remove entry', function(entry) {
|
this.chain.on('remove entry', function(entry) {
|
||||||
self.wallets.forEach(function(wallet) {
|
self.wallets.forEach(function(wallet) {
|
||||||
wallet.tx.getAll().forEach(function(tx) {
|
wallet.tx.getAll().forEach(function(tx) {
|
||||||
@ -117,16 +141,39 @@ Fullnode.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.createWallet(this.options.wallet, function(err, wallet) {
|
function load() {
|
||||||
|
if (!--pending) {
|
||||||
|
self.loading = false;
|
||||||
|
self.emit('load');
|
||||||
|
self.pool.startSync();
|
||||||
|
utils.debug('Node is loaded and syncing.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or load the primary wallet.
|
||||||
|
this.createWallet({ id: 'primary', passphrase: 'node' }, function(err, wallet) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
self.miner.address = wallet.getAddress();
|
// Set the miner payout address if the
|
||||||
|
// programmer didn't pass one in.
|
||||||
|
if (!self.miner.address)
|
||||||
|
self.miner.address = wallet.getAddress();
|
||||||
|
|
||||||
self.pool.startSync();
|
wallet.on('load', function() {
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
self.loading = false;
|
this.chain.once('load', function() {
|
||||||
self.emit('load');
|
load();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.http.listen(this.options.httpPort || 8080, '0.0.0.0', function(err) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
|
||||||
|
load();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -28,9 +28,12 @@ function Node(options) {
|
|||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
if (this.options.debug)
|
if (this.options.debug != null)
|
||||||
bcoin.debug = this.options.debug;
|
bcoin.debug = this.options.debug;
|
||||||
|
|
||||||
|
if (this.options.debugFile != null)
|
||||||
|
bcoin.debugFile = this.options.debugFile;
|
||||||
|
|
||||||
if (this.options.network)
|
if (this.options.network)
|
||||||
network.set(this.options.network);
|
network.set(this.options.network);
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ function Node(options) {
|
|||||||
this.pool = null;
|
this.pool = null;
|
||||||
this.chain = null;
|
this.chain = null;
|
||||||
this.miner = null;
|
this.miner = null;
|
||||||
|
this.profiler = null;
|
||||||
this.wallets = [];
|
this.wallets = [];
|
||||||
|
|
||||||
Node.global = this;
|
Node.global = this;
|
||||||
|
|||||||
@ -30,12 +30,6 @@ function Pool(node, options) {
|
|||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
if (options.debug)
|
|
||||||
bcoin.debug = this.options.debug;
|
|
||||||
|
|
||||||
if (options.network)
|
|
||||||
network.set(options.network);
|
|
||||||
|
|
||||||
options.spv = options.spv !== false;
|
options.spv = options.spv !== false;
|
||||||
|
|
||||||
if (options.type === 'spv')
|
if (options.type === 'spv')
|
||||||
@ -48,6 +42,7 @@ function Pool(node, options) {
|
|||||||
? (!options.spv ? true : false)
|
? (!options.spv ? true : false)
|
||||||
: options.relay;
|
: options.relay;
|
||||||
|
|
||||||
|
this.network = node.network;
|
||||||
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
|
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
|
||||||
this.setSeeds([]);
|
this.setSeeds([]);
|
||||||
|
|
||||||
@ -152,6 +147,13 @@ function Pool(node, options) {
|
|||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
|
if (!this.chain.loading) {
|
||||||
|
this.loading = false;
|
||||||
|
this.emit('load');
|
||||||
|
this._init();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.chain.once('load', function() {
|
this.chain.once('load', function() {
|
||||||
self.loading = false;
|
self.loading = false;
|
||||||
self.emit('load');
|
self.emit('load');
|
||||||
@ -1222,6 +1224,13 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) {
|
|||||||
if (this.loading)
|
if (this.loading)
|
||||||
return this.once('load', this.addWallet.bind(this, wallet, callback));
|
return this.once('load', this.addWallet.bind(this, wallet, callback));
|
||||||
|
|
||||||
|
if (!this.options.spv) {
|
||||||
|
wallet.getPending().forEach(function(tx) {
|
||||||
|
self.sendTX(tx);
|
||||||
|
});
|
||||||
|
return utils.nextTick(callback);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.wallets.indexOf(wallet) !== -1)
|
if (this.wallets.indexOf(wallet) !== -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1238,9 +1247,6 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) {
|
|||||||
self.sendTX(tx);
|
self.sendTX(tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!self.options.spv)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
if (self._pendingSearch)
|
if (self._pendingSearch)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
@ -1259,82 +1265,42 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.removeWallet = function removeWallet(wallet) {
|
Pool.prototype.removeWallet = function removeWallet(wallet) {
|
||||||
var i = this.wallets.indexOf(wallet);
|
var i;
|
||||||
|
|
||||||
|
if (!this.options.spv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
i = this.wallets.indexOf(wallet);
|
||||||
|
|
||||||
assert(!this.loading);
|
assert(!this.loading);
|
||||||
|
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.wallets.splice(i, 1);
|
this.wallets.splice(i, 1);
|
||||||
this.unwatchWallet(wallet);
|
this.unwatchWallet(wallet);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.watchAddress = function watchAddress(address) {
|
Pool.prototype.watchAddress = function watchAddress(address) {
|
||||||
if (address.script) {
|
address = bcoin.address.parse(address);
|
||||||
// For the redeem script hash in outputs:
|
this.watch(address.hash);
|
||||||
this.watch(address.getScriptHash160());
|
|
||||||
// For the redeem script in inputs:
|
|
||||||
this.watch(address.getScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address.program) {
|
|
||||||
// For programs inside P2SH
|
|
||||||
this.watch(address.getProgramHash());
|
|
||||||
// For witness scripthash
|
|
||||||
if (address.script)
|
|
||||||
this.watch(address.getScriptHash256());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the pubkey hash in outputs:
|
|
||||||
this.watch(address.getKeyHash());
|
|
||||||
// For the pubkey in inputs:
|
|
||||||
this.watch(address.getPublicKey());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.unwatchAddress = function unwatchAddress(address) {
|
Pool.prototype.unwatchAddress = function unwatchAddress(address) {
|
||||||
if (addres.script) {
|
address = bcoin.address.parse(address);
|
||||||
// For the redeem script hash in p2sh outputs:
|
this.unwatch(address.hash);
|
||||||
this.unwatch(address.getScriptHash160());
|
|
||||||
// For the redeem script in p2sh inputs:
|
|
||||||
this.unwatch(address.getScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address.program) {
|
|
||||||
// For programs inside P2SH
|
|
||||||
this.unwatch(address.getProgramHash());
|
|
||||||
// For witness scripthash
|
|
||||||
if (address.script)
|
|
||||||
this.unwatch(address.getScriptHash256());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the pubkey hash in p2pk/multisig outputs:
|
|
||||||
this.unwatch(address.getKeyHash());
|
|
||||||
// For the pubkey in p2pkh inputs:
|
|
||||||
this.unwatch(address.getPublicKey());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.watchWallet = function watchWallet(wallet) {
|
Pool.prototype.watchWallet = function watchWallet(wallet) {
|
||||||
var self = this;
|
Object.keys(wallet.addressMap).forEach(function(address) {
|
||||||
|
|
||||||
wallet.addresses.forEach(function(address) {
|
|
||||||
this.watchAddress(address);
|
this.watchAddress(address);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
wallet.on('add address', wallet._poolOnAdd = function(address) {
|
|
||||||
self.watchAddress(address);
|
|
||||||
});
|
|
||||||
|
|
||||||
wallet.on('remove address', wallet._poolOnRemove = function(address) {
|
|
||||||
self.unwatchAddress(address);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.unwatchWallet = function unwatchWallet(wallet) {
|
Pool.prototype.unwatchWallet = function unwatchWallet(wallet) {
|
||||||
wallet.addresses.forEach(function(address) {
|
Object.keys(wallet.addressMap).forEach(function(address) {
|
||||||
this.unwatchAddress(address);
|
this.unwatchAddress(address);
|
||||||
}, this);
|
}, this);
|
||||||
wallet.removeListener('add address', wallet._poolOnAdd);
|
|
||||||
wallet.removeListener('remove address', wallet._poolOnRemove);
|
|
||||||
delete wallet._poolOnAdd;
|
|
||||||
delete wallet._poolOnRemove;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.searchWallet = function(ts, height, callback) {
|
Pool.prototype.searchWallet = function(ts, height, callback) {
|
||||||
|
|||||||
@ -26,11 +26,6 @@ function WalletDB(node, options) {
|
|||||||
if (WalletDB.global)
|
if (WalletDB.global)
|
||||||
return WalletDB.global;
|
return WalletDB.global;
|
||||||
|
|
||||||
if (!(node instanceof bcoin.node)) {
|
|
||||||
options = node;
|
|
||||||
node = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options)
|
if (!options)
|
||||||
options = {};
|
options = {};
|
||||||
|
|
||||||
@ -549,7 +544,7 @@ WalletDB.prototype.ownTX = function ownTX(tx, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (input || output)
|
if (input || output)
|
||||||
return callback(null, input || [], output || []);
|
return callback(null, input, output);
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
@ -560,6 +555,4 @@ WalletDB.prototype.ownTX = function ownTX(tx, callback) {
|
|||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var self = this;
|
|
||||||
module.exports = WalletDB;
|
module.exports = WalletDB;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user