test: add standalone wallet to the NodeContext.
This commit is contained in:
parent
106fbfaacf
commit
e5bcf23f91
6 changed files with 200 additions and 55 deletions
|
|
@ -23,6 +23,9 @@ class TestUtil {
|
|||
bip37: true,
|
||||
wallet: true
|
||||
});
|
||||
|
||||
this.nodeCtx.init();
|
||||
|
||||
this.network = this.nodeCtx.network;
|
||||
this.txs = {};
|
||||
this.blocks = {};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue