Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify ports / public ports in node HTTP getinfo #696

Merged
merged 7 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## unreleased

### Node changes
### Node API changes

- HTTP API endpoint `/` (`hsd-cli getinfo`) now includes "public" networking settings.

- RPCs `getnameinfo` `getnameresource` `verifymessagewithname` and `getnamebyhash`
now accept an additional boolean parameter `safe` which will resolve the name from the Urkel
Expand All @@ -14,11 +16,12 @@ to these calls.
- `decoderesource` like `decodescript` accepts hex string as input and returns
JSON formatted DNS records resource.

### Wallet changes
### Wallet API changes

- New RPC methods:
- `createbatch` and `sendbatch` create batch transactions with any number
of outputs with any combination of covenants.

## v4.0.0

**When upgrading to this version of hsd you must pass
Expand Down
6 changes: 6 additions & 0 deletions lib/net/hostlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,12 @@ class HostList {

if (!src) {
for (const dest of this.local.values()) {
if (this.network.type === 'main') {
// Disable everything else for now.
if (dest.type < HostList.scores.UPNP)
continue;
}

if (dest.addr.hasKey())
continue;

Expand Down
28 changes: 19 additions & 9 deletions lib/node/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,20 @@ class HTTP extends Server {
const orphans = this.mempool ? this.mempool.orphans.size : 0;
const brontide = this.pool.hosts.brontide;

let addr = this.pool.hosts.getLocal();

if (!addr)
addr = this.pool.hosts.address;
const pub = {
listen: this.pool.options.listen,
host: null,
port: null,
brontidePort: null
};

const addr = this.pool.hosts.getLocal();

if (addr && pub.listen) {
pub.host = addr.host;
pub.port = addr.port;
pub.brontidePort = brontide.port;
}

res.json(200, {
version: pkg.version,
Expand All @@ -138,15 +148,15 @@ class HTTP extends Server {
}
},
pool: {
host: addr.host,
port: addr.port,
brontideHost: brontide.host,
brontidePort: brontide.port,
host: this.pool.options.host,
port: this.pool.options.port,
brontidePort: this.pool.options.brontidePort,
identitykey: brontide.getKey('base32'),
agent: this.pool.options.agent,
services: this.pool.options.services.toString(2),
outbound: this.pool.peers.outbound,
inbound: this.pool.peers.inbound
inbound: this.pool.peers.inbound,
public: pub
},
mempool: {
tx: totalTX,
Expand Down
273 changes: 214 additions & 59 deletions test/node-http-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,73 +19,239 @@ const mnemonics = require('./data/mnemonic-english.json');
// Commonly used test mnemonic
const phrase = mnemonics[0][1];

const network = Network.get('regtest');
const {types} = rules;

const node = new FullNode({
network: 'regtest',
apiKey: 'foo',
walletAuth: true,
memory: true,
indexTx: true,
indexAddress: true,
rejectAbsurdFees: false
});
describe('Node HTTP', function() {
describe('Networking info', function() {
it('should not have public address: regtest', async () => {
const network = Network.get('regtest');

const nclient = new NodeClient({
port: network.rpcPort,
apiKey: 'foo'
});
const node = new FullNode({
network: network.type
});

let cbAddress, privkey, pubkey;
let socketData, mempoolData;
const nclient = new NodeClient({
port: network.rpcPort
});

const {treeInterval} = network.names;
await node.open();
await node.connect();
const {pool} = await nclient.getInfo();
await node.close();

describe('Node HTTP', function() {
this.timeout(15000);
assert.strictEqual(pool.host, '0.0.0.0');
assert.strictEqual(pool.port, network.port);
assert.strictEqual(pool.brontidePort, network.brontidePort);

const {public: pub} = pool;

before(async () => {
await node.open();
await nclient.open();
await nclient.call('watch chain');
assert.strictEqual(pub.listen, false);
assert.strictEqual(pub.host, null);
assert.strictEqual(pub.port, null);
assert.strictEqual(pub.brontidePort, null);
});

it('should not have public address: regtest, listen', async () => {
const network = Network.get('regtest');

const mnemonic = Mnemonic.fromPhrase(phrase);
const priv = HDPrivateKey.fromMnemonic(mnemonic);
const type = network.keyPrefix.coinType;
const key = priv.derive(44, true).derive(type, true).derive(0, true);
const xkey = key.derive(0).derive(0);
const node = new FullNode({
network: network.type,
listen: true
});

pubkey = xkey.publicKey;
privkey = xkey.privateKey;
const nclient = new NodeClient({
port: network.rpcPort
});

cbAddress = Address.fromPubkey(pubkey).toString(network.type);
await node.open();
await node.connect();
const {pool} = await nclient.getInfo();
await node.close();

nclient.bind('tree commit', (root, entry, block) => {
assert.ok(root);
assert.ok(block);
assert.ok(entry);
assert.strictEqual(pool.host, '0.0.0.0');
assert.strictEqual(pool.port, network.port);
assert.strictEqual(pool.brontidePort, network.brontidePort);

socketData.push({root, entry, block});
const {public: pub} = pool;

assert.strictEqual(pub.listen, true);
assert.strictEqual(pub.host, null); // we don't discover from external
assert.strictEqual(pub.port, null);
assert.strictEqual(pub.brontidePort, null);
});

node.mempool.on('tx', (tx) => {
mempoolData[tx.txid()] = true;
it('should not have public address: main', async () => {
const network = Network.get('main');

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

assert.strictEqual(pool.host, '0.0.0.0');
assert.strictEqual(pool.port, network.port);
assert.strictEqual(pool.brontidePort, network.brontidePort);

const {public: pub} = pool;

assert.strictEqual(pub.listen, false);
assert.strictEqual(pub.host, null);
assert.strictEqual(pub.port, null);
assert.strictEqual(pub.brontidePort, null);
});
});

beforeEach(() => {
socketData = [];
mempoolData = {};
});
it('should not have public address: main, listen', async () => {
const network = Network.get('main');

const node = new FullNode({
network: network.type,
listen: true
});

const nclient = new NodeClient({
port: network.rpcPort
});

await node.open();
await node.connect();
const {pool} = await nclient.getInfo();
await node.close();

after(async () => {
await nclient.close();
await node.close();
assert.strictEqual(pool.host, '0.0.0.0');
assert.strictEqual(pool.port, network.port);
assert.strictEqual(pool.brontidePort, network.brontidePort);

const {public: pub} = pool;

assert.strictEqual(pub.listen, true);
assert.strictEqual(pub.host, null);
assert.strictEqual(pub.port, null);
assert.strictEqual(pub.brontidePort, null);
});

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,
listen: true,
publicHost,
publicPort,
publicBrontidePort
});

const nclient = new NodeClient({
port: network.rpcPort
});

await node.open();
await node.connect();
const {pool} = await nclient.getInfo();
await node.close();

assert.strictEqual(pool.host, '0.0.0.0');
assert.strictEqual(pool.port, network.port);
assert.strictEqual(pool.brontidePort, network.brontidePort);

const {public: pub} = pool;

assert.strictEqual(pub.listen, true);
assert.strictEqual(pub.host, publicHost);
assert.strictEqual(pub.port, publicPort);
assert.strictEqual(pub.brontidePort, publicBrontidePort);
});
});

describe('Websockets', function () {
this.timeout(15000);

describe('tree commit', () => {
const network = Network.get('regtest');
const {types} = rules;

const node = new FullNode({
network: 'regtest',
apiKey: 'foo',
walletAuth: true,
memory: true,
indexTx: true,
indexAddress: true,
rejectAbsurdFees: false
});

const nclient = new NodeClient({
port: network.rpcPort,
apiKey: 'foo'
});

const {treeInterval} = network.names;

let privkey, pubkey;
let socketData, mempoolData;
let cbAddress;

// take into account race conditions
async function mineBlocks(count, address) {
for (let i = 0; i < count; i++) {
const obj = { complete: false };
node.once('block', () => {
obj.complete = true;
});
await nclient.execute('generatetoaddress', [1, address]);
await common.forValue(obj, 'complete', true);
}
}

before(async () => {
await node.open();
await nclient.open();
await nclient.call('watch chain');

const mnemonic = Mnemonic.fromPhrase(phrase);
const priv = HDPrivateKey.fromMnemonic(mnemonic);
const type = network.keyPrefix.coinType;
const key = priv.derive(44, true).derive(type, true).derive(0, true);
const xkey = key.derive(0).derive(0);

socketData = [];
mempoolData = {};
pubkey = xkey.publicKey;
privkey = xkey.privateKey;

cbAddress = Address.fromPubkey(pubkey).toString(network.type);

nclient.bind('tree commit', (root, entry, block) => {
assert.ok(root);
assert.ok(block);
assert.ok(entry);

socketData.push({root, entry, block});
});

node.mempool.on('tx', (tx) => {
mempoolData[tx.txid()] = true;
});
});

after(async () => {
await nclient.close();
await node.close();
});

beforeEach(() => {
socketData = [];
mempoolData = {};
});

it('should mine 1 tree interval', async () => {
await mineBlocks(treeInterval, cbAddress);
assert.equal(socketData.length, 1);
Expand Down Expand Up @@ -153,14 +319,3 @@ describe('Node HTTP', function() {
});
});

// take into account race conditions
async function mineBlocks(count, address) {
for (let i = 0; i < count; i++) {
const obj = { complete: false };
node.once('block', () => {
obj.complete = true;
});
await nclient.execute('generatetoaddress', [1, address]);
await common.forValue(obj, 'complete', true);
}
}
Loading