From 59e22dc69c9c90d1855eb613d4a52ffd46c9da9c Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Mon, 2 Oct 2023 17:41:48 +0400 Subject: [PATCH] test: move node utils to nodeContext and rename nodeContext to NodesContext. --- test/auction-rpc-test.js | 142 +++--------- test/chain-reset-reorg-test.js | 164 +++++++------- test/mempool-invalidation-test.js | 64 +++--- test/node-http-test.js | 191 ++++++---------- test/util/chain.js | 23 +- test/util/node.js | 213 ++++++++++++++++++ .../{node-context.js => nodes-context.js} | 4 +- 7 files changed, 460 insertions(+), 341 deletions(-) create mode 100644 test/util/node.js rename test/util/{node-context.js => nodes-context.js} (97%) diff --git a/test/auction-rpc-test.js b/test/auction-rpc-test.js index 6e27efda..e479e5e3 100644 --- a/test/auction-rpc-test.js +++ b/test/auction-rpc-test.js @@ -2,111 +2,55 @@ const assert = require('bsert'); const bio = require('bufio'); -const plugin = require('../lib/wallet/plugin'); const rules = require('../lib/covenants/rules'); const common = require('./util/common'); const { ChainEntry, - FullNode, - SPVNode, KeyRing, MTX, Network, Path } = require('..'); -const {NodeClient, WalletClient} = require('../lib/client'); const {forValue} = require('./util/common'); +const NodeContext = require('./util/node'); class TestUtil { - constructor(options) { - if (!options) - options = Object.create(null); - - if (!options.host) - options.host = '127.0.0.1'; - - if (!options.nport) - options.nport = 14037; - - if (!options.wport) - options.wport = 14039; - - this.network = Network.get('regtest'); - - this.txs = {}; - - this.blocks = {}; - - this.node = new FullNode({ + constructor() { + this.nodeCtx = new NodeContext({ memory: true, workers: true, - network: this.network.type, listen: true, - bip37: true + bip37: true, + wallet: true }); + this.network = this.nodeCtx.network; + this.txs = {}; + this.blocks = {}; - this.node.use(plugin); - - this.nclient = new NodeClient({ - timeout: 15000, - host: options.host, - port: options.nport - }); - - this.wclient = new WalletClient({ - host: options.host, - port: options.wport - }); + this.node = this.nodeCtx.node; } - /** - * Execute an RPC using the wallet client. - * @param {String} method - RPC method - * @param {Array} params - method parameters - * @returns {Promise} - Returns a two item array with the RPC's return value - * or null as the first item and an error or null as the second item. - */ - - async wrpc(method, params = []) { - return this.wclient.execute(method, params) - .then(data => data) - .catch((err) => { - throw new Error(err); - }); + get nclient() { + return this.nodeCtx.nclient; } - /** - * Execute an RPC using the node client. - * @param {String} method - RPC method - * @param {Array} params - method parameters - * @returns {Promise} - Returns a two item array with the - * RPC's return value or null as the first item and an error or - * null as the second item. - */ - - async nrpc(method, params = []) { - return this.nclient.execute(method, params) - .then(data => data) - .catch((err) => { - throw new Error(err); - }); + get wclient() { + return this.nodeCtx.wclient; } - /** - * Open the util and all its child objects. - */ + wrpc(method, params = []) { + return this.nodeCtx.wrpc(method, params); + } + + nrpc(method, params = []) { + return this.nodeCtx.nrpc(method, params); + } async open() { assert(!this.opened, 'TestUtil is already open.'); this.opened = true; - await this.node.ensure(); - await this.node.open(); - await this.node.connect(); - this.node.startSync(); - - await this.nclient.open(); - await this.wclient.open(); + await this.nodeCtx.open(); this.node.plugins.walletdb.wdb.on('confirmed', ((details, tx) => { const txid = tx.txid(); @@ -125,17 +69,8 @@ class TestUtil { }); } - /** - * Close util and all its child objects. - */ - async close() { - assert(this.opened, 'TestUtil is not open.'); - this.opened = false; - - await this.nclient.close(); - await this.wclient.close(); - await this.node.close(); + await this.nodeCtx.close(); } async confirmTX(txid, timeout = 5000) { @@ -480,43 +415,34 @@ describe('Auction RPCs', function() { }); describe('SPV', function () { - const spvNode = new SPVNode({ - memory: true, - network: 'regtest', + const spvCtx = new NodeContext({ port: 10000, brontidePort: 20000, httpPort: 30000, only: '127.0.0.1', - noDns: true - }); + noDns: true, - const spvClient = new NodeClient({ - port: 30000 + spv: true }); before(async () => { await util.node.connect(); - await spvNode.open(); - await spvNode.connect(); - await spvNode.startSync(); + await spvCtx.open(); - await forValue(spvNode.chain, 'height', util.node.chain.height); - - await spvClient.open(); + await forValue(spvCtx.chain, 'height', util.node.chain.height); }); after(async () => { - await spvClient.close(); - await spvNode.close(); + await spvCtx.close(); }); it('should not get current namestate', async () => { - const {info} = await spvClient.execute('getnameinfo', [name]); + const {info} = await spvCtx.nrpc('getnameinfo', [name]); assert.strictEqual(info, null); }); it('should get historcial namestate at safe height', async () => { - const {info} = await spvClient.execute('getnameinfo', [name, true]); + const {info} = await spvCtx.nrpc('getnameinfo', [name, true]); assert.strictEqual(info.name, name); assert.strictEqual(info.state, 'CLOSED'); assert.strictEqual(info.value, loserBid.bid * COIN); @@ -524,12 +450,12 @@ describe('Auction RPCs', function() { }); it('should not get current resource', async () => { - const json = await spvClient.execute('getnameresource', [name]); + const json = await spvCtx.nrpc('getnameresource', [name]); assert.strictEqual(json, null); }); it('should get historcial resource at safe height', async () => { - const json = await spvClient.execute('getnameresource', [name, true]); + const json = await spvCtx.nrpc('getnameresource', [name, true]); assert.deepStrictEqual( json, { @@ -546,7 +472,7 @@ describe('Auction RPCs', function() { it('should not verifymessagewithname', async () => { // No local Urkel tree, namestate is always null await assert.rejects( - spvClient.execute('verifymessagewithname', [name, signSig, signMsg]), + spvCtx.nrpc('verifymessagewithname', [name, signSig, signMsg]), {message: /Cannot find the name owner/} ); }); @@ -555,7 +481,7 @@ describe('Auction RPCs', function() { // This time we do have a valid namestate to work with, but // SPV nodes still don't have a UTXO set to get addresses from await assert.rejects( - spvClient.execute('verifymessagewithname', [name, signSig, signMsg, true]), + spvCtx.nrpc('verifymessagewithname', [name, signSig, signMsg, true]), {message: /Cannot find the owner's address/} ); }); diff --git a/test/chain-reset-reorg-test.js b/test/chain-reset-reorg-test.js index 0dfb93e0..132c9fbf 100644 --- a/test/chain-reset-reorg-test.js +++ b/test/chain-reset-reorg-test.js @@ -9,16 +9,16 @@ const { openChainBundle, closeChainBundle, syncChain, - chainTreeHas, - chainTxnHas + chainTreeHasName, + chainTxnHasName } = require('./util/chain'); const network = Network.get('regtest'); describe('Chain reorg/reset test', function() { let wallet; - let chainb1, chain, mainMiner; - let chainb2, altChain, altMiner; + let chainBundle1, chain, mainMiner; + let chainBundle2, altChain, altMiner; let tipHeight = 0; const mineBlocksOpens = async (miner, n) => { @@ -58,38 +58,38 @@ describe('Chain reorg/reset test', function() { wallet = new MemWallet({ network }); - chainb1 = getChainBundle({ + chainBundle1 = getChainBundle({ memory: true, workers: true, address: wallet.getReceive() }); - chainb2 = getChainBundle({ + chainBundle2 = getChainBundle({ memory: true, workers: true, address: wallet.getReceive() }); - chainb1.chain.on('connect', (entry, block) => { + chainBundle1.chain.on('connect', (entry, block) => { wallet.addBlock(entry, block.txs); }); - chainb1.chain.on('disconnect', (entry, block) => { + chainBundle1.chain.on('disconnect', (entry, block) => { wallet.removeBlock(entry, block.txs); }); - await openChainBundle(chainb1); - await openChainBundle(chainb2); + await openChainBundle(chainBundle1); + await openChainBundle(chainBundle2); - chain = chainb1.chain; - mainMiner = chainb1.miner; - altChain = chainb2.chain; - altMiner = chainb2.miner; + chain = chainBundle1.chain; + mainMiner = chainBundle1.miner; + altChain = chainBundle2.chain; + altMiner = chainBundle2.miner; }; const afterHook = async () => { - await closeChainBundle(chainb1); - await closeChainBundle(chainb2); + await closeChainBundle(chainBundle1); + await closeChainBundle(chainBundle2); }; describe('Chain reorg', function() { @@ -124,8 +124,8 @@ describe('Chain reorg/reset test', function() { tipHeight++; for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } const root = await chain.db.treeRoot(); @@ -136,8 +136,8 @@ describe('Chain reorg/reset test', function() { assert.bufferEqual(chain.db.treeRoot(), root); for (const name of [...names0, ...names1]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } // mine 3 blocks on alt chain @@ -148,14 +148,14 @@ describe('Chain reorg/reset test', function() { assert.bufferEqual(chain.db.treeRoot(), root); for (const name of [...names0, ...names2]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } // these got reorged. for (const name of names1) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } assert.strictEqual(chain.tip.height, tipHeight); @@ -167,13 +167,13 @@ describe('Chain reorg/reset test', function() { tipHeight++; for (const name of [...names0, ...names2, ...names3]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of names1) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } assert.notBufferEqual(chain.db.treeRoot(), root); @@ -195,8 +195,8 @@ describe('Chain reorg/reset test', function() { tipHeight += 3; for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } assert.notBufferEqual(chain.db.txn.rootHash(), root); @@ -208,30 +208,30 @@ describe('Chain reorg/reset test', function() { assert.strictEqual(chain.tip.height, tipHeight + 3); for (const name of [...names0, ...names1.slice(0, -1)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } - assert.strictEqual(await chainTreeHas(chain, names1[names1.length - 1]), false); - assert.strictEqual(await chainTxnHas(chain, names1[names1.length - 1]), true); + assert.strictEqual(await chainTreeHasName(chain, names1[names1.length - 1]), false); + assert.strictEqual(await chainTxnHasName(chain, names1[names1.length - 1]), true); const names2 = await mineBlocksOpens(altMiner, 4); await syncChain(altChain, chain, tipHeight); tipHeight += 4; for (const name of [...names0, ...names2.slice(0, -2)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of [...names2.slice(-2)]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of names1) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } }); @@ -244,13 +244,13 @@ describe('Chain reorg/reset test', function() { assert.strictEqual(chain.tip.height, tipHeight + 15); for (const name of [...names1.slice(0, -2)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of [...names1.slice(-2)]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } // mine 16 on alt chain. @@ -262,18 +262,18 @@ describe('Chain reorg/reset test', function() { assert.strictEqual(chain.tip.height, tipHeight); for (const name of [...names2.slice(0, -3)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of [...names2.slice(-3)]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of names1) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } }); }); @@ -313,8 +313,8 @@ describe('Chain reorg/reset test', function() { tipHeight += 2; for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } const root = await chain.db.treeRoot(); @@ -327,26 +327,26 @@ describe('Chain reorg/reset test', function() { assert.bufferEqual(chain.db.treeRoot(), root); for (const name of [...names0, ...resetNames]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } await chain.reset(tipHeight - 2); for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of resetNames) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } await syncChain(altChain, chain, tipHeight - 2); for (const name of [...names0, ...resetNames]) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } }); @@ -358,8 +358,8 @@ describe('Chain reorg/reset test', function() { tipHeight += 3; for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } const resetNames = await mineBlocksOpens(mainMiner, 3); @@ -367,34 +367,34 @@ describe('Chain reorg/reset test', function() { tipHeight += 3; for (const name of [...names0, ...resetNames.slice(0, -1)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } const txnName = resetNames[resetNames.length - 1]; - assert.strictEqual(await chainTreeHas(chain, txnName), false); - assert.strictEqual(await chainTxnHas(chain, txnName), true); + assert.strictEqual(await chainTreeHasName(chain, txnName), false); + assert.strictEqual(await chainTxnHasName(chain, txnName), true); await chain.reset(tipHeight - 3); for (const name of names0) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of resetNames) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), false); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), false); } await syncChain(altChain, chain, tipHeight - 3); for (const name of [...names0, ...resetNames.slice(0, -1)]) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } - assert.strictEqual(await chainTreeHas(chain, txnName), false); - assert.strictEqual(await chainTxnHas(chain, txnName), true); + assert.strictEqual(await chainTreeHasName(chain, txnName), false); + assert.strictEqual(await chainTxnHasName(chain, txnName), true); }); it('should mine 18 blocks, reset and resync', async () => { @@ -411,13 +411,13 @@ describe('Chain reorg/reset test', function() { const txnNames = names.slice(-3); for (const name of treeNames) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of txnNames) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } await chain.reset(tipHeight - 18); @@ -427,13 +427,13 @@ describe('Chain reorg/reset test', function() { assert.strictEqual(altChain.tip.height, tipHeight); for (const name of treeNames) { - assert.strictEqual(await chainTreeHas(chain, name), true); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), true); + assert.strictEqual(await chainTxnHasName(chain, name), true); } for (const name of txnNames) { - assert.strictEqual(await chainTreeHas(chain, name), false); - assert.strictEqual(await chainTxnHas(chain, name), true); + assert.strictEqual(await chainTreeHasName(chain, name), false); + assert.strictEqual(await chainTxnHasName(chain, name), true); } }); }); diff --git a/test/mempool-invalidation-test.js b/test/mempool-invalidation-test.js index e146af70..fa4e302b 100644 --- a/test/mempool-invalidation-test.js +++ b/test/mempool-invalidation-test.js @@ -3,13 +3,13 @@ const assert = require('bsert'); const {BufferMap} = require('buffer-map'); const Network = require('../lib/protocol/network'); -const FullNode = require('../lib/node/fullnode'); const {ownership} = require('../lib/covenants/ownership'); const rules = require('../lib/covenants/rules'); const {states} = require('../lib/covenants/namestate'); const {Resource} = require('../lib/dns/resource'); const {forEvent} = require('./util/common'); const {CachedStubResolver} = require('./util/stub'); +const NodeContext = require('./util/node'); const network = Network.get('regtest'); const { @@ -48,40 +48,41 @@ describe('Mempool Invalidation', function() { describe('Covenant invalidation (Integration)', function() { this.timeout(3000); + let nodeCtx; let node, wallet, wallet2; const getNameState = async (name) => { - const ns = await node.chain.db.getNameStateByName(name); + const ns = await nodeCtx.chain.db.getNameStateByName(name); if (!ns) return null; - return ns.state(node.chain.tip.height + 1, network); + return ns.state(nodeCtx.chain.tip.height + 1, network); }; const isExpired = async (name) => { - const ns = await node.chain.db.getNameStateByName(name); + const ns = await nodeCtx.chain.db.getNameStateByName(name); if (!ns) return true; - return ns.isExpired(node.chain.tip.height + 1, network); + return ns.isExpired(nodeCtx.chain.tip.height + 1, network); }; before(async () => { network.names.renewalWindow = 200; - node = new FullNode({ + nodeCtx = new NodeContext({ + network: 'regtest', memory: true, - network: network.type, - plugins: [require('../lib/wallet/plugin')] + wallet: true }); - await node.ensure(); - await node.open(); + await nodeCtx.open(); - const walletPlugin = node.require('walletdb'); - const wdb = walletPlugin.wdb; + node = nodeCtx.node; + + const wdb = nodeCtx.wdb; wallet = await wdb.get('primary'); wallet2 = await wdb.create({ id: 'secondary' @@ -93,7 +94,7 @@ describe('Mempool Invalidation', function() { for (let i = 0; i < treeInterval; i++) await mineBlock(node); - const fundTX = forEvent(node.mempool, 'tx', 1, 2000); + const fundTX = forEvent(nodeCtx.mempool, 'tx', 1, 2000); const w2addr = (await wallet2.receiveAddress('default')).toString(); await wallet.send({ @@ -115,7 +116,8 @@ describe('Mempool Invalidation', function() { after(async () => { network.names.renewalWindow = ACTUAL_RENEWAL_WINDOW; - await node.close(); + await nodeCtx.close(); + await nodeCtx.destroy(); }); it('should invalidate opens', async () => { @@ -341,26 +343,26 @@ describe('Mempool Invalidation', function() { describe('Claim Invalidation (Integration)', function() { this.timeout(50000); + let nodeCtx; let node, wallet; // copy names const TEST_CLAIMS = NAMES.slice(); before(async () => { - node = new FullNode({ - memory: true, + nodeCtx = new NodeContext({ network: network.type, - plugins: [require('../lib/wallet/plugin')] + memory: true, + wallet: true }); - await node.ensure(); - await node.open(); + await nodeCtx.open(); + node = nodeCtx.node; // Ignore claim validation ownership.ignore = true; - const walletPlugin = node.require('walletdb'); - const wdb = walletPlugin.wdb; + const wdb = nodeCtx.wdb; wallet = await wdb.get('primary'); const addr = await wallet.receiveAddress('default'); @@ -376,7 +378,8 @@ describe('Mempool Invalidation', function() { after(async () => { network.names.claimPeriod = ACTUAL_CLAIM_PERIOD; - await node.close(); + await nodeCtx.close(); + await nodeCtx.destroy(); }); it('should mine an interval', async () => { @@ -444,26 +447,26 @@ describe('Mempool Invalidation', function() { describe('Claim Invalidation on reorg (Integration)', function() { this.timeout(50000); + let nodeCtx; let node, wallet; // copy names const TEST_CLAIMS = NAMES.slice(); before(async () => { - node = new FullNode({ - memory: true, + nodeCtx = new NodeContext({ network: network.type, - plugins: [require('../lib/wallet/plugin')] + memory: true, + wallet: true }); - await node.ensure(); - await node.open(); + await nodeCtx.open(); // Ignore claim validation ownership.ignore = true; - const walletPlugin = node.require('walletdb'); - const wdb = walletPlugin.wdb; + node = nodeCtx.node; + const wdb = nodeCtx.wdb; wallet = await wdb.get('primary'); const addr = await wallet.receiveAddress('default'); @@ -479,7 +482,8 @@ describe('Mempool Invalidation', function() { after(async () => { network.names.claimPeriod = ACTUAL_CLAIM_PERIOD; - await node.close(); + await nodeCtx.close(); + await nodeCtx.destroy(); }); it('should mine an interval', async () => { diff --git a/test/node-http-test.js b/test/node-http-test.js index 148ecc2f..60b16e5f 100644 --- a/test/node-http-test.js +++ b/test/node-http-test.js @@ -2,7 +2,6 @@ const assert = require('bsert'); const bio = require('bufio'); -const NodeClient = require('../lib/client/node'); const Network = require('../lib/protocol/network'); const FullNode = require('../lib/node/fullnode'); const SPVNode = require('../lib/node/spvnode'); @@ -16,40 +15,32 @@ const Coin = require('../lib/primitives/coin'); const MTX = require('../lib/primitives/mtx'); const rules = require('../lib/covenants/rules'); const common = require('./util/common'); +const NodeContext = require('./util/node'); const mnemonics = require('./data/mnemonic-english.json'); -const {forEvent} = common; + // Commonly used test mnemonic const phrase = mnemonics[0][1]; describe('Node HTTP', function() { describe('Chain info', function() { - const network = Network.get('regtest'); - const nclient = new NodeClient({ - port: network.rpcPort - }); - - let node; + let nodeCtx; afterEach(async () => { - if (node && node.opened) { - const close = forEvent(node, 'close'); - await node.close(); - await close; - } + if (nodeCtx && nodeCtx.opened) + await nodeCtx.close(); - node = null; + nodeCtx = null; }); it('should get full node chain info', async () => { - node = new FullNode({ - network: network.type + nodeCtx = new NodeContext({ + network: 'regtest' }); - await node.open(); - - const {chain} = await nclient.getInfo(); + await nodeCtx.open(); + const {chain} = await nodeCtx.nclient.getInfo(); assert.strictEqual(chain.height, 0); - assert.strictEqual(chain.tip, network.genesis.hash.toString('hex')); + assert.strictEqual(chain.tip, nodeCtx.network.genesis.hash.toString('hex')); assert.strictEqual(chain.treeRoot, Buffer.alloc(32, 0).toString('hex')); assert.strictEqual(chain.progress, 0); assert.strictEqual(chain.indexers.indexTX, false); @@ -64,41 +55,40 @@ describe('Node HTTP', function() { }); it('should get fullnode chain info with indexers', async () => { - node = new FullNode({ - network: network.type, + nodeCtx = new NodeContext({ + network: 'regtest', indexAddress: true, indexTX: true }); - await node.open(); - - const {chain} = await nclient.getInfo(); + await nodeCtx.open(); + const {chain} = await nodeCtx.nclient.getInfo(); assert.strictEqual(chain.indexers.indexTX, true); assert.strictEqual(chain.indexers.indexAddress, true); }); it('should get fullnode chain info with pruning', async () => { - node = new FullNode({ - network: network.type, + nodeCtx = new NodeContext({ + network: 'regtest', prune: true }); - await node.open(); + await nodeCtx.open(); - const {chain} = await nclient.getInfo(); + const {chain} = await nodeCtx.nclient.getInfo(); assert.strictEqual(chain.options.prune, true); }); it('should get fullnode chain info with compact', async () => { - node = new FullNode({ - network: network.type, + nodeCtx = new NodeContext({ + network: 'regtest', compactTreeOnInit: true, compactTreeInitInterval: 20000 }); - await node.open(); + await nodeCtx.open(); - const {chain} = await nclient.getInfo(); + const {chain} = await nodeCtx.nclient.getInfo(); assert.strictEqual(chain.treeCompaction.compacted, false); assert.strictEqual(chain.treeCompaction.compactOnInit, true); assert.strictEqual(chain.treeCompaction.compactInterval, 20000); @@ -109,24 +99,29 @@ describe('Node HTTP', function() { }); it('should get spv node chain info', async () => { - node = new SPVNode({ - network: network.type + nodeCtx = new NodeContext({ + network: 'regtest', + spv: true }); - await node.open(); + await nodeCtx.open(); - const {chain} = await nclient.getInfo(); + const {chain} = await nodeCtx.nclient.getInfo(); assert.strictEqual(chain.options.spv, true); }); it('should get next tree update height', async () => { const someAddr = 'rs1q7q3h4chglps004u3yn79z0cp9ed24rfrhvrxnx'; - node = new FullNode({ - network: network.type + nodeCtx = new NodeContext({ + network: 'regtest' }); - const interval = network.names.treeInterval; - await node.open(); + const interval = nodeCtx.network.names.treeInterval; + + await nodeCtx.open(); + + const nclient = nodeCtx.nclient; + const node = nodeCtx.node; { // 0th block will be 0. @@ -164,24 +159,15 @@ describe('Node HTTP', function() { describe('Networking info', function() { it('should not have public address: regtest', async () => { - const network = Network.get('regtest'); + const nodeCtx = new NodeContext(); - const node = new FullNode({ - network: network.type - }); - - const nclient = new NodeClient({ - port: network.rpcPort - }); - - await node.open(); - await node.connect(); - const {pool} = await nclient.getInfo(); - await node.close(); + await nodeCtx.open(); + const {pool} = await nodeCtx.nclient.getInfo(); + await nodeCtx.close(); assert.strictEqual(pool.host, '0.0.0.0'); - assert.strictEqual(pool.port, network.port); - assert.strictEqual(pool.brontidePort, network.brontidePort); + assert.strictEqual(pool.port, nodeCtx.network.port); + assert.strictEqual(pool.brontidePort, nodeCtx.network.brontidePort); const {public: pub} = pool; @@ -194,19 +180,13 @@ describe('Node HTTP', function() { it('should not have public address: regtest, listen', async () => { const network = Network.get('regtest'); - const node = new FullNode({ - network: network.type, + const nodeCtx = new NodeContext({ listen: true }); - const nclient = new NodeClient({ - port: network.rpcPort - }); - - await node.open(); - await node.connect(); - const {pool} = await nclient.getInfo(); - await node.close(); + await nodeCtx.open(); + const {pool} = await nodeCtx.nclient.getInfo(); + await nodeCtx.close(); assert.strictEqual(pool.host, '0.0.0.0'); assert.strictEqual(pool.port, network.port); @@ -221,20 +201,15 @@ describe('Node HTTP', function() { }); it('should not have public address: main', async () => { - const network = Network.get('main'); - - const node = new FullNode({ - network: network.type + const nodeCtx = new NodeContext({ + network: 'main' }); - const nclient = new NodeClient({ - port: network.rpcPort - }); + const network = nodeCtx.network; - await node.open(); - await node.connect(); - const {pool} = await nclient.getInfo(); - await node.close(); + await nodeCtx.open(); + const {pool} = await nodeCtx.nclient.getInfo(); + await nodeCtx.close(); assert.strictEqual(pool.host, '0.0.0.0'); assert.strictEqual(pool.port, network.port); @@ -249,21 +224,16 @@ describe('Node HTTP', function() { }); it('should not have public address: main, listen', async () => { - const network = Network.get('main'); - - const node = new FullNode({ - network: network.type, + const nodeCtx = new NodeContext({ + network: 'main', listen: true }); - const nclient = new NodeClient({ - port: network.rpcPort - }); + const network = nodeCtx.network; - await node.open(); - await node.connect(); - const {pool} = await nclient.getInfo(); - await node.close(); + await nodeCtx.open(); + const {pool} = await nodeCtx.nclient.getInfo(); + await nodeCtx.close(); assert.strictEqual(pool.host, '0.0.0.0'); assert.strictEqual(pool.port, network.port); @@ -278,27 +248,23 @@ describe('Node HTTP', function() { }); it('should have public address: main, listen, publicHost', async () => { - const network = Network.get('main'); const publicHost = '100.200.11.22'; const publicPort = 11111; const publicBrontidePort = 22222; - const node = new FullNode({ - network: network.type, + const nodeCtx = new NodeContext({ + network: 'main', listen: true, publicHost, publicPort, publicBrontidePort }); - const nclient = new NodeClient({ - port: network.rpcPort - }); + const network = nodeCtx.network; - await node.open(); - await node.connect(); - const {pool} = await nclient.getInfo(); - await node.close(); + await nodeCtx.open(); + const {pool} = await nodeCtx.nclient.getInfo(); + await nodeCtx.close(); assert.strictEqual(pool.host, '0.0.0.0'); assert.strictEqual(pool.port, network.port); @@ -317,25 +283,18 @@ describe('Node HTTP', function() { this.timeout(15000); describe('tree commit', () => { - const network = Network.get('regtest'); const {types} = rules; - const node = new FullNode({ - network: 'regtest', + const nodeCtx = new NodeContext({ apiKey: 'foo', - walletAuth: true, - memory: true, indexTx: true, indexAddress: true, rejectAbsurdFees: false }); - - const nclient = new NodeClient({ - port: network.rpcPort, - apiKey: 'foo' - }); + const network = nodeCtx.network; const {treeInterval} = network.names; + const nclient = nodeCtx.nclient; let privkey, pubkey; let socketData, mempoolData; @@ -345,7 +304,7 @@ describe('Node HTTP', function() { async function mineBlocks(count, address) { for (let i = 0; i < count; i++) { const obj = { complete: false }; - node.once('block', () => { + nodeCtx.node.once('block', () => { obj.complete = true; }); await nclient.execute('generatetoaddress', [1, address]); @@ -354,8 +313,7 @@ describe('Node HTTP', function() { } before(async () => { - await node.open(); - await nclient.open(); + await nodeCtx.open(); await nclient.call('watch chain'); const mnemonic = Mnemonic.fromPhrase(phrase); @@ -379,14 +337,13 @@ describe('Node HTTP', function() { socketData.push({root, entry, block}); }); - node.mempool.on('tx', (tx) => { + nodeCtx.mempool.on('tx', (tx) => { mempoolData[tx.txid()] = true; }); }); after(async () => { - await nclient.close(); - await node.close(); + await nodeCtx.close(); }); beforeEach(() => { @@ -423,7 +380,7 @@ describe('Node HTTP', function() { coins.sort((a, b) => a.height - b.height); const coin = Coin.fromJSON(coins[0]); - assert.ok(node.chain.height > coin.height + network.coinbaseMaturity); + assert.ok(nodeCtx.chain.height > coin.height + network.coinbaseMaturity); mtx.addCoin(coin); const addr = Address.fromPubkey(pubkey); @@ -436,7 +393,7 @@ describe('Node HTTP', function() { assert.ok(valid); const tx = mtx.toTX(); - await node.sendTX(tx); + await nodeCtx.node.sendTX(tx); await common.forValue(mempoolData, tx.txid(), true); @@ -449,7 +406,7 @@ describe('Node HTTP', function() { assert.equal(socketData.length, 1); const {root, block, entry} = socketData[0]; - assert.bufferEqual(node.chain.db.treeRoot(), root); + assert.bufferEqual(nodeCtx.chain.db.treeRoot(), root); const info = await nclient.getInfo(); assert.notEqual(pre.chain.tip, info.chain.tip); diff --git a/test/util/chain.js b/test/util/chain.js index 6e338d36..36c1bcde 100644 --- a/test/util/chain.js +++ b/test/util/chain.js @@ -116,13 +116,32 @@ chainUtils.syncChain = async (fromChain, toChain, startHeight) => { return endHeight - startHeight; }; -chainUtils.chainTreeHas = async (chain, name) => { +chainUtils.mineBlock = async (chainObj, mtxs) => { + const tip = chainObj.chain.tip; + const job = await chainObj.miner.createJob(tip); + + if (mtxs) { + for (const mtx of mtxs) { + const [tx, view] = mtx.commit(); + + job.addTX(tx, view); + } + } + + job.refresh(); + + const block = await job.mineAsync(); + const entry = await chainObj.chain.add(block); + return { block, entry }; +}; + +chainUtils.chainTreeHasName = async (chain, name) => { assert(!chain.options.spv); const hash = rules.hashName(name); return await chain.db.tree.get(hash) != null; }; -chainUtils.chainTxnHas = async (chain, name) => { +chainUtils.chainTxnHasName = async (chain, name) => { assert(!chain.options.spv); const hash = rules.hashName(name); return await chain.db.txn.get(hash) != null; diff --git a/test/util/node.js b/test/util/node.js new file mode 100644 index 00000000..62ce93bf --- /dev/null +++ b/test/util/node.js @@ -0,0 +1,213 @@ +'use strict'; + +const assert = require('bsert'); +const common = require('./common'); +const fs = require('bfile'); +const SPVNode = require('../../lib/node/spvnode'); +const FullNode = require('../../lib/node/fullnode'); +const plugin = require('../../lib/wallet/plugin'); +const Network = require('../../lib/protocol/network'); +const {NodeClient, WalletClient} = require('../../lib/client'); + +class NodeContext { + constructor(options = {}) { + this.name = 'node-test'; + this.options = {}; + this.node = null; + this.opened = false; + + this.nclient = null; + this.wclient = null; + + this.fromOptions(options); + } + + fromOptions(options) { + const fnodeOptions = { + ...options, + memory: true, + workers: true, + network: 'regtest', + listen: false, + wallet: false, + spv: false + }; + + if (options.network != null) + fnodeOptions.network = Network.get(options.network).type; + + if (options.name != null) + fnodeOptions.name = options.name; + + if (options.listen != null) { + assert(typeof options.listen === 'boolean'); + fnodeOptions.listen = options.listen; + } + + if (options.prefix != null) { + fnodeOptions.prefix = this.prefix; + fnodeOptions.memory = false; + } + + if (options.memory != null) { + assert(!fnodeOptions.prefix, 'Can not set prefix with memory.'); + fnodeOptions.memory = options.memory; + } + + if (!this.memory && !this.prefix) + fnodeOptions.prefix = common.testdir(this.name); + + if (options.wallet != null) + fnodeOptions.wallet = options.wallet; + + if (options.apiKey != null) { + assert(typeof options.apiKey === 'string'); + fnodeOptions.apiKey = options.apiKey; + } + + if (options.spv != null) { + assert(typeof options.spv === 'boolean'); + fnodeOptions.spv = options.spv; + } + + if (options.httpPort != null) { + assert(typeof options.httpPort === 'number'); + fnodeOptions.httpPort = options.httpPort; + } + + if (options.indexTX != null) { + assert(typeof options.indexTX === 'boolean'); + fnodeOptions.indexTX = options.indexTX; + } + + if (options.indexAddress != null) { + assert(typeof options.indexAddress === 'boolean'); + fnodeOptions.indexAddress = options.indexAddress; + } + + if (options.prune != null) { + assert(typeof options.prune === 'boolean'); + fnodeOptions.prune = options.prune; + } + + if (options.compactOnInit != null) { + assert(typeof options.compactOnInit === 'boolean'); + fnodeOptions.compactOnInit = options.compactOnInit; + } + + if (options.compactTreeInitInterval != null) { + assert(typeof options.compactTreeInitInterval === 'number'); + fnodeOptions.compactTreeInitInterval = options.compactTreeInitInterval; + } + + if (fnodeOptions.spv) + this.node = new SPVNode(fnodeOptions); + else + this.node = new FullNode(fnodeOptions); + + if (options.timeout != null) + fnodeOptions.timeout = options.timeout; + + if (fnodeOptions.wallet) + this.node.use(plugin); + + this.nclient = new NodeClient({ + timeout: fnodeOptions.timeout, + apiKey: fnodeOptions.apiKey, + port: fnodeOptions.httpPort || this.node.network.rpcPort + }); + + if (fnodeOptions.wallet) { + this.wclient = new WalletClient({ + timeout: fnodeOptions.timeout, + port: this.node.network.walletPort + }); + } + + this.options = fnodeOptions; + } + + get network() { + return this.node.network; + } + + get miner() { + return this.node.miner; + } + + get mempool() { + return this.node.mempool; + } + + get chain() { + return this.node.chain; + } + + get wdb() { + return this.node.get('walletdb').wdb; + } + + async open() { + if (this.prefix) + await fs.mkdirp(this.prefix); + + await this.node.ensure(); + await this.node.open(); + await this.node.connect(); + this.node.startSync(); + + if (this.wclient) + await this.wclient.open(); + + await this.nclient.open(); + + this.opened = true; + } + + async close() { + if (!this.opened) + return; + + if (this.wclient) + await this.wclient.close(); + await this.nclient.close(); + + const close = common.forEvent(this.node, 'close'); + await this.node.close(); + await close; + + this.opened = false; + } + + async destroy() { + if (this.prefix) + await fs.rimraf(this.prefix); + } + + /** + * Execute an RPC using the node client. + * @param {String} method - RPC method + * @param {Array} params - method parameters + * @returns {Promise} - Returns a two item array with the + * RPC's return value or null as the first item and an error or + * null as the second item. + */ + + async nrpc(method, params) { + return this.nclient.execute(method, params); + } + + /** + * Execute an RPC using the wallet client. + * @param {String} method - RPC method + * @param {Array} params - method parameters + * @returns {Promise} - Returns a two item array with the RPC's return value + * or null as the first item and an error or null as the second item. + */ + + async wrpc(method, params) { + return this.wclient.execute(method, params); + }; +} + +module.exports = NodeContext; diff --git a/test/util/node-context.js b/test/util/nodes-context.js similarity index 97% rename from test/util/node-context.js rename to test/util/nodes-context.js index 76a1d97a..1de3b98a 100644 --- a/test/util/node-context.js +++ b/test/util/nodes-context.js @@ -5,7 +5,7 @@ const FullNode = require('../../lib/node/fullnode'); const Network = require('../../lib/protocol/network'); const Logger = require('blgr'); -class NodeContext { +class NodesContext { constructor(network, size) { this.network = Network.get(network); this.size = size || 4; @@ -120,4 +120,4 @@ class NodeContext { } } -module.exports = NodeContext; +module.exports = NodesContext;