The Ethereum Name Service (ENS)

ENS is more than a smart contract; it’s a fundamental DApp itself, offering a decentralized name service.

  • It’s built to serve other DApps, supported by an ecosystem of DApps, embedded in other DApps.

ENS is specified mainly in three Ethereum Improvement Proposals:

  • EIP-137 specifies the basic functions of ENS;
  • EIP-162 describes the auction system for the .eth root;
  • EIP-181 specifies reverse registration of addresses.

ENS follows a “sandwich” design philosophy: a very simple layer on the bottom, followed by layers of more complex but replaceable code, with a very simple top layer that keeps all the funds in separate accounts.

Bottom Layer: Name Owners and Resolvers

The ENS operates on “nodes” instead of human-readable names: a human-readable name is converted to a node using the “Namehash” algorithm.

The base layer of ENS is a cleverly simple contract (less than 50 lines of code) defined by ERC137 that allows only nodes’ owners to set information about their names and to create subnodes (the ENS equivalent of DNS subdomains).

  • The only functions on the base layer are those that enable a node owner to set information about their own node (specifically the resolver, time to live, or transferring the ownership) and to create owners of new subnodes.

Namehash recursively hashes components of the name, producing a unique, fixed length string (or “node”) for any valid input domain.

  • To avoid expensive recomputation, since Namehash depends only on the name itself, the node for a given name can be precomputed and inserted into a contract, removing the need for string manipulation and permitting immediate lookup of ENS records regardless of the number of components in the raw name.
  • Names consist of a series of dot-separated labels.
    • Although upper- and lowercase letters are allowed, all labels should follow a UTS #46 normalization process that casefolds labels before hashing them, so names with different case but identical spelling will end up with the same Namehash.

Demonstration:

  • The Namehash node of subdomain.example.eth: keccak('<example.eth>' node) + keccak('<subdomain>')
  • The subproblem we must solve is to compute the node for example.eth: keccak('<.eth>' node) + keccak('<example>')
  • Compute the node for eth: keccak(<root node>) + keccak('<eth>')
    • The root node is the “base case” of the recursion, defined as 0x0000000000000000000000000000000000000000000000000000000000000000 (32 zero bytes).
  • keccak(keccak(('\0' * 32) + keccak('eth')) + keccak('mastering-ethereum'))
# https://go.dev/play/p/c-noevktq_7
def namehash(name):
    if name == '':
        return '\0' * 32
    else:
        label, _, remainder = name.partition('.')
        return sha3(namehash(remainder) + sha3(label))

The basic ENS contract can’t add metadata to names; that is the job of so-called “resolver contracts.”

  • These are user-created contracts that can answer questions about the name, such as what Swarm address is associated with the app, what address receives payments to the app (in ether or tokens), or what the hash of the app is (to verify its integrity).

Middle Layer: The .eth Nodes

.eth domains are distributed via an auction system.

  • There is no reserved list or priority, and the only way to acquire a name is to use the system.
  • The auction system is a complex piece of code that is replaceable and upgradeable, without risk to the funds.

Names are distributed via a modified Vickrey auction.

  • In a traditional Vickrey auction, every bidder submits a sealed bid, and all of them are revealed simultaneously, at which point the highest bidder wins the auction but only pays the second-highest bid.
    • Therefore bidders are incentivized not to bid less than the true value of the name to them, since bidding their true value increases the chance they will win but does not affect the price they will eventually pay.
  • On a blockchain, some changes are required:
    • To ensure bidders don’t submit bids they have no intention of paying, they must lock up a value equal to or higher than their bid beforehand, to guarantee the bid is valid.
    • Because you can’t hide secrets on a blockchain, bidders must execute at least two transactions (a commit–reveal process), in order to hide the original value and name they bid on.
    • Since you can’t reveal all bids simultaneously in a decentralized system, bidders must reveal their own bids themselves; if they don’t, they forfeit their locked-up funds.
      • Without this forfeit, one could make many bids and choose to reveal only one or two, turning a sealed-bid auction into a traditional increasing price auction.

Top Layer: The Deeds

The top layer of ENS is yet another super-simple contract with a single purpose: to hold the funds.

When you win a name, the funds are not actually sent anywhere, but are just locked up for the period you want to hold the name (at least a year).

  • This works like a guaranteed buyback: if the owner does not want the name any more they can sell it back to the system and recover their ether.
  • Having a single contract hold millions of dollars in ether has proven to be very risky, so instead ENS creates a deed contract for each new name.
    • The deed contract is very simple (about 50 lines of code), and it only allows the funds to be transferred back to a single account (the deed owner) and to be called by a single entity (the registrar contract).
    • This approach drastically reduces the attack surface where bugs can put the funds at risk.

References

  • Mastering Ethereum by Andreas M. Antonopoulos and Dr. Gavin Wood (O’Reilly). Copyright 2019 The Ethereum Book LLC and Gavin Wood, 978-1-491-97194-9