Alert Source Discuss
Standards Track: ERC

ERC-181: 以太坊地址的反向解析的 ENS 支持

Authors Nick Johnson <arachnid@notdot.net>
Created 2016-12-01

摘要

本 EIP 指定了一个 TLD、注册器和解析器接口,用于使用 ENS 反向解析以太坊地址。 这允许将人类可读的名称与任何以太坊区块链地址相关联。 解析器可以确定反向记录是由相关以太坊地址的所有者发布的。

动机

虽然名称服务主要用于正向解析 - 从人类可读的标识符到机器可读的标识符 - 但在许多用例中,反向解析也很有用:

  • 允许用户监控帐户的应用程序可以通过显示帐户的名称而不是其地址来受益,即使该帐户最初是按地址添加的。
  • 将描述性信息等元数据附加到地址,可以检索此信息,而无需考虑最初如何发现该地址。
  • 任何人都可以配置一个名称来解析为地址,而无需考虑该地址的所有权。 反向记录允许地址的所有者声明一个名称作为该地址的权威名称。

规范

反向 ENS 记录以与常规记录相同的方式存储在 ENS 层次结构中,位于保留域 addr.reverse 下。 要为给定帐户的反向记录生成 ENS 名称,请将该帐户转换为小写的十六进制表示形式,并附加 addr.reverse。 例如,ENS 注册表在 0x112234455c3a32fd11230c42e7bccd4a84e02010 处的地址在 112234455c3a32fd11230c42e7bccd4a84e02010.addr.reverse 处存储任何反向记录。

请注意,这意味着想要对地址进行动态反向解析的合约需要在合约中执行十六进制编码。

注册器

addr.reverse 域的所有者将是一个注册器,它允许调用者获得其自身地址的反向记录的所有权。 它提供以下方法:

function claim(address owner) returns (bytes32 node)

当由帐户 x 调用时,指示 ENS 注册表将名称 hex(x) + '.addr.reverse' 的所有权转移到提供的地址,并返回因此转移的 ENS 记录的 namehash。

允许调用者为相关节点指定除自己以外的所有者,这有助于需要准确反向 ENS 条目的合约以最少的代码在其构造函数中将其委托给其创建者:

reverseRegistrar.claim(msg.sender)

function claimWithResolver(address owner, address resolver) returns (bytes32 node)

当由帐户 x 调用时,指示 ENS 注册表将名称 hex(x) + '.addr.reverse' 的解析器设置为指定的解析器,然后将名称的所有权转移到提供的地址,并返回因此转移的 ENS 记录的 namehash。 此方法有助于设置自定义解析器和所有者,所需的事务比调用 claim 时所需的事务更少。

function setName(string name) returns (bytes32 node)

当由帐户 x 调用时,将名称 hex(x) + '.addr.reverse' 的解析器设置为默认解析器,并将该名称上的名称记录设置为指定的名称。 此方法有助于在单个事务中为用户设置简单的反向记录。

解析器接口

定义了一个新的解析器接口,包括以下方法:

function name(bytes32 node) constant returns (string);

实现此接口的解析器必须为请求的节点返回有效的 ENS 名称,如果未为请求的节点定义任何名称,则返回空字符串。

此接口的接口 ID 为 0x691f3431。

未来的 EIP 可能会指定更适合反向 ENS 记录的记录类型。

附录 1:注册器实现

此注册器是用 Solidity 编写的,实现了上面概述的规范。

pragma solidity ^0.4.10;

import "./AbstractENS.sol";

contract Resolver {
    function setName(bytes32 node, string name) public;
}

/**
 * @dev Provides a default implementation of a resolver for reverse records,
 * 为反向记录提供解析器的默认实现,
 * which permits only the owner to update it.
 * 它只允许所有者更新它。
 */
contract DefaultReverseResolver is Resolver {
    AbstractENS public ens;
    mapping(bytes32=>string) public name;

    /**
     * @dev Constructor
     * @dev 构造函数
     * @param ensAddr The address of the ENS registry.
     * @param ensAddr ENS 注册表的地址。
     */
    function DefaultReverseResolver(AbstractENS ensAddr) {
        ens = ensAddr;
    }

    /**
     * @dev Only permits calls by the reverse registrar.
     * @dev 仅允许反向注册器调用。
     * @param node The node permission is required for.
     * @param node 需要节点权限。
     */
    modifier owner_only(bytes32 node) {
        require(msg.sender == ens.owner(node));
        _;
    }

    /**
     * @dev Sets the name for a node.
     * @dev 设置节点的名称。
     * @param node The node to update.
     * @param node 要更新的节点。
     * @param _name The name to set.
     * @param _name 要设置的名称。
     */
    function setName(bytes32 node, string _name) public owner_only(node) {
        name[node] = _name;
    }
}

contract ReverseRegistrar {
    // namehash('addr.reverse')
    bytes32 constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;

    AbstractENS public ens;
    Resolver public defaultResolver;

    /**
     * @dev Constructor
     * @dev 构造函数
     * @param ensAddr The address of the ENS registry.
     * @param ensAddr ENS 注册表的地址。
     * @param resolverAddr The address of the default reverse resolver.
     * @param resolverAddr 默认反向解析器的地址。
     */
    function ReverseRegistrar(AbstractENS ensAddr, Resolver resolverAddr) {
        ens = ensAddr;
        defaultResolver = resolverAddr;
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     * @dev 转移与调用帐户关联的反向 ENS 记录的所有权。
     *      calling account.
     *      调用帐户。
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param owner 要设置为 ENS 中反向记录所有者的地址。
     * @return The ENS node hash of the reverse record.
     * @return 反向记录的 ENS 节点哈希。
     */
    function claim(address owner) returns (bytes32 node) {
        return claimWithResolver(owner, 0);
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     * @dev 转移与调用帐户关联的反向 ENS 记录的所有权。
     *      calling account.
     *      调用帐户。
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param owner 要设置为 ENS 中反向记录所有者的地址。
     * @param resolver The address of the resolver to set; 0 to leave unchanged.
     * @param resolver 要设置的解析器的地址;0 表示不更改。
     * @return The ENS node hash of the reverse record.
     * @return 反向记录的 ENS 节点哈希。
     */
    function claimWithResolver(address owner, address resolver) returns (bytes32 node) {
        var label = sha3HexAddress(msg.sender);
        node = sha3(ADDR_REVERSE_NODE, label);
        var currentOwner = ens.owner(node);

        // Update the resolver if required
        // 如果需要,更新解析器
        if(resolver != 0 && resolver != ens.resolver(node)) {
            // Transfer the name to us first if it's not already
            // 如果名称尚未转移给我们,则先转移给我们
            if(currentOwner != address(this)) {
                ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, this);
                currentOwner = address(this);
            }
            ens.setResolver(node, resolver);
        }

        // Update the owner if required
        // 如果需要,更新所有者
        if(currentOwner != owner) {
            ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);
        }

        return node;
    }

    /**
     * @dev Sets the `name()` record for the reverse ENS record associated with
     * @dev 设置与调用帐户关联的反向 ENS 记录的 `name()` 记录。
     * the calling account. First updates the resolver to the default reverse
     * 调用帐户。 如果需要,首先将解析器更新为默认反向解析器。
     * resolver if necessary.
     * @param name The name to set for this address.
     * @param name 要为此地址设置的名称。
     * @return The ENS node hash of the reverse record.
     * @return 反向记录的 ENS 节点哈希。
     */
    function setName(string name) returns (bytes32 node) {
        node = claimWithResolver(this, defaultResolver);
        defaultResolver.setName(node, name);
        return node;
    }

    /**
     * @dev Returns the node hash for a given account's reverse records.
     * @dev 返回给定帐户的反向记录的节点哈希。
     * @param addr The address to hash
     * @param addr 要哈希的地址
     * @return The ENS node hash.
     * @return ENS 节点哈希。
     */
    function node(address addr) constant returns (bytes32 ret) {
        return sha3(ADDR_REVERSE_NODE, sha3HexAddress(addr));
    }

    /**
     * @dev An optimised function to compute the sha3 of the lower-case
     * @dev 一个优化函数,用于计算以太坊地址的小写
     *      hexadecimal representation of an Ethereum address.
     *      十六进制表示的 sha3。
     * @param addr The address to hash
     * @param addr 要哈希的地址
     * @return The SHA3 hash of the lower-case hexadecimal encoding of the
     * @return 输入地址的小写十六进制编码的 SHA3 哈希。
     *         input address.
     */
    function sha3HexAddress(address addr) private returns (bytes32 ret) {
        addr; ret; // Stop warning us about unused variables
        // 停止警告我们关于未使用的变量
        assembly {
            let lookup := 0x3031323334353637383961626364656600000000000000000000000000000000
            let i := 40
        loop:
            i := sub(i, 1)
            mstore8(i, byte(and(addr, 0xf), lookup))
            addr := div(addr, 0x10)
            i := sub(i, 1)
            mstore8(i, byte(and(addr, 0xf), lookup))
            addr := div(addr, 0x10)
            jumpi(loop, i)
            ret := sha3(0, 40)
        }
    }
}

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Nick Johnson <arachnid@notdot.net>, "ERC-181: 以太坊地址的反向解析的 ENS 支持," Ethereum Improvement Proposals, no. 181, December 2016. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-181.