test: add standalone wallet to the NodeContext.

This commit is contained in:
Nodari Chkuaselidze 2023-12-27 11:46:59 +04:00
parent 106fbfaacf
commit e5bcf23f91
No known key found for this signature in database
GPG key ID: B018A7BB437D1F05
6 changed files with 200 additions and 55 deletions

View file

@ -23,6 +23,9 @@ class TestUtil {
bip37: true,
wallet: true
});
this.nodeCtx.init();
this.network = this.nodeCtx.network;
this.txs = {};
this.blocks = {};

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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<Buffer[]>} - 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);
}
}
}

View file

@ -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;
}
}