test: move node utils to nodeContext and rename nodeContext to NodesContext.

This commit is contained in:
Nodari Chkuaselidze 2023-10-02 17:41:48 +04:00
parent 349d203b58
commit 59e22dc69c
No known key found for this signature in database
GPG key ID: B018A7BB437D1F05
7 changed files with 460 additions and 341 deletions

View file

@ -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<Array>} - 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/}
);
});

View file

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

View file

@ -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 () => {

View file

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

View file

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

213
test/util/node.js Normal file
View file

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

View file

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