Skip to content

Commit

Permalink
dns: use chain.safeEntry tiemstamp for SOA serial
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Sep 14, 2022
1 parent c7ffc46 commit cf2b26f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
3 changes: 2 additions & 1 deletion lib/dns/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,8 @@ class RootServer extends DNSServer {
}

serial() {
const date = new Date();
const time = this.chain.safeEntry ? this.chain.safeEntry.time : 0;
const date = new Date(time * 1000);
const y = date.getUTCFullYear() * 1e6;
const m = (date.getUTCMonth() + 1) * 1e4;
const d = date.getUTCDate() * 1e2;
Expand Down
75 changes: 70 additions & 5 deletions test/dns-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const assert = require('bsert');
const {hashName} = require('../lib/covenants/rules');
const NameState = require('../lib/covenants/namestate');
const Network = require('../lib/protocol/network');
const FullNode = require('../lib/node/fullnode');
const SPVNode = require('../lib/node/spvnode');
Expand All @@ -19,7 +21,8 @@ recursiveResolver.setServers([`127.0.0.1:${network.rsPort}`]);
const {
treeInterval,
biddingPeriod,
revealPeriod
revealPeriod,
safeRoot
} = network.names;

describe('DNS Servers', function() {
Expand Down Expand Up @@ -111,13 +114,15 @@ describe('DNS Servers', function() {

async function mineBlocks(n) {
for (; n > 0; n--) {
// force ten minute block intervals
node.network.time.offset += 60 * 10;
const block = await miner.miner.mineBlock();
await miner.chain.add(block);
}
await forValue(node.chain, 'height', miner.chain.height);
}

let name;
let name, nameHash, serial;
const string = 'Campaign of chaos';
const resource = Resource.fromJSON({
records: [{type: 'TXT', txt: [string]}]
Expand All @@ -136,6 +141,7 @@ describe('DNS Servers', function() {
await forValue(node.pool.peers.list, 'size', 1);

name = await miner.rpc.grindName([4]);
nameHash = hashName(name);

miner.miner.addresses.length = 0;
miner.miner.addAddress(wallet.getReceive());
Expand All @@ -148,20 +154,74 @@ describe('DNS Servers', function() {
});

it('should refuse to resolve before chain sync', async () => {
assert.strictEqual(node.chain.getProgress(), 0);
await assert.rejects(
rootResolver.resolveTxt(name),
{message: `queryTxt EREFUSED ${name}`}
);
});

it('should not refuse to resolve after chain sync', async () => {
it('should resolve root SOA before chain sync', async () => {
const res = await rootResolver.resolveSoa('.');
// null UNIX timestamp because there is no safe root yet
assert.strictEqual(res.serial, 1970010100);
});

it('should still refuse to resolve after chain sync', async () => {
// On mainnet, a synced chain would have a safe root,
// but on regtest we are "synced" after the first block,
// which is not enough confirmations yet to resolve.
await mineBlocks(2);
assert.strictEqual(node.chain.getProgress(), 1);
await assert.rejects(
rootResolver.resolveTxt(name),
{message: `queryTxt EREFUSED ${name}`}
);
});

it('should not refuse to resolve after safe height', async () => {
await mineBlocks(node.chain.height % treeInterval);
await assert.rejects(
rootResolver.resolveTxt(name),
{message: `queryTxt ENOTFOUND ${name}`}
);
});

it('should resolve root SOA after safe height', async () => {
node.ns.resetCache();
const res = await rootResolver.resolveSoa('.');
// Block #1 timestamp because the latest tree commitment
// hasn't been confirmed enough times yet, so we drop back
// to the previous tree root commitment, which is genesis (#0),
// but new roots don't appear in headers until the next block.
const {time} = await miner.chain.getEntryByHeight(1);
const date = new Date(time * 1000);
const y = date.getUTCFullYear() * 1e6;
const m = (date.getUTCMonth() + 1) * 1e4;
const d = date.getUTCDate() * 1e2;
const h = date.getUTCHours();
const expected = y + m + d + h;
assert.strictEqual(res.serial, expected);
serial = res.serial;
});

it('should update SOA serial when tree interval is safe', async () => {
const startHeight = node.chain.height;
let newSerial = serial;
while (newSerial === serial) {
await mineBlocks(1);
node.ns.resetCache();
const res = await rootResolver.resolveSoa('.');
newSerial = res.serial;
}
const endHeight = node.chain.height;
assert(endHeight > startHeight);
assert.strictEqual(
endHeight % treeInterval,
safeRoot
);
});

it('should refuse to resolve invalid name', async () => {
await assert.rejects(
rootResolver.resolveTxt('com\\\\000'),
Expand All @@ -177,7 +237,7 @@ describe('DNS Servers', function() {
});

it('should fund wallet and win name', async () => {
await mineBlocks(20);
await mineBlocks(19);

await miner.mempool.addTX((await wallet.sendOpen(name)).toTX());
await mineBlocks(treeInterval + 1);
Expand All @@ -201,7 +261,7 @@ describe('DNS Servers', function() {
);
await mineBlocks(1);

// Sanity check
// Sanity check: name is registered
const ns = await miner.chain.db.getNameStateByName(name);
assert(ns);
assert.bufferEqual(ns.data, resource.encode());
Expand Down Expand Up @@ -241,6 +301,11 @@ describe('DNS Servers', function() {
rootResolver.resolveTxt(name),
{message: `queryTxt ENOTFOUND ${name}`}
);

// Sanity check: name is in tree
const raw = await miner.chain.db.lookup(commitRoot, nameHash);
const {data} = NameState.decode(raw);
assert.bufferEqual(data, resource.encode());
});

it('should resolve at safe height', async () => {
Expand Down

0 comments on commit cf2b26f

Please sign in to comment.