abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
    mapping(bytes32=>bytes) hashes;

    /**
     * Sets the contenthash associated with an ENS node.
     * May only be called by the owner of that node in the ENS registry.
     * @param node The node to update.
     * @param hash The contenthash to set
     */
    function setContenthash(bytes32 node, bytes calldata hash) virtual external authorised(node) {
        hashes[node] = hash;
        emit ContenthashChanged(node, hash);
    }

    /**
     * Returns the contenthash associated with an ENS node.
     * @param node The ENS node to query.
     * @return The associated contenthash.
     */
    function contenthash(bytes32 node) virtual external override view returns (bytes memory) {
        return hashes[node];
    }

    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
        return interfaceID == type(IContentHashResolver).interfaceId || super.supportsInterface(interfaceID);
    }
}
function setContenthash(bytes32 node, bytes calldata hash) virtual external authorised(node) {
    hashes[node] = hash;
    emit ContenthashChanged(node, hash);
}

/**
 * Sets the contenthash associated with an ENS node.
 * May only be called by the owner of that node in the ENS registry.
 * @param node The node to update.
 * @param hash The contenthash to set
 */