If you’re looking at using the Ethereum Name Service inside your application or contract, or wanting to build something on top of ENS like a registrar or resolver, this post will give you the background you need to get started.

ENS’s three components

ENS is constructed from three primary components: the registry, registrars, and resolvers.

The registry is the central directory of ENS; it keeps a list of every ENS domain (and subdomain, and sub-sub-domain, and so forth).

Every name in ENS can be found by looking it up in the ENS registry, and it’s the only component you need the address for.

The registry maintains three pieces of information about every name it knows about:

The account that owns the name (owner). The address of an (optional) resolver contract. A time-to-live for caching.

Names can be owned by external accounts or by contracts. When a contract owns a name, we call that contract a registrar.

Registrars are the second component of ENS, and are responsible for allocating new names to users. The best known of these is the .eth registrar, but anyone who owns a domain can assign ownership to a contract and create a registrar of their own. Registrars don’t have any special permissions — they just use their ability to tell the registry to create subdomains.

Resolvers are contracts that can tell you the resource associated with a name — such as an Ethereum address, a swarm hash, or a public key. Anyone can implement a resolver, as long as it implements a certain agreed-upon interface, and point their domain at it. For convenience, there are ‘public’ resolvers that anyone can point their domain at and use.

Looking up names in ENS

Looking up an ENS name is a two-step process. First, call the ENS registry’s resolver method, to fetch the address of the resolver responsible for the name. Then, ask that resolver for the resource you’re interested in.

For instance, to look up the Ethereum address of ‘vitalik.eth’, we’d first call resolver(namehash('vitalik.eth')) on the registry, then we’d call addr(namehash('vitalik.eth')) on the resolver whose address was returned by the first call. If we wanted the swarm hash for ‘vitalik.eth’ instead, the first step would remain the same, but in the second step we’d call content(namehash('vitalik.eth')) on the resolver.

namehash

ENS does not operate directly on names — there are a number of reasons for this, one of which is that parsing and processing text on the blockchain is very inefficient. Instead, ENS operates on secure hashes.

A single component of a name — eg, vitalik or eth can be simply hashed using keccak256 (commonly referred to as sha3 in Ethereum). We call the result a ‘label hash’ or just ‘label’.

Because ENS is a hierarchal system, however, we need some way to represent hierarchal names. We cannot simply hash the whole name — eg, sha3('vitalik.eth') because there would be no way to answer questions like “is vitalik.eth a subdomain of eth ?" or “what is the hash of the ‘wallet’ subdomain of this domain?”

To solve this, ENS hashes names using a system called namehash . Here’s the full definition of namehash:

namehash('') -> '0x0000000000000000000000000000000000000000000000000000000000000000'

namehash('a.xyz') -> sha3(namehash('xyz'), sha3('a'))

Namehash is thus a recursive function: to calculate the final hash, you start with the rightmost component, and repeatedly calculate the label hash, then combine it with the previous component’s name hash.

Usually, you won’t need to concern yourself with the internal details of namehash — ENS libraries will handle it for you, and you can look at it as a black box that turns names into hashes.

Resources

The ENS repository contains source code for all the primary components of ENS.

The ENS documentation goes into a lot more detail about concepts and API functionality, with practical details and examples.

EIP 137 defines ENS in full, and provides references to the different resolver profiles currently defined.