diff --git a/test/auction-rpc-test.js b/test/auction-rpc-test.js index 9a809298..d5574265 100644 --- a/test/auction-rpc-test.js +++ b/test/auction-rpc-test.js @@ -23,6 +23,9 @@ class TestUtil { bip37: true, wallet: true }); + + this.nodeCtx.init(); + this.network = this.nodeCtx.network; this.txs = {}; this.blocks = {}; diff --git a/test/node-http-test.js b/test/node-http-test.js index 0bf8c16b..1fbcca6e 100644 --- a/test/node-http-test.js +++ b/test/node-http-test.js @@ -28,9 +28,9 @@ describe('Node HTTP', function() { beforeEach(async () => { nodeCtx = new NodeContext(); - nclient = nodeCtx.nclient; await nodeCtx.open(); + nclient = nodeCtx.nclient; }); afterEach(async () => { @@ -74,9 +74,8 @@ describe('Node HTTP', function() { beforeEach(async () => { nodeCtx = new NodeContext(); - nclient = nodeCtx.nclient; - await nodeCtx.open(); + nclient = nodeCtx.nclient; }); afterEach(async () => { @@ -261,9 +260,8 @@ describe('Node HTTP', function() { network: 'regtest' }); - const interval = nodeCtx.network.names.treeInterval; - await nodeCtx.open(); + const interval = nodeCtx.network.names.treeInterval; const nclient = nodeCtx.nclient; const node = nodeCtx.node; @@ -315,9 +313,9 @@ describe('Node HTTP', function() { network: 'regtest' }); + await nodeCtx.open(); const {network, nclient} = nodeCtx; - await nodeCtx.open(); const {pool} = await nclient.getInfo(); assert.strictEqual(pool.host, '0.0.0.0'); @@ -337,9 +335,9 @@ describe('Node HTTP', function() { network: 'regtest', listen: true }); - const {network, nclient} = nodeCtx; await nodeCtx.open(); + const {network, nclient} = nodeCtx; const {pool} = await nclient.getInfo(); assert.strictEqual(pool.host, '0.0.0.0'); @@ -359,9 +357,9 @@ describe('Node HTTP', function() { network: 'main' }); + await nodeCtx.open(); const {network, nclient} = nodeCtx; - await nodeCtx.open(); const {pool} = await nclient.getInfo(); assert.strictEqual(pool.host, '0.0.0.0'); @@ -382,9 +380,9 @@ describe('Node HTTP', function() { listen: true }); + await nodeCtx.open(); const {network, nclient} = nodeCtx; - await nodeCtx.open(); const {pool} = await nclient.getInfo(); assert.strictEqual(pool.host, '0.0.0.0'); @@ -412,9 +410,9 @@ describe('Node HTTP', function() { publicBrontidePort }); + await nodeCtx.open(); const {network, nclient} = nodeCtx; - await nodeCtx.open(); const {pool} = await nclient.getInfo(); assert.strictEqual(pool.host, '0.0.0.0'); @@ -443,6 +441,8 @@ describe('Node HTTP', function() { rejectAbsurdFees: false }); + nodeCtx.init(); + const {network, nclient} = nodeCtx; const {treeInterval} = network.names; diff --git a/test/node-rescan-test.js b/test/node-rescan-test.js index c651a3e5..3d6fca10 100644 --- a/test/node-rescan-test.js +++ b/test/node-rescan-test.js @@ -66,11 +66,10 @@ describe('Node Rescan Interactive API', function() { before(async () => { nodeCtx = new NodeContext(); - const {network} = nodeCtx; - - funderWallet = new MemWallet({ network }); await nodeCtx.open(); + const {network} = nodeCtx; + funderWallet = new MemWallet({ network }); nodeCtx.on('connect', (entry, block) => { funderWallet.addBlock(entry, block.txs); diff --git a/test/node-rpc-test.js b/test/node-rpc-test.js index 0b142801..9701d439 100644 --- a/test/node-rpc-test.js +++ b/test/node-rpc-test.js @@ -37,6 +37,7 @@ describe('RPC', function() { describe('getblockchaininfo', function() { const nodeCtx = new NodeContext(nodeOptions); + nodeCtx.init(); const nclient = nodeCtx.nclient; before(async () => { @@ -58,6 +59,7 @@ describe('RPC', function() { describe('getrawmempool', function() { const nodeCtx = new NodeContext(nodeOptions); + nodeCtx.init(); const nclient = nodeCtx.nclient; before(async () => { @@ -83,10 +85,9 @@ describe('RPC', function() { name: 'node-rpc-test' }); + await nodeCtx.open(); nclient = nodeCtx.nclient; node = nodeCtx.node; - - await nodeCtx.open(); }); after(async () => { @@ -221,6 +222,7 @@ describe('RPC', function() { ...nodeOptions, spv: true }); + await nodeCtx.open(); await assert.rejects(async () => { @@ -265,7 +267,6 @@ describe('RPC', function() { // default - prune: false nodeCtx = new NodeContext(nodeOptions); await nodeCtx.open(); - const {miner, nclient} = nodeCtx; const addr = 'rs1q4rvs9pp9496qawp2zyqpz3s90fjfk362q92vq8'; @@ -320,6 +321,7 @@ describe('RPC', function() { describe('mining', function() { const nodeCtx = new NodeContext(nodeOptions); + nodeCtx.init(); const { miner, chain, @@ -505,6 +507,7 @@ describe('RPC', function() { ...nodeOptions, indexTX: true }); + nodeCtx.init(); const { miner, @@ -588,6 +591,7 @@ describe('RPC', function() { describe('networking', function() { const nodeCtx = new NodeContext({ ...nodeOptions, bip37: true }); + nodeCtx.init(); const nclient = nodeCtx.nclient; before(async () => { @@ -607,6 +611,7 @@ describe('RPC', function() { describe('DNS Utility', function() { const nodeCtx = new NodeContext(nodeOptions); + nodeCtx.init(); const nclient = nodeCtx.nclient; before(async () => { @@ -762,6 +767,8 @@ describe('RPC', function() { wallet: true }); + nodeCtx.init(); + const { node, nclient, diff --git a/test/util/node-context.js b/test/util/node-context.js index c0a49db1..aa2efd3e 100644 --- a/test/util/node-context.js +++ b/test/util/node-context.js @@ -3,10 +3,11 @@ const assert = require('bsert'); const common = require('./common'); const fs = require('bfile'); +const Network = require('../../lib/protocol/network'); const SPVNode = require('../../lib/node/spvnode'); const FullNode = require('../../lib/node/fullnode'); +const WalletNode = require('../../lib/wallet/node'); const plugin = require('../../lib/wallet/plugin'); -const Network = require('../../lib/protocol/network'); const {NodeClient, WalletClient} = require('../../lib/client'); const Logger = require('blgr'); @@ -23,7 +24,7 @@ class NodeContext { constructor(options = {}) { this.name = 'node-test'; this.options = {}; - this.node = null; + this.prefix = null; this.opened = false; this.logger = new Logger({ console: true, @@ -31,13 +32,15 @@ class NodeContext { level: 'none' }); + this.initted = false; + this.node = null; + this.walletNode = null; this.nclient = null; this.wclient = null; this.clients = []; this.fromOptions(options); - this.init(); } fromOptions(options) { @@ -54,6 +57,11 @@ class NodeContext { walletHttpPort: null }; + if (options.name != null) { + assert(typeof options.name === 'string'); + this.name = options.name; + } + if (options.network != null) fnodeOptions.network = Network.get(options.network).type; @@ -66,17 +74,23 @@ class NodeContext { } if (options.prefix != null) { - fnodeOptions.prefix = this.prefix; + fnodeOptions.prefix = options.prefix; fnodeOptions.memory = false; + this.prefix = fnodeOptions.prefix; } if (options.memory != null) { - assert(!fnodeOptions.prefix, 'Can not set prefix with memory.'); + assert(typeof options.memory === 'boolean'); + assert(!(options.memory && options.prefix), + 'Can not set prefix with memory.'); + fnodeOptions.memory = options.memory; } - if (!this.memory && !this.prefix) + if (!fnodeOptions.memory && !fnodeOptions.prefix) { fnodeOptions.prefix = common.testdir(this.name); + this.prefix = fnodeOptions.prefix; + } if (options.wallet != null) fnodeOptions.wallet = options.wallet; @@ -101,23 +115,45 @@ class NodeContext { fnodeOptions.timeout = options.timeout; } + if (options.standalone != null) { + assert(typeof options.standalone === 'boolean'); + fnodeOptions.standalone = options.standalone; + } + this.options = fnodeOptions; } init() { + if (this.initted) + return; + if (this.options.spv) this.node = new SPVNode(this.options); else this.node = new FullNode(this.options); - if (this.options.wallet) + if (this.options.wallet && !this.options.standalone) { this.node.use(plugin); + } else if (this.options.wallet && this.options.standalone) { + this.walletNode = new WalletNode({ + ...this.options, + + nodeHost: '127.0.0.1', + nodePort: this.options.httpPort, + nodeApiKey: this.options.apiKey, + + httpPort: this.options.walletHttpPort, + apiKey: this.options.apiKey + }); + } // Initial wallets. this.nclient = this.nodeClient(); if (this.options.wallet) this.wclient = this.walletClient(); + + this.initted = true; } get network() { @@ -145,6 +181,12 @@ class NodeContext { } get wdb() { + if (!this.options.wallet) + return null; + + if (this.walletNode) + return this.walletNode.wdb; + return this.node.get('walletdb').wdb; } @@ -177,16 +219,26 @@ class NodeContext { */ async open() { + this.init(); + if (this.opened) return; if (this.prefix) await fs.mkdirp(this.prefix); + const open = common.forEvent(this.node, 'open'); await this.node.ensure(); await this.node.open(); await this.node.connect(); this.node.startSync(); + await open; + + if (this.walletNode) { + const walletOpen = common.forEvent(this.walletNode, 'open'); + await this.walletNode.open(); + await walletOpen; + } if (this.wclient) await this.wclient.open(); @@ -200,7 +252,6 @@ class NodeContext { if (!this.opened) return; - const close = common.forEvent(this.node, 'close'); const closeClients = []; for (const client of this.clients) { @@ -209,10 +260,22 @@ class NodeContext { } await Promise.all(closeClients); + + if (this.walletNode) { + const walletClose = common.forEvent(this.walletNode, 'close'); + await this.walletNode.close(); + await walletClose; + } + + const close = common.forEvent(this.node, 'close'); await this.node.close(); await close; + this.node = null; + this.wclient = null; + this.nclient = null; this.opened = false; + this.initted = false; } async destroy() { @@ -224,8 +287,8 @@ class NodeContext { * Helpers */ - enableLogging() { - this.logger.setLevel('debug'); + enableLogging(level = 'debug') { + this.logger.setLevel(level); } disableLogging() { @@ -299,17 +362,20 @@ class NodeContext { * Mine blocks and wait for connect. * @param {Number} count * @param {Address} address + * @param {ChainEntry} [tip=chain.tip] - Tip to mine on * @returns {Promise} - Block hashes */ - async mineBlocks(count, address) { + async mineBlocks(count, address, tip) { assert(this.open); - const blockEvents = common.forEvent(this.node, 'block', count); - const hashes = await this.nodeRPC.generateToAddress([count, address]); - await blockEvents; + if (!tip) + tip = this.chain.tip; - return hashes; + for (let i = 0; i < count; i++) { + const block = await this.miner.mineBlock(tip, address); + tip = await this.chain.add(block); + } } } diff --git a/test/util/nodes-context.js b/test/util/nodes-context.js index 0be0f325..221b8820 100644 --- a/test/util/nodes-context.js +++ b/test/util/nodes-context.js @@ -19,7 +19,7 @@ class NodesContext { } addNode(options = {}) { - const index = this.nodeCtxs.length; + const index = this.nodeCtxs.length + 1; let seedPort = this.network.port + index - 1; @@ -30,17 +30,21 @@ class NodesContext { const brontidePort = this.network.brontidePort + index; const httpPort = this.network.rpcPort + index + 100; const walletHttpPort = this.network.walletPort + index + 200; + const nsPort = this.network.nsPort + index; + const rsPort = this.network.rsPort + index + 100; const nodeCtx = new NodeContext({ + listen: true, + ...options, // override name: `node-${index}`, network: this.network, - listen: true, - publicHost: '127.0.0.1', - publicPort: port, + port: port, brontidePort: brontidePort, + rsPort: rsPort, + nsPort: nsPort, httpPort: httpPort, walletHttpPort: walletHttpPort, seeds: [ @@ -49,9 +53,19 @@ class NodesContext { }); this.nodeCtxs.push(nodeCtx); + return nodeCtx; } - open() { + /** + * Open all or specific nodes. + * @param {Number} [index=-1] default all + * @returns {Promise} + */ + + open(index = -1) { + if (index !== -1) + return this.context(index).open(); + const jobs = []; for (const nodeCtx of this.nodeCtxs) @@ -60,7 +74,16 @@ class NodesContext { return Promise.all(jobs); } - close() { + /** + * Close all or specific nodes. + * @param {Number} [index=-1] default all + * @returns {Promise} + */ + + close(index = -1) { + if (index !== -1) + return this.context(index).close(); + const jobs = []; for (const nodeCtx of this.nodeCtxs) @@ -69,21 +92,52 @@ class NodesContext { return Promise.all(jobs); } + /** + * Destroy specific or all nodes. Clean up directories on the disk. + * @param {Number} [index=-1] default all + * @returns {Promise} + */ + + destroy(index = -1) { + if (index !== -1) + return this.context(index).destroy(); + + const jobs = []; + + for (const nodeCtx of this.nodeCtxs) + jobs.push(nodeCtx.destroy()); + + return Promise.all(jobs); + } + + /** + * Connect all nodes. + * @returns {Promise} + */ + async connect() { for (const nodeCtx of this.nodeCtxs) { await nodeCtx.node.connect(); - await new Promise(r => setTimeout(r, 1000)); + await nodeCtx.node.startSync(); } } + /** + * Disconnect all nodes. + * @returns {Promise} + */ + async disconnect() { for (let i = this.nodeCtxs.length - 1; i >= 0; i--) { - const node = this.nodeCtxs[i]; + const node = this.nodeCtxs[i].node; await node.disconnect(); - await new Promise(r => setTimeout(r, 1000)); } } + /** + * Start syncing. + */ + startSync() { for (const nodeCtx of this.nodeCtxs) { nodeCtx.chain.synced = true; @@ -92,32 +146,48 @@ class NodesContext { } } + /** + * Stop syncing. + */ + stopSync() { for (const nodeCtx of this.nodeCtxs) nodeCtx.stopSync(); } - async generate(index, blocks) { - const nodeCtx = this.nodeCtxs[index]; + /** + * Mine blocks. + * @param {Number} index + * @param {Number} blocks + * @param {String} address + * @param {ChainEntry} [tip=chain.tip] + * @returns {Promise} + */ - assert(nodeCtx); - - for (let i = 0; i < blocks; i++) { - const block = await nodeCtx.miner.mineBlock(); - await nodeCtx.chain.add(block); - } + async generate(index, blocks, address, tip) { + return this.context(index).mineBlocks(blocks, address, tip); } + /** + * Get NodeCtx for the node. + * @param {Number} index + * @returns {NodeContext} + */ + context(index) { - const node = this.nodeCtxs[index]; - assert(node); - return node; - } - - height(index) { const nodeCtx = this.nodeCtxs[index]; assert(nodeCtx); - return nodeCtx.height; + return nodeCtx; + } + + /** + * Get height for the node. + * @param {Number} index + * @returns {Number} + */ + + height(index) { + return this.context(index).height; } }