diff --git a/lib/bcoin/blockdb.js b/lib/bcoin/blockdb.js index e68d4d24..e584f948 100644 --- a/lib/bcoin/blockdb.js +++ b/lib/bcoin/blockdb.js @@ -22,11 +22,6 @@ function BlockDB(node, options) { if (!(this instanceof BlockDB)) return new BlockDB(node, options); - if (!(node instanceof bcoin.node)) { - options = node; - node = null; - } - // Some lazy loading levelup = require('levelup'); @@ -45,7 +40,7 @@ function BlockDB(node, options) { this.options = options; this.node = node; - this.data = new BlockData(options); + this.data = new BlockData(node, this, options); this.cache = { unspent: new bcoin.lru(32 * 1024 * 1024), @@ -1039,13 +1034,15 @@ BlockDB.prototype._getEntry = function _getEntry(height, callback) { * BlockData */ -function BlockData(options) { +function BlockData(node, blockdb, options) { if (!(this instanceof BlockData)) - return new BlockData(options); + return new BlockData(node, blockdb, options); if (!options) options = {}; + this.node = node; + this.blockdb = blockdb; this.options = options; this.file = options.blockFile; diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index e9665ad6..24865b0c 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -32,12 +32,12 @@ function Chain(node, options) { if (this.options.debug) bcoin.debug = this.options.debug; - this.db = new bcoin.chaindb(this); + this.node = node; this.request = new utils.RequestCache(); this.loading = false; - this.node = node; this.mempool = node.mempool; this.blockdb = node.blockdb; + this.db = new bcoin.chaindb(node, this); this.busy = false; this.jobs = []; this.pending = []; @@ -132,17 +132,6 @@ Chain.prototype._init = function _init() { 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; utils.debug('Chain is loading.'); diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 15b4c9cc..7e7bc309 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -20,9 +20,9 @@ var BLOCK_SIZE = bcoin.chainblock.BLOCK_SIZE; * ChainDB */ -function ChainDB(chain, options) { +function ChainDB(node, chain, options) { if (!(this instanceof ChainDB)) - return new ChainDB(chain, options); + return new ChainDB(node, chain, options); if (!options) options = {}; @@ -30,6 +30,8 @@ function ChainDB(chain, options) { EventEmitter.call(this); this.options = options; + this.node = node; + this.network = node.network; this.chain = chain; this.file = options.file; diff --git a/lib/bcoin/http.js b/lib/bcoin/http.js index e457bc69..6b1e66e5 100644 --- a/lib/bcoin/http.js +++ b/lib/bcoin/http.js @@ -60,7 +60,10 @@ HTTPServer.prototype._init = function _init() { }); 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 diff --git a/lib/bcoin/node.js b/lib/bcoin/node.js index 74656d5f..d67c31a8 100644 --- a/lib/bcoin/node.js +++ b/lib/bcoin/node.js @@ -28,17 +28,6 @@ function Fullnode(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; Fullnode.global = this; @@ -50,35 +39,52 @@ utils.inherits(Fullnode, bcoin.node); Fullnode.prototype._init = function _init() { var self = this; + var pending = 3; this.loading = true; - // BlockDB and Mempool need to be instantiated - // first because the chain needs access to them. + // BlockDB technically needs access to the + // chain, but that's only once it's being + // used for tx retrieval. this.blockdb = new bcoin.blockdb(this, { 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, { preload: false }); + // Pool needs access to the chain. this.pool = new bcoin.pool(this, { witness: this.network.type === 'segnet', spv: false }); - this.miner = new bcoin.miner(this, this.options.miner); - this.walletdb = new bcoin.walletdb(this, this.options.walletdb); + // Miner needs access to the mempool. + this.miner = new bcoin.miner(this, { + address: this.options.payoutAddress, + coinbaseFlags: this.options.coinbaseFlags + }); - if (this.options.http && bcoin.http) { - this.http = new bcoin.http(this, this.options.http); - this.http.listen(this.options.http.port || 8080); - } + // WalletDB needs access to the network type. + this.walletdb = new bcoin.walletdb(this, { + 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) { self.emit('error', err); }); @@ -87,15 +93,23 @@ Fullnode.prototype._init = function _init() { 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) { self.walletdb.ownTX(tx, function(err, input, output) { if (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) { self.emit('block', block); block.txs.forEach(function(tx) { @@ -107,7 +121,17 @@ Fullnode.prototype._init = function _init() { 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) { self.wallets.forEach(function(wallet) { 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) 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; - self.emit('load'); + this.chain.once('load', function() { + load(); + }); + + this.http.listen(this.options.httpPort || 8080, '0.0.0.0', function(err) { + if (err) + throw err; + + load(); }); }; diff --git a/lib/bcoin/node2.js b/lib/bcoin/node2.js index e484197e..477d9433 100644 --- a/lib/bcoin/node2.js +++ b/lib/bcoin/node2.js @@ -28,9 +28,12 @@ function Node(options) { this.options = options; - if (this.options.debug) + if (this.options.debug != null) bcoin.debug = this.options.debug; + if (this.options.debugFile != null) + bcoin.debugFile = this.options.debugFile; + if (this.options.network) network.set(this.options.network); @@ -40,6 +43,7 @@ function Node(options) { this.pool = null; this.chain = null; this.miner = null; + this.profiler = null; this.wallets = []; Node.global = this; diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 3cac6e33..2968613b 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -30,12 +30,6 @@ function Pool(node, options) { this.options = options; - if (options.debug) - bcoin.debug = this.options.debug; - - if (options.network) - network.set(options.network); - options.spv = options.spv !== false; if (options.type === 'spv') @@ -48,6 +42,7 @@ function Pool(node, options) { ? (!options.spv ? true : false) : options.relay; + this.network = node.network; this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost); this.setSeeds([]); @@ -152,6 +147,13 @@ function Pool(node, options) { this.loading = true; + if (!this.chain.loading) { + this.loading = false; + this.emit('load'); + this._init(); + return; + } + this.chain.once('load', function() { self.loading = false; self.emit('load'); @@ -1222,6 +1224,13 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) { if (this.loading) 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) return false; @@ -1238,9 +1247,6 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) { self.sendTX(tx); }); - if (!self.options.spv) - return callback(); - if (self._pendingSearch) return callback(); @@ -1259,82 +1265,42 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) { }; 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); + if (i == -1) return; + this.wallets.splice(i, 1); this.unwatchWallet(wallet); }; Pool.prototype.watchAddress = function watchAddress(address) { - if (address.script) { - // For the redeem script hash in outputs: - 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()); + address = bcoin.address.parse(address); + this.watch(address.hash); }; Pool.prototype.unwatchAddress = function unwatchAddress(address) { - if (addres.script) { - // For the redeem script hash in p2sh outputs: - 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()); + address = bcoin.address.parse(address); + this.unwatch(address.hash); }; Pool.prototype.watchWallet = function watchWallet(wallet) { - var self = this; - - wallet.addresses.forEach(function(address) { + Object.keys(wallet.addressMap).forEach(function(address) { this.watchAddress(address); }, 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) { - wallet.addresses.forEach(function(address) { + Object.keys(wallet.addressMap).forEach(function(address) { this.unwatchAddress(address); }, 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) { diff --git a/lib/bcoin/walletdb.js b/lib/bcoin/walletdb.js index 2108a774..3bce0657 100644 --- a/lib/bcoin/walletdb.js +++ b/lib/bcoin/walletdb.js @@ -26,11 +26,6 @@ function WalletDB(node, options) { if (WalletDB.global) return WalletDB.global; - if (!(node instanceof bcoin.node)) { - options = node; - node = null; - } - if (!options) options = {}; @@ -549,7 +544,7 @@ WalletDB.prototype.ownTX = function ownTX(tx, callback) { return callback(err); if (input || output) - return callback(null, input || [], output || []); + return callback(null, input, output); return callback(); }); @@ -560,6 +555,4 @@ WalletDB.prototype.ownTX = function ownTX(tx, callback) { * Expose */ - var self = this; - var self = this; module.exports = WalletDB;