|Author||Felix Lange, Péter Szilágyi|
This document describes a scheme for authenticated, updateable Ethereum node lists retrievable via DNS.
Many Ethereum clients contain hard-coded bootstrap node lists. Updating those lists requires a software update. The current lists are small, giving the client little choice of initial entry point into the Ethereum network. We would like to maintain larger node lists containing hundreds of nodes, and update them regularly.
The scheme described here is a replacement for client bootstrap node lists with equivalent security and many additional benefits. DNS node lists may also be useful to Ethereum peering providers because their customers can configure the client to use the provider’s list. Finally, the scheme serves as a fallback option for nodes which can’t join the node discovery DHT.
DNS Record Structure
Node lists are encoded as TXT records. The records form a merkle tree. The root of the tree is a record with content:
enrtree-root=v1 hash=<roothash> seq=<seqnum> sig=<signature>
roothash is the abbreviated root hash of the tree in base32 encoding.
is the tree’s update sequence number, a decimal integer.
signature is a
65-byte secp256k1 EC signature over the keccak256 hash of the record content,
encoded as URL-safe base64.
Further TXT records on subdomains map hashes to one of three entry types. The subdomain name of any entry is the base32 encoding of the abbreviated keccak256 hash of its text content.
enrtree=<h₁>,<h₂>,...,<hₙ>is an intermediate tree containing further hash subdomains.
enrtree-link=<key>@<fqdn>is a leaf pointing to a different list located at another fully qualified domain name. The key is the expected signer of the remote list, a base32 encoded secp256k1 public key,
enr=<node-record>is a leaf containing a node record as defined in EIP-778. The node record is encoded as a URL-safe base64 string.
No particular ordering or structure is defined for the tree. Whenever the tree
is updated, its sequence number should increase. The content of any TXT record
should be small enough to fit into the 512 byte limit imposed on UDP DNS
packets. This limits the number of hashes that can be placed into a
Example in zone file format:
; name ttl class type content @ 60 IN TXT "enrtree-root=v1 hash=TO4Q75OQ2N7DX4EOOR7X66A6OM seq=3 sig=N-YY6UB9xD0hFx1Gmnt7v0RfSxch5tKyry2SRDoLx7B4GfPXagwLxQqyf7gAMvApFn_ORwZQekMWa_pXrcGCtwE=" TO4Q75OQ2N7DX4EOOR7X66A6OM 86900 IN TXT "enrtree=F4YWVKW4N6B2DDZWFS4XCUQBHY,JTNOVTCP6XZUMXDRANXA6SWXTM,JGUFMSAGI7KZYB3P7IZW4S5Y3A" F4YWVKW4N6B2DDZWFS4XCUQBHY 86900 IN TXT "enr=-H24QI0fqW39CMBZjJvV-EJZKyBYIoqvh69kfkF4X8DsJuXOZC6emn53SrrZD8P4v9Wp7NxgDYwtEUs3zQkxesaGc6UBgmlkgnY0gmlwhMsAcQGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOA==" JTNOVTCP6XZUMXDRANXA6SWXTM 86900 IN TXT "enr=-H24QDquAsLj8mCMzJh8ka2BhVFg3n4V9efBJBiaXHcoL31vRJJef-lAseMhuQBEVpM_8Zrin0ReuUXJE7Fs8jy9FtwBgmlkgnY0gmlwhMYzZGOJc2VjcDI1NmsxoQLtfC0F55K2s1egRhrc6wWX5dOYjqla-OuKCELP92O3kA==" JGUFMSAGI7KZYB3P7IZW4S5Y3A 86900 IN TXT "enr[email protected]morenodes.example.org"
Referencing Trees by URL
When referencing a record tree, e.g. in source code, the preferred form is a
URL. References should use the scheme
enrtree:// and encode the DNS domain in
the hostname. The expected public key that signs the tree should be encoded in
33-byte compressed form as a base32 string in the username portion of the URL.
To find nodes at a given DNS name, say “mynodes.org”:
- Resolve the TXT record of the name and check whether it contains a valid “enrtree-root=v1” entry. Let’s say the root hash contained in the entry is “CFZUWDU7JNQR4VTCZVOJZ5ROV4”.
- Optionally verify the signature on the root against a known public key and check whether the sequence number is larger than or equal to any previous number seen for that name.
- Resolve the TXT record of the hash subdomain, e.g. “CFZUWDU7JNQR4VTCZVOJZ5ROV4.mynodes.org” and verify whether the content matches the hash.
- The next step depends on the entry type found:
enrtree: parse the list of hashes and continue resolving those (step 3).
enrtree-link: continue traversal on the linked domain (step 1).
enr: decode, verify the node record and import it to local node storage.
During traversal, the client should track hashes and domains which are already resolved to avoid going into an infinite loop.
We have chosen DNS as the distribution medium because it is always available, even under restrictive network conditions. The protocol provides low latency and answers to DNS queries can be cached by intermediate resolvers. No custom server software is needed. Node lists can be deployed to any DNS provider such as CloudFlare DNS, dnsimple, Amazon Route 53 using their respective client libraries.
Why is this a merkle tree?
Being a merkle tree, any node list can be authenticated by a single signature on the root. Hash subdomains protect the integrity of the list. At worst intermediate resolvers can block access to the list or disallow updates to it, but cannot corrupt its content. The sequence number prevents replacing the root with an older version.
Synchronizing updates on the client side can be done incrementally, which matters for large lists. Individual entries of the tree are small enough to fit into a single UDP packet, ensuring compatibility with environments where only basic UDP DNS is available. The tree format also works well with caching resolvers: only the root of the tree needs a short TTL. Intermediate entries and leaves can be cached for days.
Links between lists enable federation and web-of-trust functionality. The operator of a large list can delegate maintenance to other list providers. If two node lists link to each other, users can use either list and get nodes from both.
- The base64 and base32 encodings used to represent binary data are defined in RFC 4648 (https://tools.ietf.org/html/rfc4648). No padding is used for base32.
Copyright and related rights waived via CC0.