From 1a8a9afade7a33a543b76fdc607b301a3772291e Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 10 Mar 2017 20:25:00 -0800 Subject: [PATCH] config/wallet: refactor config handling. add wallet server. --- bin/cli | 10 ++- bin/node | 3 + bin/spvnode | 3 + browser/index.js | 27 +++---- etc/sample.conf | 4 +- lib/http/server.js | 19 ++--- lib/net/hostlist.js | 9 ++- lib/node/config.js | 169 ++++++++++++++++++++++++----------------- lib/node/fullnode.js | 9 ++- lib/node/node.js | 15 +++- lib/node/spvnode.js | 5 +- lib/utils/fs.js | 16 +++- lib/wallet/client.js | 5 +- lib/wallet/http.js | 3 +- lib/wallet/plugin.js | 65 ++++++++++++++++ lib/wallet/server.js | 67 ++++++++++++++++ lib/wallet/walletdb.js | 96 ++++++++--------------- package.json | 2 + test/node-test.js | 2 +- 19 files changed, 346 insertions(+), 183 deletions(-) create mode 100644 lib/wallet/plugin.js create mode 100644 lib/wallet/server.js diff --git a/bin/cli b/bin/cli index f0d2fe30..ea2fc110 100755 --- a/bin/cli +++ b/bin/cli @@ -11,9 +11,15 @@ var Amount = require('../lib/btc/amount'); var main; function CLI() { - this.config = new Config({ - network: 'main' + this.config = new Config('bcoin'); + + this.config.load({ + argv: true, + env: true }); + + this.config.open('bcoin.conf'); + this.argv = this.config.argv; this.client = null; this.wallet = null; diff --git a/bin/node b/bin/node index 6b8dcb79..5d61cb6c 100755 --- a/bin/node +++ b/bin/node @@ -9,6 +9,9 @@ var co = bcoin.co; var node; node = new bcoin.fullnode({ + config: true, + argv: true, + env: true, logFile: true, logLevel: 'debug', db: 'leveldb', diff --git a/bin/spvnode b/bin/spvnode index 7d7450f5..47b7e49b 100755 --- a/bin/spvnode +++ b/bin/spvnode @@ -11,6 +11,9 @@ var co = bcoin.co; var node; node = bcoin.spvnode({ + config: true, + argv: true, + env: true, logFile: true, logLevel: 'debug', db: 'leveldb', diff --git a/browser/index.js b/browser/index.js index 7e9d35fb..94301b52 100644 --- a/browser/index.js +++ b/browser/index.js @@ -15,7 +15,7 @@ var rpc = document.getElementById('rpc'); var cmd = document.getElementById('cmd'); var items = []; var scrollback = 0; -var logger, node, options; +var logger, node, wdb; body.onmouseup = function() { floating.style.display = 'none'; @@ -87,9 +87,9 @@ send.onsubmit = function(ev) { }] }; - node.wallet.createTX(options).then(function(mtx) { + wdb.primary.createTX(options).then(function(mtx) { tx = mtx; - return node.wallet.sign(tx); + return wdb.primary.sign(tx); }).then(function() { return node.sendTX(tx); }).then(function() { @@ -103,8 +103,8 @@ send.onsubmit = function(ev) { }; newaddr.onmouseup = function() { - node.wallet.createReceive().then(function() { - formatWallet(node.wallet); + wdb.primary.createReceive().then(function() { + formatWallet(wdb.primary); }); }; @@ -211,19 +211,17 @@ function formatWallet(wallet) { }); } -options = bcoin.config({ +node = new bcoin.fullnode({ + hash: true, query: true, + prune: true, network: 'testnet', db: 'leveldb', - useWorkers: true, coinCache: 30000000, logger: logger }); -bcoin.set(options); - -node = new bcoin.fullnode(options); -node.rpc = new bcoin.rpc(node); +wdb = node.use(bcoin.walletdb); node.on('error', function(err) { ; @@ -233,15 +231,14 @@ node.chain.on('block', addItem); node.mempool.on('tx', addItem); node.open().then(function() { - node.rpc.wallet = node.wallet; node.connect().then(function() { node.startSync(); - node.wallet.on('balance', function() { - formatWallet(node.wallet); + wdb.primary.on('balance', function() { + formatWallet(wdb.primary); }); - formatWallet(node.wallet); + formatWallet(wdb.primary); }); }); diff --git a/etc/sample.conf b/etc/sample.conf index d1ebbb81..7676c523 100644 --- a/etc/sample.conf +++ b/etc/sample.conf @@ -79,8 +79,6 @@ host: :: # BIP151 AuthDB and Identity Key bip150: false identity-key: 74b4147957813b62cc8987f2b711ddb31f8cb46dcbf71502033da66053c8780a -auth-peers: ./authorized-peers -known-peers: ./known-peers # Always try to connect to these nodes. # nodes: 127.0.0.1,127.0.0.2 @@ -90,7 +88,7 @@ known-peers: ./known-peers # coinbase-flags: mined by bcoin -# payout-address: 1111111111111111111114oLvT2,1111111111111111111114oLvT2 +# coinbase-address: 1111111111111111111114oLvT2,1111111111111111111114oLvT2 preverify: false max-block-weight: 4000000 reserved-block-weight: 4000 diff --git a/lib/http/server.js b/lib/http/server.js index 41a4ba56..4e86c555 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -20,7 +20,6 @@ var crypto = require('../crypto/crypto'); var Network = require('../protocol/network'); var Validator = require('../utils/validator'); var pkg = require('../pkg'); -var RPC = require('./rpc'); /** * HTTPServer @@ -50,7 +49,7 @@ function HTTPServer(options) { this.pool = this.node.pool; this.fees = this.node.fees; this.miner = this.node.miner; - this.rpc = new RPC(this.node); + this.rpc = this.node.rpc; this.init(); } @@ -387,7 +386,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) { socket.auth = true; - this.logger.info('Successful auth from %s.', socket.host); + this.logger.info('Successful auth from %s.', socket.remoteAddress); this.handleAuth(socket); return null; @@ -408,18 +407,22 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) { HTTPServer.prototype.handleAuth = function handleAuth(socket) { socket.hook('watch chain', function(args) { socket.join('chain'); + return null; }); socket.hook('unwatch chain', function(args) { socket.leave('chain'); + return null; }); socket.hook('watch mempool', function(args) { socket.join('mempool'); + return null; }); socket.hook('unwatch mempool', function(args) { socket.leave('mempool'); + return null; }); socket.hook('set filter', function(args) { @@ -443,7 +446,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { var block = valid.numhash(0); var entry; - if (!block) + if (block == null) throw new Error('Invalid parameter.'); entry = yield this.chain.db.getEntry(block); @@ -526,7 +529,7 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) { var valid = new Validator([args]); var start = valid.numhash(0); - if (!start) + if (start == null) throw new Error('Invalid parameter.'); return this.scan(socket, start); @@ -730,7 +733,6 @@ function HTTPOptions(options) { this.apiKey = base58.encode(crypto.randomBytes(20)); this.apiHash = hash256(this.apiKey); this.noAuth = false; - this.walletAuth = false; this.prefix = null; this.host = '127.0.0.1'; @@ -779,11 +781,6 @@ HTTPOptions.prototype.fromOptions = function fromOptions(options) { this.noAuth = options.noAuth; } - if (options.walletAuth != null) { - assert(typeof options.walletAuth === 'boolean'); - this.walletAuth = options.walletAuth; - } - if (options.prefix != null) { assert(typeof options.prefix === 'string'); this.prefix = options.prefix; diff --git a/lib/net/hostlist.js b/lib/net/hostlist.js index 88d43d01..d5ea9e2a 100644 --- a/lib/net/hostlist.js +++ b/lib/net/hostlist.js @@ -51,6 +51,7 @@ function HostList(options) { this.banned = {}; this.timer = null; + this.needsFlush = false; this._init(); } @@ -287,6 +288,9 @@ HostList.prototype.flush = co(function* flush() { if (!filename) return; + if (!this.needsFlush) + return; + this.logger.debug('Writing hosts to %s.', filename); json = this.toJSON(); @@ -505,8 +509,10 @@ HostList.prototype.add = function add(addr, src) { interval = 60 * 60; // Periodically update time. - if (entry.addr.ts < addr.ts - interval - penalty) + if (entry.addr.ts < addr.ts - interval - penalty) { entry.addr.ts = addr.ts; + this.needsFlush = true; + } // Do not update if no new // information is present. @@ -558,6 +564,7 @@ HostList.prototype.add = function add(addr, src) { entry.refCount++; this.map[entry.key()] = entry; + this.needsFlush = true; return true; }; diff --git a/lib/node/config.js b/lib/node/config.js index 84105406..d4744be6 100644 --- a/lib/node/config.js +++ b/lib/node/config.js @@ -1,5 +1,5 @@ /*! - * config.js - bcoin configuration + * config.js - configuration parsing for bcoin * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ @@ -12,15 +12,21 @@ var util = require('../utils/util'); var global = util.global; /** - * Node Config + * Config Parser * @alias module:node.Config * @constructor - * @param {Object} options + * @param {String} module - Module name (e.g. `bcoin`). */ -function Config(options) { +function Config(module) { if (!(this instanceof Config)) - return new Config(options); + return new Config(module); + + assert(typeof module === 'string'); + + this.module = module; + this.network = 'main'; + this.prefix = util.HOME + '/.' + module; this.options = Object.create(null); this.data = Object.create(null); @@ -29,14 +35,6 @@ function Config(options) { this.argv = []; this.query = Object.create(null); this.hash = Object.create(null); - this.prefix = null; - this.network = null; - - if (options) - this.inject(options); - - this.init(); - this.open(); } /** @@ -57,48 +55,6 @@ Config.alias = { } }; -/** - * Initialize the config. - * @private - */ - -Config.prototype.init = function init() { - this.parseHash(); - this.parseQuery(); - this.parseEnv(); - this.parseArg(); - - this.network = this.getNetwork(); - this.prefix = this.getPrefix(); -}; - -/** - * Open the config. - * @private - */ - -Config.prototype.open = function open() { - var file, text; - - if (fs.unsupported) - return; - - file = this.getFile(); - - try { - text = fs.readFileSync(file, 'utf8'); - } catch (e) { - if (e.code === 'ENOENT') - return; - throw e; - } - - this.parseConfig(text); - - this.network = this.getNetwork(); - this.prefix = this.getPrefix(); -}; - /** * Inject options. * @param {Object} options @@ -110,11 +66,72 @@ Config.prototype.inject = function inject(options) { for (i = 0; i < keys.length; i++) { key = keys[i]; + + switch (key) { + case 'hash': + case 'query': + case 'env': + case 'argv': + case 'config': + continue; + } + value = options[key]; + this.set(key, value); } }; +/** + * Load options from hash, query, env, or args. + * @param {Object} options + */ + +Config.prototype.load = function load(options) { + if (options.hash) + this.parseHash(options.hash); + + if (options.query) + this.parseQuery(options.query); + + if (options.env) + this.parseEnv(options.env); + + if (options.argv) + this.parseArg(options.argv); + + this.network = this.getNetwork(); + this.prefix = this.getPrefix(); +}; + +/** + * Open a config file. + * @param {String} file - e.g. `bcoin.conf`. + * @throws on IO error + */ + +Config.prototype.open = function open(file) { + var path, text; + + if (fs.unsupported) + return; + + path = this.getFile(file); + + try { + text = fs.readFileSync(path, 'utf8'); + } catch (e) { + if (e.code === 'ENOENT') + return; + throw e; + } + + this.parseConfig(text); + + this.network = this.getNetwork(); + this.prefix = this.getPrefix(); +}; + /** * Set default option. * @param {String} key @@ -492,7 +509,7 @@ Config.prototype.getPrefix = function getPrefix() { if (prefix) return prefix; - prefix = util.HOME + '/.bcoin'; + prefix = util.HOME + '/.' + this.module; network = this.str('network'); if (network) { @@ -507,16 +524,27 @@ Config.prototype.getPrefix = function getPrefix() { /** * Grab config filename from config data. * @private + * @param {String} file * @returns {String} */ -Config.prototype.getFile = function getFile() { - var file = this.str('config'); +Config.prototype.getFile = function getFile(file) { + var path = this.str('config'); - if (file) - return file; + if (path) + return path; - return this.prefix + '/bcoin.conf'; + return this.prefix + '/' + file; +}; + +/** + * Create a file path using `prefix`. + * @param {String} file + * @returns {String} + */ + +Config.prototype.location = function location(file) { + return this.prefix + '/' + file; }; /** @@ -581,7 +609,7 @@ Config.prototype.parseConfig = function parseConfig(text) { Config.prototype.parseArg = function parseArg(argv) { var i, j, arg, key, value, alias, equals; - if (!argv) + if (!argv || typeof argv !== 'object') argv = process.argv; for (i = 2; i < argv.length; i++) { @@ -653,18 +681,19 @@ Config.prototype.parseArg = function parseArg(argv) { * Parse environment variables. * @private * @param {Object?} env - * @param {String?} prefix * @returns {Object} */ -Config.prototype.parseEnv = function parseEnv(env, prefix) { +Config.prototype.parseEnv = function parseEnv(env) { + var prefix = this.module; var i, keys, key, value, alias; - if (!env) - env = process.env; + prefix = prefix.toUpperCase(); + prefix = prefix.replace(/-/g, '_'); + prefix += '_'; - if (!prefix) - prefix = 'BCOIN_'; + if (!env || typeof env !== 'object') + env = process.env; keys = Object.keys(env); @@ -700,7 +729,7 @@ Config.prototype.parseEnv = function parseEnv(env, prefix) { */ Config.prototype.parseQuery = function parseQuery(query) { - if (query == null) { + if (typeof query !== 'string') { if (!util.isBrowser || !global.location) return {}; @@ -717,7 +746,7 @@ Config.prototype.parseQuery = function parseQuery(query) { */ Config.prototype.parseHash = function parseHash(hash) { - if (hash == null) { + if (typeof hash !== 'string') { if (!util.isBrowser || !global.location) return {}; diff --git a/lib/node/fullnode.js b/lib/node/fullnode.js index 604be111..31830182 100644 --- a/lib/node/fullnode.js +++ b/lib/node/fullnode.js @@ -16,6 +16,7 @@ var Mempool = require('../mempool/mempool'); var Pool = require('../net/pool'); var Miner = require('../mining/miner'); var HTTPServer = require('../http/server'); +var RPC = require('../http/rpc'); /** * Respresents a fullnode complete with a @@ -118,8 +119,7 @@ function FullNode(options) { logger: this.logger, chain: this.chain, mempool: this.mempool, - fees: this.fees, - address: this.config.array('payout-address'), + address: this.config.array('coinbase-address'), coinbaseFlags: this.config.str('coinbase-flags'), preverify: this.config.bool('preverify'), maxWeight: this.config.num('max-weight'), @@ -127,6 +127,9 @@ function FullNode(options) { reservedSigops: this.config.num('reserved-sigops') }); + // RPC needs access to the node. + this.rpc = new RPC(this); + // HTTP needs access to the node. if (!HTTPServer.unsupported) { this.http = new HTTPServer({ @@ -140,8 +143,6 @@ function FullNode(options) { host: this.config.str('http-host'), port: this.config.num('http-port'), apiKey: this.config.str('api-key'), - serviceKey: this.config.str('service-key'), - walletAuth: this.config.bool('wallet-auth'), noAuth: this.config.bool('no-auth') }); } diff --git a/lib/node/node.js b/lib/node/node.js index 0a0e1367..7d0f5eff 100644 --- a/lib/node/node.js +++ b/lib/node/node.js @@ -34,7 +34,13 @@ function Node(options) { AsyncObject.call(this); - this.config = new Config(options); + this.config = new Config('bcoin'); + this.config.inject(options); + this.config.load(options); + + if (options.config) + this.config.open('bcoin.conf'); + this.network = Network.get(this.config.network); this.startTime = -1; this.bound = []; @@ -269,6 +275,7 @@ Node.prototype.uptime = function uptime() { /** * Attach a plugin. * @param {Object} plugin + * @returns {Object} Plugin instance. */ Node.prototype.use = function use(plugin) { @@ -285,7 +292,7 @@ Node.prototype.use = function use(plugin) { assert(typeof instance.close === 'function', '`close` must be a function.'); if (plugin.id) { - assert(typeof plugin.id === 'string', '`name` must be a string.'); + assert(typeof plugin.id === 'string', '`id` must be a string.'); // Reserved names switch (plugin.id) { @@ -305,6 +312,8 @@ Node.prototype.use = function use(plugin) { } this.stack.push(instance); + + return instance; }; /** @@ -366,7 +375,7 @@ Node.prototype.loadPlugins = function loadPlugins() { // Temporary until we separate walletdb out. if (name === 'walletdb') - name = __dirname + '/../wallet/walletdb'; + name = __dirname + '/../wallet/plugin'; plugin = loader(name); diff --git a/lib/node/spvnode.js b/lib/node/spvnode.js index dc2de83e..4c00bfc4 100644 --- a/lib/node/spvnode.js +++ b/lib/node/spvnode.js @@ -14,6 +14,7 @@ var Node = require('./node'); var Chain = require('../blockchain/chain'); var Pool = require('../net/pool'); var HTTPServer = require('../http/server'); +var RPC = require('../http/rpc'); /** * Create an spv node which only maintains @@ -74,6 +75,8 @@ function SPVNode(options) { listen: false }); + this.rpc = new RPC(this); + if (!HTTPServer.unsupported) { this.http = new HTTPServer({ network: this.network, @@ -86,8 +89,6 @@ function SPVNode(options) { host: this.config.str('host'), port: this.config.num('port'), apiKey: this.config.str('api-key'), - serviceKey: this.config.str('service-key'), - walletAuth: this.config.bool('wallet-auth'), noAuth: this.config.bool('no-auth') }); } diff --git a/lib/utils/fs.js b/lib/utils/fs.js index c004e240..b76a9cb4 100644 --- a/lib/utils/fs.js +++ b/lib/utils/fs.js @@ -1,3 +1,11 @@ +/*! + * fs.js - promisified fs module for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + var fs = require('fs'); var co = require('./co'); @@ -144,9 +152,11 @@ function getParts(path) { path = parts.shift() + '/'; } - if (parts[0].length === 0) { - parts.shift(); - path = '/'; + if (parts.length > 0) { + if (parts[0].length === 0) { + parts.shift(); + path = '/'; + } } return { diff --git a/lib/wallet/client.js b/lib/wallet/client.js index b71736be..d0582f86 100644 --- a/lib/wallet/client.js +++ b/lib/wallet/client.js @@ -340,9 +340,10 @@ function parseEntry(data, enc) { if (typeof data === 'string') data = new Buffer(data, 'hex'); - br = new BufferReader(data); + block = Headers.fromAbbr(data); - block = Headers.fromAbbr(br); + br = new BufferReader(data); + br.seek(80); height = br.readU32(); hash = block.hash('hex'); diff --git a/lib/wallet/http.js b/lib/wallet/http.js index 4ac641d7..51107274 100644 --- a/lib/wallet/http.js +++ b/lib/wallet/http.js @@ -19,7 +19,6 @@ var crypto = require('../crypto/crypto'); var Network = require('../protocol/network'); var Validator = require('../utils/validator'); var common = require('./common'); -var RPC = require('./rpc'); /** * HTTPServer @@ -44,7 +43,7 @@ function HTTPServer(options) { this.walletdb = this.options.walletdb; this.server = new HTTPBase(this.options); - this.rpc = new RPC(this.walletdb); + this.rpc = this.walletdb.rpc; this.init(); } diff --git a/lib/wallet/plugin.js b/lib/wallet/plugin.js new file mode 100644 index 00000000..4ad0528c --- /dev/null +++ b/lib/wallet/plugin.js @@ -0,0 +1,65 @@ +/*! + * plugin.js - wallet plugin for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var WalletDB = require('./walletdb'); +var NodeClient = require('../node/nodeclient'); + +/** + * @exports wallet/plugin + */ + +var plugin = exports; + +/** + * Plugin name. + * @const {String} + */ + +plugin.id = 'walletdb'; + +/** + * Plugin initialization. + * @param {Node} node + * @returns {WalletDB} + */ + +plugin.init = function init(node) { + var config = node.config; + var client = new NodeClient(node); + var wdb; + + wdb = new WalletDB({ + network: node.network, + logger: node.logger, + client: client, + prefix: config.prefix, + db: config.str(['wallet-db', 'db']), + maxFiles: config.num('wallet-max-files'), + cacheSize: config.mb('wallet-cache-size'), + witness: config.bool('wallet-witness'), + checkpoints: config.bool('wallet-checkpoints'), + startHeight: config.num('wallet-start-height'), + wipeNoReally: config.bool('wallet-wipe-no-really'), + apiKey: config.str(['wallet-api-key', 'api-key']), + walletAuth: config.bool('wallet-auth'), + noAuth: config.bool(['wallet-no-auth', 'no-auth']), + ssl: config.str('wallet-ssl'), + host: config.str('wallet-host'), + port: config.num('wallet-port'), + spv: node.spv, + verify: node.spv, + listen: false + }); + + if (node.http && wdb.http) + wdb.http.attach(node.http); + + wdb.rpc.attach(node.rpc); + + return wdb; +}; diff --git a/lib/wallet/server.js b/lib/wallet/server.js new file mode 100644 index 00000000..ef94629d --- /dev/null +++ b/lib/wallet/server.js @@ -0,0 +1,67 @@ +/*! + * server.js - wallet server for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var WalletDB = require('./walletdb'); +var Config = require('../node/config'); +var Logger = require('../node/logger'); +var Client = require('./client'); + +/** + * @exports wallet/server + */ + +var server = exports; + +/** + * Create a wallet server. + * @param {Object} options + * @returns {WalletDB} + */ + +server.create = function create(options) { + var config = new Config('bcoin'); + var logger = new Logger('debug'); + var client; + + config.inject(options); + config.load(options); + + if (options.config) + config.open('wallet.conf'); + + client = new Client({ + network: config.network, + uri: config.str('node-uri'), + apiKey: config.str('node-api-key') + }); + + logger.setFile(config.location('wallet.log')); + + return new WalletDB({ + network: config.network, + logger: logger, + client: client, + prefix: config.prefix, + db: config.str('db'), + maxFiles: config.num('max-files'), + cacheSize: config.mb('cache-size'), + witness: config.bool('witness'), + checkpoints: config.bool('checkpoints'), + startHeight: config.num('start-height'), + wipeNoReally: config.bool('wipe-no-really'), + apiKey: config.str('api-key'), + walletAuth: config.bool('auth'), + noAuth: config.bool('no-auth'), + ssl: config.str('ssl'), + host: config.str('host'), + port: config.num('port'), + spv: config.bool('spv'), + verify: config.bool('spv'), + listen: true + }); +}; diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 1e7f83fa..c916de98 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -26,8 +26,8 @@ var Logger = require('../node/logger'); var Outpoint = require('../primitives/outpoint'); var layouts = require('./layout'); var records = require('./records'); -var NodeClient = require('../node/nodeclient'); -var HTTP = require('./http'); +var HTTPServer = require('./http'); +var RPC = require('./rpc'); var layout = layouts.walletdb; var ChainState = records.ChainState; var BlockMapRecord = records.BlockMapRecord; @@ -63,20 +63,24 @@ function WalletDB(options) { this.logger = this.options.logger; this.client = this.options.client; this.db = LDB(this.options); + this.rpc = new RPC(this); this.primary = null; + this.http = null; - this.http = new HTTP({ - walletdb: this, - network: this.network, - logger: this.logger, - prefix: this.options.prefix, - apiKey: this.options.apiKey, - walletAuth: this.options.walletAuth, - noAuth: this.options.noAuth, - host: this.options.host, - port: this.options.port, - ssl: this.options.ssl - }); + if (!HTTPServer.unsupported) { + this.http = new HTTPServer({ + walletdb: this, + network: this.network, + logger: this.logger, + prefix: this.options.prefix, + apiKey: this.options.apiKey, + walletAuth: this.options.walletAuth, + noAuth: this.options.noAuth, + host: this.options.host, + port: this.options.port, + ssl: this.options.ssl + }); + } this.state = new ChainState(); this.wallets = Object.create(null); @@ -98,54 +102,6 @@ function WalletDB(options) { util.inherits(WalletDB, AsyncObject); -/** - * Plugin name. - * @const {String} - */ - -WalletDB.id = 'walletdb'; - -/** - * Plugin initialization. - * @param {Node} node - * @returns {WalletDB} - */ - -WalletDB.init = function init(node) { - var config = node.config; - var client = new NodeClient(node); - var wdb; - - wdb = new WalletDB({ - network: node.network, - logger: node.logger, - client: client, - prefix: config.prefix, - db: config.str(['wallet-db', 'db']), - maxFiles: config.num('wallet-max-files'), - cacheSize: config.mb('wallet-cache-size'), - witness: config.bool('wallet-witness'), - checkpoints: config.bool('wallet-checkpoints'), - startHeight: config.num('wallet-start-height'), - wipeNoReally: config.bool('wallet-wipe-no-really'), - apiKey: config.str(['wallet-api-key', 'api-key']), - walletAuth: config.bool('wallet-auth'), - noAuth: config.bool(['wallet-no-auth', 'no-auth']), - ssl: config.str('wallet-ssl'), - host: config.str('wallet-host'), - port: config.num('wallet-port'), - spv: node.spv, - verify: node.spv - }); - - if (node.http) { - wdb.http.attach(node.http); - wdb.http.rpc.attach(node.http.rpc); - } - - return wdb; -}; - /** * Database layout. * @type {Object} @@ -205,11 +161,14 @@ WalletDB.prototype._open = co(function* open() { }); this.logger.info( - 'Loaded wallet with id=%s wid=%d address=%s', + 'Loaded primary wallet (id=%s, wid=%d, address=%s)', wallet.id, wallet.wid, wallet.getAddress()); this.primary = wallet; - this.http.rpc.wallet = wallet; + this.rpc.wallet = wallet; + + if (this.http && this.options.listen) + yield this.http.open(); }); /** @@ -224,6 +183,9 @@ WalletDB.prototype._close = co(function* close() { yield this.disconnect(); + if (this.http && this.options.listen) + yield this.http.close(); + for (i = 0; i < keys.length; i++) { key = keys[i]; wallet = this.wallets[key]; @@ -2271,6 +2233,7 @@ function WalletOptions(options) { this.ssl = false; this.host = '127.0.0.1'; this.port = this.network.rpcPort + 2; + this.listen = false; if (options) this.fromOptions(options); @@ -2387,6 +2350,11 @@ WalletOptions.prototype.fromOptions = function fromOptions(options) { this.port = options.port; } + if (options.listen != null) { + assert(typeof options.listen === 'boolean'); + this.listen = options.listen; + } + return this; }; diff --git a/package.json b/package.json index 6db26570..9939c609 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,9 @@ "./lib/utils/nfkd": "./lib/utils/nfkd-browser.js", "./lib/utils/nexttick": "./lib/utils/nexttick-browser.js", "./lib/utils/lazy": "./lib/utils/lazy-browser.js", + "./lib/wallet/http": "./browser/empty.js", "./lib/wallet/layout": "./lib/wallet/layout-browser.js", + "./lib/wallet/server": "./browser/empty.js", "bcoin-native": "./browser/empty.js", "child_process": "./browser/empty.js", "crypto": "./browser/empty.js", diff --git a/test/node-test.js b/test/node-test.js index 64e3b4a4..3f34e083 100644 --- a/test/node-test.js +++ b/test/node-test.js @@ -15,7 +15,7 @@ describe('Node', function() { apiKey: 'foo', network: 'regtest', loader: require, - plugins: ['../lib/wallet/walletdb'] + plugins: ['../lib/wallet/plugin'] }); var chain = node.chain; var walletdb = node.require('walletdb');