Skip to content

Commit 236adc2

Browse files
committed
Implement sendopen http interface for node. Requires updated hs-client lib to work
1 parent 28a3877 commit 236adc2

File tree

3 files changed

+202
-1
lines changed

3 files changed

+202
-1
lines changed

lib/node/http.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const Claim = require('../primitives/claim');
2121
const Address = require('../primitives/address');
2222
const Network = require('../protocol/network');
2323
const pkg = require('../pkg');
24+
const rules = require('../covenants/rules');
2425

2526
/**
2627
* HTTP
@@ -383,6 +384,52 @@ class HTTP extends Server {
383384

384385
res.json(200, { success: true });
385386
});
387+
388+
this.get('/info/name/:name', async (req, res) => {
389+
const valid = Validator.fromRequest(req);
390+
const name = valid.str('name');
391+
392+
if (!name || !rules.verifyName(name))
393+
throw new Error('Invalid parameter.');
394+
395+
const network = this.network;
396+
const height = this.chain.height;
397+
const nameHash = rules.hashName(name);
398+
const reserved = rules.isReserved(nameHash, height + 1, network);
399+
const [start, week] = rules.getRollout(nameHash, network);
400+
const ns = await this.chain.db.getNameState(nameHash);
401+
402+
let info = null;
403+
404+
if (ns) {
405+
if (!ns.isExpired(height, network))
406+
info = ns.getJSON(height, network);
407+
}
408+
409+
return res.json(200, {
410+
start: {
411+
reserved: reserved,
412+
week: week,
413+
start: start
414+
},
415+
info
416+
});
417+
});
418+
419+
this.get('/name/hash/:hash', async (req, res) => {
420+
const valid = Validator.fromRequest(req);
421+
const hash = valid.bhash('hash');
422+
423+
if (!hash)
424+
throw new Error('Invalid parameter.');
425+
426+
const ns = await this.chain.db.getNameState(hash);
427+
428+
if (!ns)
429+
return res.json(404);
430+
431+
return res.json(200, { name: ns.name.toString('binary') });
432+
});
386433
}
387434

388435
/**

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"bval": "~0.1.6",
4949
"bweb": "~0.1.8",
5050
"goosig": "~0.1.0",
51-
"hs-client": "~0.0.6",
51+
"hs-client": "file:/run/media/wiski/549A5F9E28D6FB4C/hs-client",
5252
"mrmr": "~0.1.8",
5353
"n64": "~0.2.9",
5454
"urkel": "~0.6.3"

test/node-http-test.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/* eslint-env mocha */
2+
/* eslint prefer-arrow-callback: 'off' */
3+
4+
'use strict';
5+
6+
const assert = require('bsert');
7+
const consensus = require('../lib/protocol/consensus');
8+
const Network = require('../lib/protocol/network');
9+
const Coin = require('../lib/primitives/coin');
10+
const Script = require('../lib/script/script');
11+
const Opcode = require('../lib/script/opcode');
12+
const FullNode = require('../lib/node/fullnode');
13+
const Wallet = require('../lib/wallet/wallet');
14+
const MTX = require('../lib/primitives/mtx');
15+
const TX = require('../lib/primitives/tx');
16+
const Address = require('../lib/primitives/address');
17+
const rules = require('../lib/covenants/rules');
18+
const network = Network.get('regtest');
19+
20+
const { NodeClient, WalletClient } = require('hs-client');
21+
22+
const nclient = new NodeClient({
23+
port: network.rpcPort,
24+
apiKey: 'foo'
25+
});
26+
27+
const wclient = new WalletClient({
28+
port: network.walletPort,
29+
apiKey: 'foo'
30+
});
31+
32+
describe('Node http', function() {
33+
this.timeout(5000);
34+
let NAME0;
35+
let node;
36+
let miner;
37+
let chain;
38+
let NAME1;
39+
40+
const mineBlocks = async (n = 1) => {
41+
for (let i = 0; i < n; i++) {
42+
const block = await miner.mineBlock();
43+
await chain.add(block);
44+
}
45+
};
46+
47+
beforeEach(async () => {
48+
node = new FullNode({
49+
memory: true,
50+
apiKey: 'foo',
51+
network: 'regtest',
52+
workers: true,
53+
plugins: [require('../lib/wallet/plugin')]
54+
});
55+
miner = node.miner;
56+
chain = node.chain;
57+
NAME0 = await rules.grindName(10, 0, network);
58+
NAME1 = await rules.grindName(10, 20, network);
59+
await node.open();
60+
await mineBlocks(network.names.auctionStart);
61+
assert.equal(network.names.auctionStart, 0);
62+
await mineBlocks(1);
63+
});
64+
65+
afterEach(async () => {
66+
await node.close();
67+
});
68+
69+
describe('getNameInfo', () => {
70+
describe('For names that are available at height 0', () => {
71+
it('It should return null when there hasn\'t been an auction initiated', async () => {
72+
const nameInfo = await nclient.getNameInfo(NAME0);
73+
assert.deepEqual(nameInfo, {
74+
info: null,
75+
start: {
76+
reserved: false,
77+
start: 0,
78+
week: 0
79+
}
80+
});
81+
});
82+
it('It should start an auction on the first day', async () => {
83+
await mineBlocks(1);
84+
const nameInfo = await nclient.getNameInfo(NAME0);
85+
assert.deepEqual(nameInfo, {
86+
info: null,
87+
start: {
88+
reserved: false,
89+
start: 0,
90+
week: 0
91+
}
92+
});
93+
const open = await wclient.execute('sendopen', [NAME0]);
94+
assert(open);
95+
});
96+
it('It should start an auction on the 2nd day', async () => {
97+
// Question: This test passes non-deterministically. Why?
98+
// Note: Keeping this test as proof that the behavior of grindName
99+
// isnt working as one would expect.
100+
await mineBlocks(175); // Note: This number seems to pass consistently. \o.o/
101+
const nameInfo = await nclient.getNameInfo(NAME0);
102+
assert.deepEqual(nameInfo, {
103+
info: null,
104+
start: {
105+
reserved: false,
106+
start: 0,
107+
week: 0
108+
}
109+
});
110+
const open = await wclient.execute('sendopen', [NAME0]);
111+
assert(open);
112+
const nameInfoBefore = await nclient.getNameInfo(NAME0);
113+
assert.equal(nameInfoBefore.info, null);
114+
await mineBlocks(1);
115+
const nameInfoAfter = await nclient.getNameInfo(NAME0);
116+
assert.equal(nameInfoAfter.info.name, NAME0);
117+
assert.equal(nameInfoAfter.info.state, 'OPENING');
118+
});
119+
});
120+
121+
describe('For names that are available at height 20', () => {
122+
it('It should getNameInfo for an opening name', async () => {
123+
await mineBlocks(20);
124+
await wclient.execute('sendopen', [NAME1]);
125+
await mineBlocks(1);
126+
const nameInfo = await nclient.getNameInfo(NAME1);
127+
assert(nameInfo.start.start < 20);
128+
assert.equal(nameInfo.start.reserved, false);
129+
assert.equal(nameInfo.info.state, 'OPENING');
130+
});
131+
});
132+
});
133+
134+
describe('getNameByHash', () => {
135+
it('It should return null when an auction has not been initiated', async () => {
136+
const nameHash = rules.hashName(NAME0);
137+
const name = await nclient.getNameByHash(nameHash.toString('hex'));
138+
assert.equal(name, null);
139+
});
140+
141+
describe('When an auction has been initiated', () => {
142+
beforeEach(async () => {
143+
await mineBlocks(250);
144+
await wclient.execute('sendopen', [NAME0]);
145+
await mineBlocks(1);
146+
});
147+
it('It should return the name', async () => {
148+
const nameHash = rules.hashName(NAME0);
149+
const { name } = await nclient.getNameByHash(nameHash.toString('hex'));
150+
assert.equal(name, NAME0);
151+
});
152+
});
153+
});
154+
});

0 commit comments

Comments
 (0)