diff --git a/lib/node/http.js b/lib/node/http.js index 10fca6fcf..8e646783c 100644 --- a/lib/node/http.js +++ b/lib/node/http.js @@ -22,6 +22,7 @@ const Address = require('../primitives/address'); const Network = require('../protocol/network'); const pkg = require('../pkg'); const rules = require('../covenants/rules'); +const Resource = require('../dns/resource'); /** * HTTP @@ -421,7 +422,7 @@ class HTTP extends Server { const hash = valid.bhash('hash'); if (!hash) - throw new Error('Invalid parameter.'); + throw new Error('Invalid hash.'); const ns = await this.chain.db.getNameState(hash); @@ -430,6 +431,62 @@ class HTTP extends Server { return res.json(200, { name: ns.name.toString('binary') }); }); + + this.get('/resource/name/:name', async (req, res) => { + const valid = Validator.fromRequest(req); + const name = valid.str('name'); + + if (!name || !rules.verifyName(name)) + throw new Error('Invalid name.'); + + const nameHash = rules.hashName(name); + const ns = await this.chain.db.getNameState(nameHash); + + if (!ns || ns.data.length === 0) + return null; + + const resource = Resource.decode(ns.data); + + return res.json(200, resource.toJSON()); + }); + + this.get('/proof/name/:name', async (req, res) => { + const valid = Validator.fromRequest(req); + const name = valid.str('name'); + + if (!name || !rules.verifyName(name)) + throw new Error('Invalid name.'); + + const hash = this.chain.tip.hash; + const height = this.chain.tip.height; + const root = this.chain.tip.treeRoot; + const key = rules.hashName(name); + const proof = await this.chain.db.prove(root, key); + + return res.json(200, { + hash: hash.toString('hex'), + height: height, + root: root.toString('hex'), + name: name, + key: key.toString('hex'), + proof: proof.toJSON() + }); + }); + + this.get('/grind', async (req, res) => { + const valid = Validator.fromRequest(req); + const size = valid.u32('size'); + + if (size < 1 || size > 63) + throw new Error('Invalid length.'); + + const network = this.network; + const height = this.chain.height; + + const name = await rules.grindName(size, height + 1, network); + + res.json(200, { name }); + }); } /** diff --git a/package.json b/package.json index b39ca9929..dd7109dad 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "bval": "~0.1.6", "bweb": "~0.1.8", "goosig": "~0.1.0", - "hs-client": "file:/run/media/wiski/549A5F9E28D6FB4C/hs-client", + "hs-client": "~0.0.6", "mrmr": "~0.1.8", "n64": "~0.2.9", "urkel": "~0.6.3" diff --git a/test/node-http-test.js b/test/node-http-test.js index 8bb5ad148..d0ade94d9 100644 --- a/test/node-http-test.js +++ b/test/node-http-test.js @@ -4,16 +4,8 @@ 'use strict'; const assert = require('bsert'); -const consensus = require('../lib/protocol/consensus'); const Network = require('../lib/protocol/network'); -const Coin = require('../lib/primitives/coin'); -const Script = require('../lib/script/script'); -const Opcode = require('../lib/script/opcode'); const FullNode = require('../lib/node/fullnode'); -const Wallet = require('../lib/wallet/wallet'); -const MTX = require('../lib/primitives/mtx'); -const TX = require('../lib/primitives/tx'); -const Address = require('../lib/primitives/address'); const rules = require('../lib/covenants/rules'); const network = Network.get('regtest'); @@ -151,4 +143,77 @@ describe('Node http', function() { }); }); }); + + describe('getNameResource', () => { + const zonefile = { compat: false, version: 0, ttl: 172800, ns: ['ns1.example.com.@1.2.3.4'] }; + it('It should return null when an auction has not been initiated', async () => { + const resource = await nclient.getNameResource(NAME0); + assert.equal(resource, null); + }); + + describe('When an auction has been initiated', () => { + beforeEach(async () => { + await mineBlocks(250); + await wclient.execute('sendopen', [NAME0]); + // Question: We have to mine ~7 blocks here to get 'getauctioninfo' to work consistently. Will pass w. 4 + await mineBlocks(7); + const { stats: { blocksUntilBidding } } = await wclient.execute('getauctioninfo', [NAME0]); + await mineBlocks(blocksUntilBidding); + const sendBid = await wclient.execute('sendbid', [NAME0, 12, 12]); + assert(sendBid); + const { stats: { blocksUntilReveal } } = await wclient.execute('getauctioninfo', [NAME0]); + // Question: We have to mine ~2 blocks here to get 'sendreveal' to work consistently. Will pass w. 1. + await mineBlocks(blocksUntilReveal + 2); + await wclient.execute('sendreveal', [NAME0]); + const { stats: { blocksUntilClose } } = await wclient.execute('getauctioninfo', [NAME0]); + await mineBlocks(blocksUntilClose); + await wclient.execute('sendupdate', [NAME0, zonefile]); + await mineBlocks(1); + }); + it('It should return the resource', async () => { + const resource = await nclient.getNameResource(NAME0); + assert.deepEqual(resource, zonefile); + }); + }); + }); + + describe('getNameProof', () => { + it('It should return null when an auction has not been initiated', async () => { + const proof = await nclient.getNameProof(NAME0); + assert.equal(proof.proof.type, 'TYPE_DEADEND'); + assert.equal(proof.name, NAME0); + }); + + describe('When an auction has been initiated', () => { + beforeEach(async () => { + await mineBlocks(250); + await wclient.execute('sendopen', [NAME0]); + // Question: We have to mine ~7 blocks here to get 'getauctioninfo' to work consistently. Will pass w. 4 + await mineBlocks(7); + const { stats: { blocksUntilBidding } } = await wclient.execute('getauctioninfo', [NAME0]); + await mineBlocks(blocksUntilBidding); + const sendBid = await wclient.execute('sendbid', [NAME0, 12, 12]); + assert(sendBid); + const { stats: { blocksUntilReveal } } = await wclient.execute('getauctioninfo', [NAME0]); + // Question: We have to mine ~2 blocks here to get 'sendreveal' to work consistently. Will pass w. 1. + await mineBlocks(blocksUntilReveal + 2); + await wclient.execute('sendreveal', [NAME0]); + const { stats: { blocksUntilClose } } = await wclient.execute('getauctioninfo', [NAME0]); + await mineBlocks(blocksUntilClose); + await wclient.execute('sendupdate', [NAME0, { compat: false, version: 0, ttl: 172800, ns: ['ns1.example.com.@1.2.3.4'] }]); + await mineBlocks(1); + }); + it('It should return the name\'s proof', async () => { + const proof = await nclient.getNameProof(NAME0); + assert.equal(proof.proof.type, 'TYPE_EXISTS'); + assert.equal(proof.name, NAME0); + }); + }); + }); + describe('grindName', () => { + it('It should grind a name', async () => { + const { name } = await nclient.grindName(10); + assert(name); + }); + }); });