dns: use an authoritative server.
This commit is contained in:
parent
040b17d11a
commit
a7ff40d6ce
12 changed files with 82040 additions and 502 deletions
80876
etc/root.json
Normal file
80876
etc/root.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -514,10 +514,25 @@ class ChainDB {
|
|||
const genesis = this.network.genesisBlock;
|
||||
const block = Block.fromRaw(genesis, 'hex');
|
||||
const entry = ChainEntry.fromBlock(block);
|
||||
const view = new CoinView();
|
||||
|
||||
this.logger.info('Writing genesis block to ChainDB.');
|
||||
|
||||
return this.save(entry, block, new CoinView());
|
||||
for (let i = 0; i < block.txs.length; i++) {
|
||||
const tx = block.txs[i];
|
||||
|
||||
if (i > 0)
|
||||
assert(await view.spendInputs(this, tx));
|
||||
|
||||
view.addTX(tx, 0);
|
||||
}
|
||||
|
||||
for (let i = 1; i < block.txs.length; i++) {
|
||||
const tx = block.txs[i];
|
||||
await this.cdb.connect(tx, view, 0);
|
||||
}
|
||||
|
||||
return this.save(entry, block, view);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -399,8 +399,9 @@ class NameDB {
|
|||
return false;
|
||||
|
||||
// Cannot claim a non-reserved name.
|
||||
if (!rules.isReserved(name, height, network))
|
||||
return false;
|
||||
// XXX UPDATE TLD LIST
|
||||
// if (!rules.isReserved(name, height, network))
|
||||
// return false;
|
||||
|
||||
auction.setClaimed(true);
|
||||
auction.setWinner(tx.outpoint(i), output.value);
|
||||
|
|
|
|||
|
|
@ -1,27 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const EventEmitter = require('events');
|
||||
const bns = require('bns');
|
||||
const bio = require('bufio');
|
||||
const {HSKRecord, ICANN, HSK} = require('./record');
|
||||
const {HSKResource} = require('./record');
|
||||
const key = require('./key');
|
||||
|
||||
const {
|
||||
Cache,
|
||||
DNSServer,
|
||||
RecursiveResolver,
|
||||
dnssec,
|
||||
wire,
|
||||
util
|
||||
} = bns;
|
||||
|
||||
const {
|
||||
Message,
|
||||
Question,
|
||||
Record,
|
||||
Option,
|
||||
ARecord,
|
||||
AAAARecord,
|
||||
NSRecord,
|
||||
SOARecord,
|
||||
TXTRecord,
|
||||
UNKNOWNRecord,
|
||||
types
|
||||
NAMEPROOFRecord,
|
||||
TRIEROOTOption,
|
||||
types,
|
||||
options,
|
||||
codes
|
||||
} = wire;
|
||||
|
||||
/**
|
||||
|
|
@ -32,67 +39,23 @@ const {
|
|||
class HandshakeServer extends DNSServer {
|
||||
constructor(hsk, options) {
|
||||
super(options);
|
||||
this.resolver = new HandshakeResolver(hsk, options);
|
||||
this.resolver.on('log', (...a) => this.emit('log', ...a));
|
||||
this.resolver.on('error', e => this.emit('error', e));
|
||||
this.ra = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HandshakeResolver
|
||||
* @extends DNSResolver
|
||||
*/
|
||||
|
||||
class HandshakeResolver extends RecursiveResolver {
|
||||
constructor(hsk, options) {
|
||||
super(options);
|
||||
this.cache = new Cache();
|
||||
this.hsk = hsk;
|
||||
this.ra = false;
|
||||
}
|
||||
|
||||
async hook(qs, auth) {
|
||||
if (auth.zone !== '.')
|
||||
return [null, null];
|
||||
|
||||
let {name, type} = qs;
|
||||
|
||||
assert(util.isFQDN(name));
|
||||
|
||||
const labels = util.split(name);
|
||||
|
||||
// Acutal root zone.
|
||||
if (labels.length === 0)
|
||||
return [null, null];
|
||||
|
||||
// Handshake root zone.
|
||||
const zone = util.label(name, labels, -1);
|
||||
|
||||
if (zone !== HSK)
|
||||
return [null, null];
|
||||
|
||||
// Slice off HSK, so as not
|
||||
// to confuse the resolver.
|
||||
// i.e. Don't make it hit
|
||||
// us repeatedly.
|
||||
name = name.substring(0, labels.pop());
|
||||
|
||||
if (name === '')
|
||||
name = '.';
|
||||
|
||||
const cache = this.cache.hit(qs, auth.zone);
|
||||
|
||||
if (cache)
|
||||
return [cache, null];
|
||||
async resolve(req, rinfo) {
|
||||
const [qs] = req.question;
|
||||
|
||||
// Our root zone.
|
||||
if (name === '.') {
|
||||
if (qs.name === '.') {
|
||||
const res = new Message();
|
||||
|
||||
res.qr = true;
|
||||
res.ad = true;
|
||||
res.aa = true;
|
||||
|
||||
switch (type) {
|
||||
switch (qs.type) {
|
||||
case types.NS:
|
||||
res.answer.push(this.toNS());
|
||||
res.additional.push(this.toNSIPA());
|
||||
|
|
@ -101,66 +64,82 @@ class HandshakeResolver extends RecursiveResolver {
|
|||
case types.SOA:
|
||||
res.answer.push(this.toSOA());
|
||||
break;
|
||||
case types.DNSKEY:
|
||||
res.answer.push(key.pub);
|
||||
break;
|
||||
default:
|
||||
res.authority.push(this.toSOA());
|
||||
break;
|
||||
}
|
||||
|
||||
this.cache.insert(qs, auth.zone, res, true);
|
||||
if (req.isDNSSEC())
|
||||
dnssec.signMessage(res, '.', key.pub, key.priv);
|
||||
|
||||
return [res, null];
|
||||
return res;
|
||||
}
|
||||
|
||||
// Slice off the naked TLD.
|
||||
const tld = util.label(name, labels, -1);
|
||||
const data = await this.hsk.getDataByName(tld);
|
||||
const labels = util.split(qs.name);
|
||||
const tld = util.from(qs.name, labels, -1);
|
||||
const name = util.label(qs.name, labels, -1);
|
||||
const data = await this.hsk.getDataByName(name);
|
||||
const root = await this.getRoot(req);
|
||||
|
||||
// Send the root back to them.
|
||||
const opt = new Option();
|
||||
opt.code = options.TRIEROOT;
|
||||
opt.option = new TRIEROOTOption();
|
||||
opt.option.root = root;
|
||||
|
||||
// Should return root zone SOA record.
|
||||
if (!data) {
|
||||
const res = new Message();
|
||||
|
||||
res.code = codes.NXDOMAIN;
|
||||
res.qr = true;
|
||||
res.ad = true;
|
||||
res.aa = true;
|
||||
|
||||
res.authority.push(this.toSOA());
|
||||
if (type === types.TXT) {
|
||||
res.answer.push(await this.prove(tld, 900, null));
|
||||
res.answer.push(await this.hdr(tld, 900, null));
|
||||
} else {
|
||||
res.additional.push(await this.prove(tld, 900, null));
|
||||
res.additional.push(await this.hdr(tld, 900, null));
|
||||
|
||||
if (req.isEDNS0()) {
|
||||
const proof = await this.prove(root, name, 900, null);
|
||||
|
||||
res.additional.push(proof);
|
||||
|
||||
if (req.isDNSSEC()) {
|
||||
dnssec.signMessage(res, '.', key.pub, key.priv);
|
||||
dnssec.signMessage(res, tld, key.pub, key.priv);
|
||||
}
|
||||
|
||||
res.setOption(opt);
|
||||
}
|
||||
this.cache.insert(qs, auth.zone, res, true);
|
||||
return [res, null];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Our fake resolution.
|
||||
const rec = HSKRecord.fromRaw(data);
|
||||
const res = rec.toDNS(name, type);
|
||||
// Our resolution.
|
||||
const rec = HSKResource.fromRaw(data);
|
||||
const res = rec.toDNS(qs.name, qs.type);
|
||||
|
||||
if (res.aa) {
|
||||
if (type === types.TXT) {
|
||||
res.answer.push(await this.prove(tld, rec.ttl, data));
|
||||
res.answer.push(await this.hdr(tld, 900, null));
|
||||
} else {
|
||||
res.additional.push(await this.prove(tld, rec.ttl, data));
|
||||
res.additional.push(await this.hdr(tld, 900, null));
|
||||
}
|
||||
this.cache.insert(qs, auth.zone, res, true);
|
||||
return [res, null];
|
||||
if (req.isEDNS0()) {
|
||||
const proof = await this.prove(root, name, rec.ttl, data);
|
||||
|
||||
res.additional.push(proof);
|
||||
|
||||
if (req.isDNSSEC())
|
||||
dnssec.signMessage(res, tld, key.pub, key.priv);
|
||||
|
||||
res.setOption(opt);
|
||||
}
|
||||
|
||||
if (rec.compat && rec.ns.length > 0)
|
||||
return [res, name];
|
||||
|
||||
this.cache.insert(qs, auth.zone, res, true);
|
||||
|
||||
return [res, null];
|
||||
return res;
|
||||
}
|
||||
|
||||
toSOA() {
|
||||
const rr = new Record();
|
||||
const rd = new SOARecord();
|
||||
rr.name = `${HSK}.`;
|
||||
rr.name = '.';
|
||||
rr.type = types.SOA;
|
||||
rr.ttl = 900;
|
||||
rr.data = rd;
|
||||
|
|
@ -177,7 +156,7 @@ class HandshakeResolver extends RecursiveResolver {
|
|||
toNS() {
|
||||
const rr = new Record();
|
||||
const rd = new NSRecord();
|
||||
rr.name = `${HSK}.`;
|
||||
rr.name = '.';
|
||||
rr.type = types.NS;
|
||||
rr.ttl = 900;
|
||||
rr.data = rd;
|
||||
|
|
@ -207,183 +186,52 @@ class HandshakeResolver extends RecursiveResolver {
|
|||
return rr;
|
||||
}
|
||||
|
||||
async prove(tld, ttl, data) {
|
||||
const [hash, nodes] = await this.hsk.getProof(tld);
|
||||
const bw = bio.write();
|
||||
async prove(root, tld, ttl, data) {
|
||||
const [, nodes] = await this.hsk.proveName(root, tld);
|
||||
const rr = new Record();
|
||||
const rd = new TXTRecord();
|
||||
const rd = new NAMEPROOFRecord();
|
||||
|
||||
rr.name = `${tld}.${HSK}.`;
|
||||
rr.type = types.TXT;
|
||||
rr.name = `${tld}.`;
|
||||
rr.type = types.NAMEPROOF;
|
||||
rr.ttl = ttl;
|
||||
rr.data = rd;
|
||||
|
||||
bw.writeHash(hash);
|
||||
bw.writeVarint(nodes.length);
|
||||
|
||||
for (const node of nodes)
|
||||
bw.writeVarBytes(node);
|
||||
rd.exists = data ? true : false;
|
||||
rd.nodes = nodes;
|
||||
|
||||
if (data)
|
||||
bw.writeVarBytes(data);
|
||||
|
||||
const raw = bw.render();
|
||||
const b64 = raw.toString('base64');
|
||||
|
||||
rd.txt.push('hsk:proof');
|
||||
|
||||
for (let i = 0; i < b64.length; i += 255) {
|
||||
const chunk = b64.slice(i, i + 255);
|
||||
rd.txt.push(chunk);
|
||||
}
|
||||
rd.data = data;
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
async hdr(tld, ttl, hash) {
|
||||
let header = await this.hsk.getTip();
|
||||
async getRoot(req) {
|
||||
const opt = getRoot(req);
|
||||
|
||||
if (hash)
|
||||
header = await this.hsk.getEntry(hash);
|
||||
if (opt)
|
||||
return opt;
|
||||
|
||||
const rr = new Record();
|
||||
const rd = new TXTRecord();
|
||||
const tip = await this.hsk.getTip();
|
||||
assert(tip);
|
||||
|
||||
rr.name = `${tld}.${HSK}.`;
|
||||
rr.type = types.TXT;
|
||||
rr.ttl = ttl;
|
||||
rr.data = rd;
|
||||
|
||||
const txt = [];
|
||||
let b64 = '';
|
||||
|
||||
if (header)
|
||||
b64 = header.toRaw().toString('base64');
|
||||
|
||||
rd.txt.push('hsk:header');
|
||||
|
||||
for (let i = 0; i < b64.length; i += 255) {
|
||||
const chunk = b64.slice(i, i + 255);
|
||||
rd.txt.push(chunk);
|
||||
}
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
async resolve(qs, ns) {
|
||||
const name = qs.name;
|
||||
const labels = util.split(name);
|
||||
const zone = util.label(name, labels, -1);
|
||||
|
||||
if (zone === ICANN) {
|
||||
qs = qs.clone();
|
||||
qs.name = util.to(name, labels, -1);
|
||||
}
|
||||
|
||||
const rc = await this._resolve(qs, ns);
|
||||
const res = rc.toAnswer();
|
||||
|
||||
if (rc.rewritten || zone === ICANN) {
|
||||
const domain = util.to(name, labels, -1);
|
||||
return convert(res, domain, zone);
|
||||
}
|
||||
|
||||
return res;
|
||||
return Buffer.from(tip.trieRoot, 'hex');
|
||||
}
|
||||
}
|
||||
|
||||
function append(name, domain, zone) {
|
||||
if (zone === ICANN) {
|
||||
if (!util.isSubdomain(zone, name))
|
||||
name += `${zone}.`;
|
||||
return name;
|
||||
}
|
||||
if (util.isSubdomain(domain, name))
|
||||
name += `${zone}.`;
|
||||
return name;
|
||||
}
|
||||
function getRoot(req) {
|
||||
const edns = req.getEDNS0();
|
||||
|
||||
function convert(res, domain, zone) {
|
||||
const msg = res;
|
||||
if (!edns)
|
||||
return null;
|
||||
|
||||
for (const qs of msg.question)
|
||||
qs.name = append(qs.name, domain, zone);
|
||||
const options = edns.data.options;
|
||||
|
||||
for (const section of msg.sections()) {
|
||||
for (const rr of section) {
|
||||
const x = rr.data;
|
||||
|
||||
rr.name = append(rr.name, domain, zone);
|
||||
|
||||
// DNSSEC standard
|
||||
switch (rr.type) {
|
||||
case types.NS:
|
||||
x.ns = append(x.ns, domain, zone);
|
||||
break;
|
||||
case types.MD:
|
||||
x.md = append(x.md, domain, zone);
|
||||
break;
|
||||
case types.MF:
|
||||
x.mf = append(x.mf, domain, zone);
|
||||
break;
|
||||
case types.CNAME:
|
||||
x.target = append(x.target, domain, zone);
|
||||
break;
|
||||
case types.SOA:
|
||||
x.ns = append(x.ns, domain, zone);
|
||||
x.mbox = append(x.mbox, domain, zone);
|
||||
break;
|
||||
case types.MB:
|
||||
x.mb = append(x.mb, domain, zone);
|
||||
break;
|
||||
case types.MG:
|
||||
x.mg = append(x.mg, domain, zone);
|
||||
break;
|
||||
case types.MR:
|
||||
x.mr = append(x.mr, domain, zone);
|
||||
break;
|
||||
case types.PTR:
|
||||
x.ptr = append(x.ptr, domain, zone);
|
||||
break;
|
||||
case types.MINFO:
|
||||
x.rmail = append(x.rmail, domain, zone);
|
||||
x.email = append(x.email, domain, zone);
|
||||
break;
|
||||
case types.MX:
|
||||
x.mx = append(x.mx, domain, zone);
|
||||
break;
|
||||
case types.RP:
|
||||
x.mbox = append(x.mbox, domain, zone);
|
||||
break;
|
||||
case types.AFSDB:
|
||||
x.hostname = append(x.hostname, domain, zone);
|
||||
break;
|
||||
case types.SIG:
|
||||
case types.RRSIG:
|
||||
x.signerName = append(x.signerName, domain, zone);
|
||||
break;
|
||||
case types.PX:
|
||||
x.map822 = append(x.map822, domain, zone);
|
||||
x.mapx400 = append(x.mapx400, domain, zone);
|
||||
break;
|
||||
case types.NAPTR:
|
||||
x.replacement = append(x.replacement, domain, zone);
|
||||
break;
|
||||
case types.KX:
|
||||
x.exchanger = append(x.exchanger, domain, zone);
|
||||
break;
|
||||
case types.SRV:
|
||||
x.target = append(x.target, domain, zone);
|
||||
break;
|
||||
case types.DNAME:
|
||||
x.target = append(x.target, domain, zone);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const opt of options) {
|
||||
if (opt.code === wire.options.TRIEROOT)
|
||||
return opt.option.root;
|
||||
}
|
||||
|
||||
return msg;
|
||||
return null;
|
||||
}
|
||||
|
||||
exports.HandshakeServer = HandshakeServer;
|
||||
exports.HandshakeResolver = HandshakeResolver;
|
||||
|
|
|
|||
52
lib/covenants/key.js
Normal file
52
lib/covenants/key.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
const {Record} = require('bns').wire;
|
||||
|
||||
exports.priv = Buffer.from(''
|
||||
+ 'MIIEpQIBAAKCAQEAsF965ZdEncXuSbwxhD0BV3LnhUkRPw85Ws+LTokucKfBaR6G'
|
||||
+ 'GOV2qc/CyfBI3ZBmM0TpJthzSKVZWeddeVxcjMAZ+qUIw4U7NkPGXALiDVUQItx/'
|
||||
+ 'ZgcBtiV2hmFfVpArQodMUxveKzMLzj8VbWpGTu2myzyCTQ1MIKddoee85S4QbfjM'
|
||||
+ 'bM1nR00ML6bBqUhOpOKxfi+V4ycjjeafINV4XCIbacD7bp2AJuNrn2qAzixP5xge'
|
||||
+ 'oTS1WQAUWbfOjLRzG+/Dr/cMx0eLuYf1Vs7OsFZittzdBoMv3xBS0KSUkwM0Y1ST'
|
||||
+ 'TrHf9xyOqaUCIwD7ksiFHiZUPoq77S9hDvSIbwIDAQABAoIBAATpU8HK+ZUvKtiQ'
|
||||
+ 'zgwxqrTltT7H7xwDb4Rw3R89wLZQZZloyTEuSqSl7XW0JENPPxlUZO24/1TZjehs'
|
||||
+ 'AfVcNhORUefh6qGPNzvmnUJ4rhTS9pUR8NZFga2x02AgnAgMEbhTjjOORhyL2ltO'
|
||||
+ '9GjMmdKe2ZM1RyegJCuQnZHhoyf6mYXB2r7dA09OnwZdBEa/O1DhBuAmTVre+OZk'
|
||||
+ '10Rex4wTGhxzfWUASxfQfhC5cr9cR1R+Km6kOf9RX3BEDNArpQHV2d1x9FyekOzw'
|
||||
+ 'BH1zuhgheSdzuAGR7rXQvLIMCSZ/0LvdSrUJiY0Zh1tkvhdUW4hZqs+Gz4Ul7QF1'
|
||||
+ 'JGcSZXkCgYEA6Tl8llu5jiN0U2+XPFvfGrXPqSvhS3RHvlo94eRzNRZ0cQskLHIt'
|
||||
+ '3jLHrCBI2VykGF35aVSqTbumv4cnsFlmQZVl/OmMLI44ugnWy005o3ySOqF3FsA0'
|
||||
+ 'l8SQD0vIJk1UTTu9obAqV72Kbt9sx6fSeuR6xckSNlYgcWDljtHeUasCgYEAwZi6'
|
||||
+ 'bBydJvJ61PKNrXQyEP15d4i1CnGh2OBfbGiQSMNpvzFcKfR79qn2K+XhV6eIrmE2'
|
||||
+ 'bM3rzjgE66rv6fzQn5LDDN7ZuCoPBfAV9hH3/Dr7GqC1GvWoeG/deWobPuzBGxnW'
|
||||
+ '1B2VVjKvqG18DZVZlgsjFN9NM6f3hogPNNI56E0CgYEAkwXcVmToaoRLNrXoHvLD'
|
||||
+ 'iHEIwdqZohlhiMwWqqp7PgIz0Xd2jFZGOAbG/Ok1Q2E1SO8k5ZOr8GjVS3QGPxN8'
|
||||
+ 'dOebbX5FEWlutUiykWLTbQ6AmFllW4A7J1mQfzQErrCc7js05hLJ/pnMBOzwBET1'
|
||||
+ 'WOdjxf9lbb+JoC+3RvtiLRUCgYEApYEG5oPzyacEYWZWvpGWd7XqkMkbVKleXsU6'
|
||||
+ 'brhZmQsOLThqfSeYjoAwhsjIw6HjFIjg+VV1oN99PWfuIJBUXgcenrMpV+sE2uOs'
|
||||
+ 'Mqib41Mc9l+rVDftZcDkivauAjZuw9dsM/xyfbVpPEkVA5vJcZ9lx2M7YczXrHhG'
|
||||
+ '37ZVcQUCgYEAqgVrQ5CfInj9MZSxTUVWjwL9imrgRQEX77y6hlCkblUH3ubpk91m'
|
||||
+ 'HdX400I6Xo5nIp9IZobGPLGTyUHojmFAeFAHNSltduMwRb41dyjXNwG2s5v5uY9T'
|
||||
+ 'E2dDJc22xqmzRb9nc2e8xZhFmRcweHWOK+isiqK/6quK77WfO9JHykU=',
|
||||
'base64'
|
||||
);
|
||||
|
||||
// . 172800 IN DS 28834 8 2 305fadd310e0e468faa92d65d3d0c0fe1ff740f86f2b203bd46986bdf25582d5
|
||||
exports.pub = Record.fromJSON({
|
||||
name: '.',
|
||||
ttl: 172800,
|
||||
class: 'INET',
|
||||
type: 'DNSKEY',
|
||||
data: {
|
||||
flags: 257,
|
||||
protocol: 3,
|
||||
algorithm: 8,
|
||||
publicKey: ''
|
||||
+ 'AwEAAQCwX3rll0Sdxe5JvDGEPQFXcueFSRE/Dzlaz4tOiS5wp8FpHoYY5Xap'
|
||||
+ 'z8LJ8EjdkGYzROkm2HNIpVlZ5115XFyMwBn6pQjDhTs2Q8ZcAuINVRAi3H9m'
|
||||
+ 'BwG2JXaGYV9WkCtCh0xTG94rMwvOPxVtakZO7abLPIJNDUwgp12h57zlLhBt'
|
||||
+ '+MxszWdHTQwvpsGpSE6k4rF+L5XjJyON5p8g1XhcIhtpwPtunYAm42ufaoDO'
|
||||
+ 'LE/nGB6hNLVZABRZt86MtHMb78Ov9wzHR4u5h/VWzs6wVmK23N0Ggy/fEFLQ'
|
||||
+ 'pJSTAzRjVJNOsd/3HI6ppQIjAPuSyIUeJlQ+irvtL2EO9Ihv'
|
||||
}
|
||||
});
|
||||
|
|
@ -4,6 +4,7 @@ const assert = require('assert');
|
|||
const bns = require('bns');
|
||||
const {IP, onion, base32} = require('binet');
|
||||
const {bech32} = require('bstring');
|
||||
const {Struct} = require('bufio');
|
||||
const compress = require('./compress');
|
||||
|
||||
const {
|
||||
|
|
@ -14,7 +15,6 @@ const {
|
|||
const {
|
||||
Message,
|
||||
Record,
|
||||
RecordData,
|
||||
ARecord,
|
||||
AAAARecord,
|
||||
NSRecord,
|
||||
|
|
@ -29,6 +29,8 @@ const {
|
|||
TLSARecord,
|
||||
SSHFPRecord,
|
||||
OPENPGPKEYRecord,
|
||||
URIRecord,
|
||||
RPRecord,
|
||||
types
|
||||
} = wire;
|
||||
|
||||
|
|
@ -48,38 +50,29 @@ const {
|
|||
|
||||
const DUMMY = Buffer.alloc(0);
|
||||
|
||||
const ICANN = 'i';
|
||||
const HSK = 'h';
|
||||
const ICANNP = `.${ICANN}`;
|
||||
const ICANNS = `${ICANN}.`;
|
||||
const HSKP = `.${HSK}`;
|
||||
const HSKS = `${HSK}.`;
|
||||
|
||||
const rtypes = {
|
||||
INET4: 1, // A
|
||||
INET6: 2, // AAAA
|
||||
ONION: 3, // TXT (appended to A/AAA responses)
|
||||
ONIONNG: 5, // TXT (appended to A/AAA responses)
|
||||
INAME: 6, // N/A
|
||||
HNAME: 7, // N/A
|
||||
|
||||
CANONICAL: 8, // CNAME
|
||||
DELEGATE: 9, // DNAME
|
||||
NS: 10, // NS
|
||||
SERVICE: 11, // SRV
|
||||
URL: 12, // TXT
|
||||
EMAIL: 13, // TXT
|
||||
TEXT: 14, // TXT
|
||||
LOCATION: 15, // LOC
|
||||
MAGNET: 16, // TXT
|
||||
DS: 17, // DS
|
||||
TLS: 18, // TLSA
|
||||
SSH: 19, // SSHFP
|
||||
PGP: 20, // OPENPGPKEY (XXX)
|
||||
ADDR: 21 // TXT
|
||||
ONIONNG: 4, // TXT (appended to A/AAA responses)
|
||||
NAME: 5, // CNAME
|
||||
CANONICAL: 6, // CNAME
|
||||
DELEGATE: 7, // DNAME
|
||||
NS: 8, // NS
|
||||
SERVICE: 9, // SRV
|
||||
URL: 10, // URI
|
||||
EMAIL: 11, // RP
|
||||
TEXT: 12, // TXT
|
||||
LOCATION: 13, // LOC
|
||||
MAGNET: 14, // TXT
|
||||
DS: 15, // DS
|
||||
TLS: 16, // TLSA
|
||||
SSH: 17, // SSHFP
|
||||
PGP: 18, // OPENPGPKEY (XXX)
|
||||
ADDR: 19 // TXT
|
||||
};
|
||||
|
||||
class Extra extends RecordData {
|
||||
class Extra extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 0;
|
||||
|
|
@ -132,7 +125,7 @@ class Extra extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class Addr extends RecordData {
|
||||
class Addr extends Struct {
|
||||
constructor(currency, address) {
|
||||
super();
|
||||
this.currency = currency || '';
|
||||
|
|
@ -327,11 +320,11 @@ class Addr extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class SSH extends RecordData {
|
||||
class SSH extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.algorithm = 0;
|
||||
this.type = 0;
|
||||
this.keyType = 0;
|
||||
this.fingerprint = DUMMY;
|
||||
}
|
||||
|
||||
|
|
@ -344,7 +337,7 @@ class SSH extends RecordData {
|
|||
|
||||
toWriter(bw) {
|
||||
bw.writeU8(this.algorithm);
|
||||
bw.writeU8(this.type);
|
||||
bw.writeU8(this.keyType);
|
||||
bw.writeU8(this.fingerprint.length);
|
||||
bw.writeBytes(this.fingerprint);
|
||||
return bw;
|
||||
|
|
@ -352,7 +345,7 @@ class SSH extends RecordData {
|
|||
|
||||
fromReader(br) {
|
||||
this.algorithm = br.readU8();
|
||||
this.type = br.readU8();
|
||||
this.keyType = br.readU8();
|
||||
this.fingerprint = br.readBytes(br.readU8());
|
||||
return this;
|
||||
}
|
||||
|
|
@ -360,7 +353,7 @@ class SSH extends RecordData {
|
|||
toJSON() {
|
||||
return {
|
||||
algorithm: this.algorithm,
|
||||
type: this.type,
|
||||
keyType: this.keyType,
|
||||
fingerprint: this.fingerprint.toString('hex')
|
||||
};
|
||||
}
|
||||
|
|
@ -368,11 +361,11 @@ class SSH extends RecordData {
|
|||
fromJSON(json) {
|
||||
assert(json && typeof json === 'object');
|
||||
assert((json.algorithm & 0xff) === json.algorithm);
|
||||
assert((json.type & 0xff) === json.type);
|
||||
assert((json.keyType & 0xff) === json.keyType);
|
||||
assert(typeof json.fingerprint === 'string');
|
||||
assert((json.fingerprint >>> 1) <= 255);
|
||||
this.algorithm = json.algorithm;
|
||||
this.type = json.type;
|
||||
this.keyType = json.keyType;
|
||||
this.fingerprint = Buffer.from(json.fingerprint, 'hex');
|
||||
return this;
|
||||
}
|
||||
|
|
@ -392,7 +385,7 @@ class PGP extends SSH {
|
|||
}
|
||||
}
|
||||
|
||||
class TLS extends RecordData {
|
||||
class TLS extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.protocol = '';
|
||||
|
|
@ -471,7 +464,7 @@ class TLS extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class DS extends RecordData {
|
||||
class DS extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.keyTag = 0;
|
||||
|
|
@ -497,7 +490,7 @@ class DS extends RecordData {
|
|||
}
|
||||
|
||||
fromReader(br) {
|
||||
this.keyTag = br.readU16BE();
|
||||
this.keyTag = br.readU16();
|
||||
this.algorithm = br.readU8();
|
||||
this.digestType = br.readU8();
|
||||
this.digest = br.readBytes(br.readU8());
|
||||
|
|
@ -536,7 +529,7 @@ class DS extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class Magnet extends RecordData {
|
||||
class Magnet extends Struct {
|
||||
constructor(nid, nin) {
|
||||
super();
|
||||
this.nid = nid || '';
|
||||
|
|
@ -623,7 +616,7 @@ class Magnet extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class Service extends RecordData {
|
||||
class Service extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.service = '';
|
||||
|
|
@ -728,7 +721,7 @@ class Service extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class Location extends RecordData {
|
||||
class Location extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.version = 0;
|
||||
|
|
@ -833,8 +826,7 @@ class Location extends RecordData {
|
|||
|
||||
function compressTarget(type, target, c) {
|
||||
switch (type) {
|
||||
case rtypes.INAME:
|
||||
case rtypes.HNAME: {
|
||||
case rtypes.NAME: {
|
||||
c.add(target);
|
||||
break;
|
||||
}
|
||||
|
|
@ -857,8 +849,7 @@ function sizeTarget(type, target, c) {
|
|||
case rtypes.ONIONNG:
|
||||
size += 33;
|
||||
break;
|
||||
case rtypes.INAME:
|
||||
case rtypes.HNAME: {
|
||||
case rtypes.NAME: {
|
||||
size += c.size(target);
|
||||
break;
|
||||
}
|
||||
|
|
@ -891,8 +882,7 @@ function writeTarget(type, target, bw, c) {
|
|||
bw.writeBytes(key);
|
||||
break;
|
||||
}
|
||||
case rtypes.INAME:
|
||||
case rtypes.HNAME: {
|
||||
case rtypes.NAME: {
|
||||
c.write(bw, target);
|
||||
break;
|
||||
}
|
||||
|
|
@ -913,14 +903,9 @@ function readTarget(type, br, d) {
|
|||
return onion.encodeLegacy(br.readBytes(10));
|
||||
case rtypes.ONIONNG:
|
||||
return onion.encodeNG(br.readBytes(33), null);
|
||||
case rtypes.INAME: {
|
||||
case rtypes.NAME: {
|
||||
const name = d.read(br);
|
||||
assert(verifyICANN(name));
|
||||
return name;
|
||||
}
|
||||
case rtypes.HNAME: {
|
||||
const name = d.read(br);
|
||||
assert(verifyHSK(name));
|
||||
assert(verifyName(name));
|
||||
return name;
|
||||
}
|
||||
default:
|
||||
|
|
@ -928,15 +913,7 @@ function readTarget(type, br, d) {
|
|||
}
|
||||
}
|
||||
|
||||
function verifyICANN(name) {
|
||||
return verifyName(name, false);
|
||||
}
|
||||
|
||||
function verifyHSK(name) {
|
||||
return verifyName(name, true);
|
||||
}
|
||||
|
||||
function verifyName(name, hsk) {
|
||||
function verifyName(name) {
|
||||
if (name.length === 0)
|
||||
return false;
|
||||
|
||||
|
|
@ -963,7 +940,7 @@ function verifyName(name, hsk) {
|
|||
}
|
||||
|
||||
// - and _
|
||||
if (ch === 0x2d || (hsk && ch === 0x5f)) {
|
||||
if (ch === 0x2d || ch === 0x5f) {
|
||||
if (i === 0 || i === name.length - 1)
|
||||
return false; // Bad dash.
|
||||
|
||||
|
|
@ -976,16 +953,10 @@ function verifyName(name, hsk) {
|
|||
return false; // Unexpected character.
|
||||
}
|
||||
|
||||
if (util.endsWith(name, HSKP))
|
||||
return false;
|
||||
|
||||
if (util.endsWith(name, ICANNP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class Target extends RecordData {
|
||||
class Target extends Struct {
|
||||
constructor(type, target) {
|
||||
super();
|
||||
this.type = rtypes.INET4;
|
||||
|
|
@ -1015,10 +986,8 @@ class Target extends RecordData {
|
|||
}
|
||||
|
||||
toString() {
|
||||
if (this.isHSK())
|
||||
return `${this.target}.${HSK}`;
|
||||
if (this.isICANN())
|
||||
return `${this.target}.${ICANN}`;
|
||||
if (this.isName())
|
||||
return `${this.target}.`;
|
||||
return this.target;
|
||||
}
|
||||
|
||||
|
|
@ -1060,23 +1029,11 @@ class Target extends RecordData {
|
|||
return this;
|
||||
}
|
||||
|
||||
let name = util.trimFQDN(str);
|
||||
const name = util.trimFQDN(str);
|
||||
assert(verifyName(name));
|
||||
|
||||
if (util.endsWith(name, HSKP)) {
|
||||
name = name.slice(0, -HSKP.length);
|
||||
assert(verifyHSK(name));
|
||||
this.type = rtypes.HNAME;
|
||||
this.target = name;
|
||||
} else if (util.endsWith(name, ICANNP)) {
|
||||
name = name.slice(0, -ICANNP.length);
|
||||
assert(verifyICANN(name));
|
||||
this.type = rtypes.INAME;
|
||||
this.target = name;
|
||||
} else {
|
||||
assert(verifyICANN(name));
|
||||
this.type = rtypes.INAME;
|
||||
this.target = name;
|
||||
}
|
||||
this.type = rtypes.NAME;
|
||||
this.target = name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -1113,7 +1070,7 @@ class Target extends RecordData {
|
|||
return `_${hash}.${name}`;
|
||||
}
|
||||
|
||||
return `_${hash}.${HSK}`;
|
||||
return `_${hash}.`;
|
||||
}
|
||||
|
||||
isINET4() {
|
||||
|
|
@ -1132,20 +1089,12 @@ class Target extends RecordData {
|
|||
return this.type === rtypes.ONIONNG;
|
||||
}
|
||||
|
||||
isHSK() {
|
||||
return this.type === rtypes.HNAME;
|
||||
}
|
||||
|
||||
isICANN() {
|
||||
return this.type === rtypes.INAME;
|
||||
}
|
||||
|
||||
isINET() {
|
||||
return this.type <= rtypes.INET6;
|
||||
}
|
||||
|
||||
isName() {
|
||||
return this.type > rtypes.ONIONNG;
|
||||
return this.type === rtypes.NAME;
|
||||
}
|
||||
|
||||
isTor() {
|
||||
|
|
@ -1153,12 +1102,7 @@ class Target extends RecordData {
|
|||
}
|
||||
|
||||
toDNS() {
|
||||
if (this.isHSK()) {
|
||||
assert(!util.isFQDN(this.target));
|
||||
return `${this.target}.${HSK}.`;
|
||||
}
|
||||
|
||||
if (this.isICANN()) {
|
||||
if (this.isName()) {
|
||||
assert(!util.isFQDN(this.target));
|
||||
return `${this.target}.`;
|
||||
}
|
||||
|
|
@ -1187,7 +1131,7 @@ class Target extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
class HSKRecord extends RecordData {
|
||||
class HSKResource extends Struct {
|
||||
constructor() {
|
||||
super();
|
||||
this.version = 0;
|
||||
|
|
@ -1449,8 +1393,7 @@ class HSKRecord extends RecordData {
|
|||
this.hosts.push(new Target(type, target));
|
||||
break;
|
||||
}
|
||||
case rtypes.INAME:
|
||||
case rtypes.HNAME: {
|
||||
case rtypes.NAME: {
|
||||
assert(!this.canonical);
|
||||
const target = readTarget(type, br, d);
|
||||
this.canonical = new Target(type, target);
|
||||
|
|
@ -1689,7 +1632,7 @@ class HSKRecord extends RecordData {
|
|||
toSOA(name) {
|
||||
assert(util.isFQDN(name));
|
||||
|
||||
const tld = util.from(name, -2);
|
||||
const tld = util.from(name, -1);
|
||||
const rr = new Record();
|
||||
const rd = new SOARecord();
|
||||
|
||||
|
|
@ -1908,7 +1851,7 @@ class HSKRecord extends RecordData {
|
|||
rr.data = rd;
|
||||
|
||||
rd.algorithm = ssh.algorithm;
|
||||
rd.type = ssh.type;
|
||||
rd.keyType = ssh.keyType;
|
||||
rd.fingerprint = ssh.fingerprint;
|
||||
|
||||
answer.push(rr);
|
||||
|
|
@ -1938,6 +1881,49 @@ class HSKRecord extends RecordData {
|
|||
return answer;
|
||||
}
|
||||
|
||||
toURI(name) {
|
||||
const answer = [];
|
||||
|
||||
for (const url of this.url) {
|
||||
const rr = new Record();
|
||||
const rd = new URIRecord();
|
||||
|
||||
rr.name = name;
|
||||
rr.type = types.URI;
|
||||
rr.ttl = this.ttl;
|
||||
rr.data = rd;
|
||||
|
||||
rd.priority = 0;
|
||||
rd.weight = 0;
|
||||
rd.target = url;
|
||||
|
||||
answer.push(rr);
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
toRP(name) {
|
||||
const answer = [];
|
||||
|
||||
for (const email of this.email) {
|
||||
const rr = new Record();
|
||||
const rd = new RPRecord();
|
||||
|
||||
rr.name = name;
|
||||
rr.type = types.RP;
|
||||
rr.ttl = this.ttl;
|
||||
rr.data = rd;
|
||||
|
||||
rd.mbox = email;
|
||||
rd.txt = '.';
|
||||
|
||||
answer.push(rr);
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
hasTor() {
|
||||
for (const host of this.hosts) {
|
||||
if (host.isTor())
|
||||
|
|
@ -1965,40 +1951,6 @@ class HSKRecord extends RecordData {
|
|||
return rr;
|
||||
}
|
||||
|
||||
toURLTXT(name) {
|
||||
const rr = new Record();
|
||||
const rd = new TXTRecord();
|
||||
|
||||
rr.name = name;
|
||||
rr.type = types.TXT;
|
||||
rr.ttl = this.ttl;
|
||||
rr.data = rd;
|
||||
|
||||
rd.txt.push('hsk:url');
|
||||
|
||||
for (const url of this.url)
|
||||
rd.txt.push(url);
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
toEmailTXT(name) {
|
||||
const rr = new Record();
|
||||
const rd = new TXTRecord();
|
||||
|
||||
rr.name = name;
|
||||
rr.type = types.TXT;
|
||||
rr.ttl = this.ttl;
|
||||
rr.data = rd;
|
||||
|
||||
rd.txt.push('hsk:email');
|
||||
|
||||
for (const email of this.email)
|
||||
rd.txt.push(email);
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
toMagnetTXT(name) {
|
||||
const rr = new Record();
|
||||
const rd = new TXTRecord();
|
||||
|
|
@ -2054,12 +2006,6 @@ class HSKRecord extends RecordData {
|
|||
if (this.text.length > 0)
|
||||
answer.push(this.toTextTXT(name));
|
||||
|
||||
if (this.url.length > 0)
|
||||
answer.push(this.toURLTXT(name));
|
||||
|
||||
if (this.email.length > 0)
|
||||
answer.push(this.toEmailTXT(name));
|
||||
|
||||
if (this.magnet.length > 0)
|
||||
answer.push(this.toMagnetTXT(name));
|
||||
|
||||
|
|
@ -2078,13 +2024,34 @@ class HSKRecord extends RecordData {
|
|||
|
||||
assert(util.isFQDN(name));
|
||||
|
||||
name += `${HSK}.`;
|
||||
if (this.compat) {
|
||||
const records = wire.fromZone(bns.hints);
|
||||
|
||||
for (const rr of records) {
|
||||
switch (rr.type) {
|
||||
case types.NS:
|
||||
rr.data.ns = rr.data.ns.toLowerCase();
|
||||
res.authority.push(rr);
|
||||
break;
|
||||
case types.A:
|
||||
case types.AAAA:
|
||||
rr.name = rr.name.toLowerCase();
|
||||
res.additional.push(rr);
|
||||
break;
|
||||
case types.DS:
|
||||
res.authority.push(rr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const labels = util.split(name);
|
||||
|
||||
// Referral.
|
||||
if (labels.length > 2) {
|
||||
const tld = util.from(name, labels, -2);
|
||||
if (labels.length > 1) {
|
||||
const tld = util.from(name, labels, -1);
|
||||
|
||||
if (this.ns.length > 0) {
|
||||
res.authority = this.toNS(tld, naked);
|
||||
|
|
@ -2099,8 +2066,6 @@ class HSKRecord extends RecordData {
|
|||
res.authority = this.toSOA(tld);
|
||||
}
|
||||
|
||||
res.setEDNS0(4096, true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -2161,6 +2126,12 @@ class HSKRecord extends RecordData {
|
|||
case types.OPENPGPKEY:
|
||||
res.answer = this.toOPENPGPKEY(name);
|
||||
break;
|
||||
case types.URI:
|
||||
res.answer = this.toURI(name);
|
||||
break;
|
||||
case types.RP:
|
||||
res.answer = this.toRP(name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (res.answer.length === 0
|
||||
|
|
@ -2179,15 +2150,21 @@ class HSKRecord extends RecordData {
|
|||
// think it's standard recursive resolver
|
||||
// behavior to pay attention to them.
|
||||
}
|
||||
res.setEDNS0(4096, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Nothing. Return the SOA.
|
||||
res.authority = this.toSOA(name);
|
||||
}
|
||||
if (this.ns.length > 0) {
|
||||
res.authority = this.toNS(name, naked);
|
||||
res.additional = this.toNSIP(name, naked);
|
||||
|
||||
res.setEDNS0(4096, true);
|
||||
// Always push on DS records for a referral.
|
||||
for (const rr of this.toDS(name))
|
||||
res.authority.push(rr);
|
||||
} else {
|
||||
// Nothing. Return the SOA.
|
||||
res.authority = this.toSOA(name);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -2435,10 +2412,4 @@ class HSKRecord extends RecordData {
|
|||
}
|
||||
}
|
||||
|
||||
exports.ICANN = ICANN;
|
||||
exports.HSK = HSK;
|
||||
exports.ICANNP = ICANNP;
|
||||
exports.ICANNS = ICANNS;
|
||||
exports.HSKP = HSKP;
|
||||
exports.HSKS = HSKS;
|
||||
exports.HSKRecord = HSKRecord;
|
||||
exports.HSKResource = HSKResource;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,8 +23,8 @@ const blacklist = new Set([
|
|||
'bit', // Namecoin
|
||||
'eth', // ENS
|
||||
'example', // ICANN reserved
|
||||
'h', // Handshake compat
|
||||
'i', // ICANN compat
|
||||
// 'h', // Handshake compat
|
||||
// 'i', // ICANN compat
|
||||
'invalid', // ICANN reserved
|
||||
'local', // mDNS
|
||||
'localhost', // ICANN reserved
|
||||
|
|
@ -185,8 +185,8 @@ exports.isReserved = function isReserved(name, height, network) {
|
|||
assert((height >>> 0) === height);
|
||||
assert(network);
|
||||
|
||||
if (network.type !== 'main')
|
||||
return false;
|
||||
// if (network.type !== 'main')
|
||||
// return false;
|
||||
|
||||
if (height >= exports.CLAIM_PERIOD)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ class FullNode extends Node {
|
|||
await this.openPlugins();
|
||||
|
||||
await this.http.open();
|
||||
await this.dns.open(53, '127.0.0.1');
|
||||
await this.dns.open(5368, '127.0.0.1');
|
||||
await this.handleOpen();
|
||||
|
||||
this.logger.info('Node is loaded.');
|
||||
|
|
|
|||
6
lib/protocol/genesis.json
Normal file
6
lib/protocol/genesis.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
const BN = require('bn.js');
|
||||
const genesis = require('./genesis.json');
|
||||
|
||||
const network = exports;
|
||||
|
||||
|
|
@ -96,12 +97,12 @@ main.halvingInterval = 875000;
|
|||
|
||||
main.genesis = {
|
||||
version: 0,
|
||||
hash: '278c36df6a34966988b0c35c369124cc65bd909fdadedfd57390d2228cdb7f6b',
|
||||
hash: '9b5d0da7b31f9a909cff699c47c5ac503e4440a3e524ec0c0ac45157961c148f',
|
||||
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
|
||||
merkleRoot:
|
||||
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
|
||||
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
|
||||
witnessRoot:
|
||||
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
|
||||
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
|
||||
trieRoot:
|
||||
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
||||
time: 1514765688,
|
||||
|
|
@ -116,22 +117,7 @@ main.genesis = {
|
|||
* @const {String}
|
||||
*/
|
||||
|
||||
main.genesisBlock = ''
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
|
||||
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
|
||||
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
|
||||
+ '4c111314787d495a00000000ffff7f2000000000000000000000000000000000'
|
||||
+ '2a00000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000100000000010000000000000000000000000000000000'
|
||||
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
|
||||
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
|
||||
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
|
||||
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
|
||||
main.genesisBlock = genesis.main;
|
||||
|
||||
/**
|
||||
* POW-related constants.
|
||||
|
|
@ -429,12 +415,12 @@ testnet.halvingInterval = 875000;
|
|||
|
||||
testnet.genesis = {
|
||||
version: 0,
|
||||
hash: 'a126bf34683dfe1b17646b2d3472d4ebbb20a4b246014f788e8bb6a0badfd7d8',
|
||||
hash: '600b659a56c45c7687d3e8e7646ed8224d209ee145fe010cc580f9cb260bd8d8',
|
||||
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
|
||||
merkleRoot:
|
||||
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
|
||||
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
|
||||
witnessRoot:
|
||||
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
|
||||
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
|
||||
trieRoot:
|
||||
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
||||
time: 1514765689,
|
||||
|
|
@ -444,19 +430,7 @@ testnet.genesis = {
|
|||
height: 0
|
||||
};
|
||||
|
||||
testnet.genesisBlock = ''
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
|
||||
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
|
||||
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
|
||||
+ '4c111314797d495a00000000ffff7f2000000000000000000000000000000000'
|
||||
+ '1200000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000100000000010000000000000000000000000000000000'
|
||||
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
|
||||
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
|
||||
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
|
||||
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
|
||||
testnet.genesisBlock = genesis.testnet;
|
||||
|
||||
testnet.pow = {};
|
||||
testnet.pow.limit = new BN(
|
||||
|
|
@ -563,12 +537,12 @@ regtest.halvingInterval = 150;
|
|||
|
||||
regtest.genesis = {
|
||||
version: 0,
|
||||
hash: 'efad42980aeca59254a17f8ea40df2f5dc43db6a020c5e60a4e620e953aa6d99',
|
||||
hash: '4acfcebc924ccf90ec37933bf24982814f5a8014d799d828dd25c631adb786d3',
|
||||
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
|
||||
merkleRoot:
|
||||
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
|
||||
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
|
||||
witnessRoot:
|
||||
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
|
||||
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
|
||||
trieRoot:
|
||||
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
||||
time: 1514765690,
|
||||
|
|
@ -578,19 +552,7 @@ regtest.genesis = {
|
|||
height: 0
|
||||
};
|
||||
|
||||
regtest.genesisBlock = ''
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
|
||||
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
|
||||
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
|
||||
+ '4c1113147a7d495a00000000ffff7f2000000000000000000000000000000000'
|
||||
+ '1200000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000100000000010000000000000000000000000000000000'
|
||||
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
|
||||
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
|
||||
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
|
||||
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
|
||||
regtest.genesisBlock = genesis.regtest;
|
||||
|
||||
regtest.pow = {};
|
||||
regtest.pow.limit = new BN(
|
||||
|
|
@ -698,12 +660,12 @@ simnet.halvingInterval = 875000;
|
|||
|
||||
simnet.genesis = {
|
||||
version: 0,
|
||||
hash: 'b185fff116006d8099bc50fa072f2beed6c077be0ec9160d2f5a6401a2dfdeb6',
|
||||
hash: '4f3f5a9029753f50bd793b34cffbd5563cc74004fef97e7e3851adac302cc6ab',
|
||||
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
|
||||
merkleRoot:
|
||||
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
|
||||
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
|
||||
witnessRoot:
|
||||
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
|
||||
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
|
||||
trieRoot:
|
||||
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
||||
time: 1514765691,
|
||||
|
|
@ -713,19 +675,7 @@ simnet.genesis = {
|
|||
height: 0
|
||||
};
|
||||
|
||||
simnet.genesisBlock = ''
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
|
||||
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
|
||||
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
|
||||
+ '4c1113147b7d495a00000000ffff7f2000000000000000000000000000000000'
|
||||
+ '1200000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
+ '0000000000000000000100000000010000000000000000000000000000000000'
|
||||
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
|
||||
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
|
||||
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
|
||||
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
|
||||
simnet.genesisBlock = genesis.simnet;
|
||||
|
||||
simnet.pow = {};
|
||||
simnet.pow.limit = new BN(
|
||||
|
|
|
|||
217
scripts/gen.js
217
scripts/gen.js
|
|
@ -1,11 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('bfile');
|
||||
const Path = require('path');
|
||||
const consensus = require('../lib/protocol/consensus');
|
||||
const TX = require('../lib/primitives/tx');
|
||||
const Block = require('../lib/primitives/block');
|
||||
const Address = require('../lib/primitives/address');
|
||||
const Witness = require('../lib/script/witness');
|
||||
const Input = require('../lib/primitives/input');
|
||||
const Output = require('../lib/primitives/output');
|
||||
const util = require('../lib/utils/util');
|
||||
const rules = require('../lib/covenants/rules');
|
||||
const {types} = rules;
|
||||
|
||||
const secp256k1 = require('bcrypto/lib/secp256k1');
|
||||
const hash160 = require('bcrypto/lib/hash160');
|
||||
|
|
@ -18,6 +25,10 @@ const keyHash = hash160.digest(key);
|
|||
const ZERO_ROOT =
|
||||
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314';
|
||||
|
||||
const {HSKResource} = require('../lib/covenants/record');
|
||||
const root = require('../etc/root.json');
|
||||
const names = Object.keys(root).sort();
|
||||
|
||||
function createGenesisBlock(options) {
|
||||
let flags = options.flags;
|
||||
let addr = options.address;
|
||||
|
|
@ -70,9 +81,189 @@ function createGenesisBlock(options) {
|
|||
|
||||
block.txs.push(tx);
|
||||
|
||||
const claim = new TX({
|
||||
version: 0,
|
||||
inputs: [{
|
||||
prevout: {
|
||||
hash: tx.hash('hex'),
|
||||
index: 0
|
||||
},
|
||||
witness: new Witness(),
|
||||
sequence: 0xffffffff
|
||||
}],
|
||||
outputs: [{
|
||||
value: consensus.BASE_REWARD,
|
||||
address: addr
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
for (const name of names) {
|
||||
const output = new Output();
|
||||
output.value = 0;
|
||||
output.address = addr;
|
||||
output.covenant.type = types.CLAIM;
|
||||
output.covenant.items.push(Buffer.from(name, 'ascii'));
|
||||
claim.outputs.push(output);
|
||||
}
|
||||
|
||||
claim.refresh();
|
||||
|
||||
const register = new TX({
|
||||
version: 0,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
let i = 1;
|
||||
|
||||
for (const name of names) {
|
||||
const res = HSKResource.fromJSON(root[name]);
|
||||
|
||||
const input = Input.fromOutpoint(claim.outpoint(i));
|
||||
register.inputs.push(input);
|
||||
|
||||
const output = new Output();
|
||||
output.value = 0;
|
||||
output.address = addr;
|
||||
output.covenant.type = types.REGISTER;
|
||||
output.covenant.items.push(Buffer.from(name, 'ascii'));
|
||||
output.covenant.items.push(res.toRaw());
|
||||
register.outputs.push(output);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
register.refresh();
|
||||
|
||||
block.txs.push(claim);
|
||||
block.txs.push(register);
|
||||
block.merkleRoot = block.createMerkleRoot('hex');
|
||||
block.witnessRoot = block.createWitnessRoot('hex');
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
const tlds = require('handshake-names/build/tld');
|
||||
const record = Buffer.from('00008000', 'hex');
|
||||
|
||||
function createGenesisBlock(options) {
|
||||
let flags = options.flags;
|
||||
let addr = options.address;
|
||||
let nonce = options.nonce;
|
||||
let sol = options.solution;
|
||||
|
||||
if (!flags) {
|
||||
flags = Buffer.from(
|
||||
'01/Nov/2017 EFF to ICANN: Don\'t Pick Up the Censor\'s Pen',
|
||||
'ascii');
|
||||
}
|
||||
|
||||
if (!addr)
|
||||
addr = Address.fromHash(keyHash, 0);
|
||||
|
||||
if (!nonce)
|
||||
nonce = Buffer.alloc(16, 0x00);
|
||||
|
||||
if (!sol)
|
||||
sol = new Uint32Array(2);
|
||||
|
||||
const tx = new TX({
|
||||
version: 0,
|
||||
inputs: [{
|
||||
prevout: {
|
||||
hash: consensus.NULL_HASH,
|
||||
index: 0xffffffff
|
||||
},
|
||||
witness: new Witness([flags]),
|
||||
sequence: 0xffffffff
|
||||
}],
|
||||
outputs: [{
|
||||
value: consensus.BASE_REWARD,
|
||||
address: addr
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
const block = new Block({
|
||||
version: 0,
|
||||
prevBlock: consensus.NULL_HASH,
|
||||
merkleRoot: tx.hash('hex'),
|
||||
witnessRoot: tx.witnessHash('hex'),
|
||||
trieRoot: ZERO_ROOT,
|
||||
time: options.time,
|
||||
bits: options.bits,
|
||||
nonce: nonce,
|
||||
solution: sol
|
||||
});
|
||||
|
||||
block.txs.push(tx);
|
||||
|
||||
const claim = new TX({
|
||||
version: 0,
|
||||
inputs: [{
|
||||
prevout: {
|
||||
hash: tx.hash('hex'),
|
||||
index: 0
|
||||
},
|
||||
witness: new Witness(),
|
||||
sequence: 0xffffffff
|
||||
}],
|
||||
outputs: [{
|
||||
value: consensus.BASE_REWARD,
|
||||
address: addr
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
for (const name of tlds) {
|
||||
const output = new Output();
|
||||
output.value = 0;
|
||||
output.address = addr;
|
||||
output.covenant.type = types.CLAIM;
|
||||
output.covenant.items.push(Buffer.from(name, 'ascii'));
|
||||
claim.outputs.push(output);
|
||||
}
|
||||
|
||||
claim.refresh();
|
||||
|
||||
const register = new TX({
|
||||
version: 0,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
let i = 1;
|
||||
|
||||
for (const name of tlds) {
|
||||
const input = Input.fromOutpoint(claim.outpoint(i));
|
||||
register.inputs.push(input);
|
||||
|
||||
const output = new Output();
|
||||
output.value = 0;
|
||||
output.address = addr;
|
||||
output.covenant.type = types.REGISTER;
|
||||
output.covenant.items.push(Buffer.from(name, 'ascii'));
|
||||
output.covenant.items.push(record);
|
||||
register.outputs.push(output);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
register.refresh();
|
||||
|
||||
block.txs.push(claim);
|
||||
block.txs.push(register);
|
||||
block.merkleRoot = block.createMerkleRoot('hex');
|
||||
block.witnessRoot = block.createWitnessRoot('hex');
|
||||
|
||||
return block;
|
||||
}
|
||||
*/
|
||||
|
||||
const main = createGenesisBlock({
|
||||
time: 1514765688,
|
||||
bits: 0x207fffff,
|
||||
|
|
@ -116,33 +307,29 @@ function formatBlock(name, block) {
|
|||
};`;
|
||||
}
|
||||
|
||||
function formatRaw(name, block) {
|
||||
const str = block.toRaw().toString('hex');
|
||||
|
||||
let out = `${name}.genesisBlock = ''\n`;
|
||||
|
||||
for (let i = 0; i < str.length; i += 64)
|
||||
out += ` + '${str.slice(i, i + 64)}'\n`;
|
||||
|
||||
out = out.slice(0, -1) + ';';
|
||||
|
||||
return out;
|
||||
function toHex(block) {
|
||||
return block.toRaw().toString('hex');
|
||||
}
|
||||
|
||||
function dump(name, block) {
|
||||
const blk = formatBlock(name, block);
|
||||
const raw = formatRaw(name, block);
|
||||
|
||||
console.log(blk);
|
||||
console.log('');
|
||||
console.log(raw);
|
||||
console.log('');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
dump('main', main);
|
||||
dump('testnet', testnet);
|
||||
dump('regtest', regtest);
|
||||
dump('simnet', simnet);
|
||||
|
||||
console.log(JSON.stringify(testnet.toJSON(), null, 2));
|
||||
const file = Path.resolve(__dirname, '..', 'lib', 'protocol', 'genesis.json');
|
||||
|
||||
fs.writeFileSync(file, JSON.stringify({
|
||||
main: toHex(main),
|
||||
testnet: toHex(testnet),
|
||||
regtest: toHex(regtest),
|
||||
simnet: toHex(simnet)
|
||||
}, null, 2));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue