-
Notifications
You must be signed in to change notification settings - Fork 15
Document Introductory ENSRainbow Topics #1513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
djstrong
wants to merge
35
commits into
main
Choose a base branch
from
932-refine-ensrainbow-docs3
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
2006959
feat: add CSV conversion command to ensrainbow CLI
djstrong b491441
refactor
djstrong 4c18e0b
Create brave-kiwis-notice.md
djstrong 5aefe9d
fix tests
djstrong f2c8f20
use fast-csv package
djstrong e20932d
add documentation for csv convert
djstrong b9c31b0
feat: add filtering capabilities to CSV conversion
djstrong e2b9255
feat: enhance CSV conversion with Bloom filter and deduplication options
djstrong 2c94d41
refactor: simplify command options in package.json
djstrong 721a50d
refactor: improve memory management and logging in CSV conversion
djstrong 56bc356
refactor: streamline CSV conversion CLI options and improve logging
djstrong 11992d7
fix: improve error handling and logging in CSV conversion tests
djstrong 3dea60e
refactor: update CSV conversion logic and improve deduplication handling
djstrong b6c668a
Merge branch 'main' into csv-conversion-tool
djstrong 42c06a1
Enhance documentation for label sets and versions across various file…
djstrong 73376a7
Update environment variable documentation and improve comments in scr…
djstrong 62d87a5
Update glossary with environment variable definitions and enhance des…
djstrong e954fa1
Update terminology documentation to clarify the definition of LabelHa…
djstrong b58612b
Enhance documentation by adding glossary references for the term "hea…
djstrong f540f70
Enhance documentation by adding glossary references for "rainbow reco…
djstrong 6946cc1
Refine glossary documentation by correcting formatting for LABEL_SET_…
djstrong 25e03d9
Update glossary and Terraform variable descriptions to correct label …
djstrong ebb03ff
Fix labelhash glossary URL in types.ts
djstrong 57836ed
Create fifty-spies-call.md
djstrong 9d7b12b
Enhance ENSRainbow documentation by adding detailed instructions for …
djstrong 11d656b
Merge branch 'main' into 932-refine-ensrainbow-docs
djstrong 3cbfaef
Remove unnecessary code block from creating-files documentation
djstrong dd757b7
Merge branch 'main' into 932-refine-ensrainbow-docs
djstrong 1abee90
chore: update documentation links to use absolute URLs and remove unu…
djstrong dee381c
docs: add comprehensive section on unknown labels in ENS and link to …
djstrong 8380a38
Merge branch 'main' into 932-refine-ensrainbow-docs3
djstrong ea5399a
Create lucky-eagles-hammer.md
djstrong 5be838f
Apply suggestions from code review
djstrong 7c1587a
Update sidebar order for multiple ENSRainbow documentation pages to i…
djstrong f0cc0b1
Merge branch 'main' into 932-refine-ensrainbow-docs3
djstrong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@docs/ensnode": patch | ||
| --- | ||
|
|
||
| Document Introductory ENSRainbow Topics |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
docs/ensnode.io/src/content/docs/ensrainbow/concepts/unknown-labels.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| --- | ||
| title: Unknown Labels | ||
| description: Understanding the fundamental problem of unknown labels in ENS and how ENSRainbow mitigates it. | ||
| sidebar: | ||
| label: Unknown Labels | ||
| order: 2 | ||
djstrong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| keywords: [ensrainbow, unknown labels, labelhash, healing, rainbow tables, keccak256] | ||
| --- | ||
|
|
||
| ## The Problem: Unknown Labels | ||
|
|
||
| When querying indexed ENS names, you may encounter labels represented as [**Encoded LabelHashes**](/docs/reference/terminology#encoded-labelhash) like `[428...b0b]` instead of human-readable strings. | ||
|
|
||
| An **Unknown Label** is a [**Label**](/ensrainbow/concepts/glossary#label) that is known to exist, but where only the [**LabelHash**](/ensrainbow/concepts/glossary#labelhash) of the label is known, not the human-readable string. These unknown labels are represented by ENS indexers as encoded labelhashes using the format `[{LabelHash}]`. | ||
|
|
||
| Unknown labels are an unfortunate user experience issue in the ENS ecosystem. They can make names difficult to read, understand, and work with in applications. | ||
|
|
||
| ENSRainbow serves the goal of minimizing the number of unknown labels that exist, and therefore minimizing the probability that users experience interacting with them. | ||
|
|
||
| ### Format: Encoded LabelHash | ||
|
|
||
| When an unknown label is encountered, it is represented as an **Encoded LabelHash** in the format `[{labelhash}]`, where `{labelhash}` is the 64-character hexadecimal representation of the labelhash (without the `0x` prefix). | ||
|
|
||
| **Examples:** | ||
djstrong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - `vitalik.eth` — a normalized name with known labels | ||
| - `[731f7025b488151de311c24abc1f27f02940bde412246fbdb3dea0d4f0663b22].eth` — a name with an unknown label encoded as a labelhash, followed by the known label `eth` | ||
| - `[731f7025b488151de311c24abc1f27f02940bde412246fbdb3dea0d4f0663b22].[af2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc].eth` — a name with multiple unknown labels, each encoded as a labelhash | ||
|
|
||
| **Important:** Labels formatted as encoded labelhashes need to be carefully interpreted depending on the context as either [**literal labels**](/docs/reference/terminology/#literal-label) or [**interpreted labels**](/docs/reference/terminology/#interpreted-label). ENSNode (unlike the ENS Subgraph) guarantees that all labels it returns are interpreted labels so long as ENSNode's `SUBGRAPH_COMPAT` is not activated (off by default). | ||
|
|
||
| ## What Causes Unknown Labels? | ||
|
|
||
| Unknown labels arise from the fundamental design of the ENS protocol: | ||
|
|
||
| ### The ENS Registry Design | ||
|
|
||
| Unknown labels are a consequence of the ENS Registry not emitting the actual label in events when subnames are created. Only the labelhash is emitted. | ||
|
|
||
| **Understanding the distinction:** | ||
| - The ENS Registry contract ([`ENSRegistryWithFallback`](https://etherscan.io/address/0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e#code)) stores only the **node** for each registered name (the node is a 32-byte hash computed via `namehash`) | ||
| - **However**, indexers don't generally read what's stored on-chain—they read the data from **events** emitted by contracts | ||
| - The problem for indexers emerges from what's emitted in events, not what's stored | ||
|
|
||
| **The root cause:** All subnames are created by calling the [`setSubnodeOwner`](https://etherscan.io/address/0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e#code#F1#L84) function on the Registry contract. When this happens, the Registry emits a `NewOwner` event for the newly created subname. However, this event contains a parameter misleadingly named `label` that is **not actually the label string**—it's the **labelhash** of the new subname's label: | ||
|
|
||
| ```solidity | ||
| event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); | ||
| // ^^^^^ This is actually a labelhash, not a label! | ||
| ``` | ||
|
|
||
| **The critical issue:** When a subname is added to the Registry, the Registry doesn't emit the label of the newly created subname—only the labelhash of the new subname's label. This means: | ||
|
|
||
| 1. **Indexers only receive labelhashes**: When indexers listen to `NewOwner` events, they can only discover the labelhash, not the human-readable label | ||
| 2. **Contracts that wrap the Registry** (like `ETHRegistrarController` or `NameWrapper`) can emit additional events with the actual label string, making labels discoverable to indexers | ||
| 3. **Direct Registry calls** from contracts that don't wrap the Registry and emit the label separately will result in unknown labels for indexers | ||
| 4. **Historical data** from before label emission was standardized may not include label information | ||
|
|
||
| ### Shadow Registries | ||
|
|
||
| The unknown label problem also impacts **Shadow Registries**, which are essentially clones of the "root" ENS Registry deployed on other chains. These are part of projects such as: | ||
|
|
||
| - **Basenames** on Base | ||
| - **Lineanames** on Linea | ||
| - Other ENS-compatible naming systems on L2s and alternative chains | ||
|
|
||
| Shadow Registries inherit the same architectural design as the original ENS Registry, meaning they also only emit labelhashes (not labels) in their events. This means unknown labels are a challenge across the entire ecosystem of ENS-compatible naming systems, not just on Ethereum mainnet. | ||
|
|
||
| ### When Labels Can Be Made Known | ||
|
|
||
| In many cases, the labels that make up a name can be made **known** through several strategies: | ||
|
|
||
| - **Contract events**: Some contracts (like `ETHRegistrarController` or `NameWrapper`) emit the human-readable label in their events | ||
| - **[Rainbow table](/ensrainbow/concepts/glossary#rainbow-table) lookups**: The human-readable label for a given labelhash can be determined via customizable and massive rainbow table lookups through ENSRainbow | ||
| - **Heuristics for addr.reverse**: ENSNode uses specialized heuristics that heal 100% of subnames under `addr.reverse`, which represent reverse ENS records | ||
| - **Intelligent expansion strategies**: ENSNode has implemented strategies to intelligently expand the set of rainbow tables in ENSRainbow over time, ensuring healing coverage improves continuously | ||
|
Comment on lines
+72
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid absolute “100%” claim unless guaranteed. 🤖 Prompt for AI Agents |
||
|
|
||
| ENSNode uses a number of these strategies in combination to heal unknown labels. However, if none of these methods succeed, the label remains unknown and must be represented as an encoded labelhash. | ||
|
|
||
| ## Why Unknown Labels Are Forever a Consideration | ||
|
|
||
| Unknown labels are a **permanent architectural constraint** of the ENS protocol, not a temporary issue that can be fully eliminated. Here's why: | ||
|
|
||
| ### 1. Protocol Design Immutability | ||
|
|
||
| The ENS Registry contract is immutable—it cannot be changed or upgraded. The design decision to emit only labelhashes (not labels) in `NewOwner` events is permanent. | ||
|
|
||
| ### 2. Cryptographic One-Way Function | ||
|
|
||
| The [**labelhash**](/ensrainbow/concepts/glossary#labelhash) function computes a 32-byte hash of a label using `keccak256`: | ||
|
|
||
| ```typescript | ||
| import { labelhash } from 'viem'; | ||
| const labelHash = labelhash("vitalik"); | ||
| // Returns: 0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc | ||
| ``` | ||
|
|
||
| `keccak256` is a cryptographic hash function that is **one-way**: | ||
|
|
||
| - Given a label, you can compute its labelhash: `labelhash("vitalik") → 0xaf2c...` | ||
| - Given a labelhash, you **cannot** reverse it to get the original label: `0xaf2c... → ???` | ||
|
|
||
| This means that without external knowledge (rainbow tables, event logs, etc.), a labelhash cannot be converted back to its original label. This one-way property is exactly why rainbow tables—and ENSRainbow—are necessary. | ||
|
|
||
| ### 3. Ongoing Subname Creation | ||
|
|
||
| New subnames continue to be created on-chain. While many modern contracts emit label information in events, the protocol itself does not guarantee this. | ||
|
|
||
| ## How Unknown Labels Influence Indexing | ||
|
|
||
| Unknown labels impact how ENS data is indexed and queried: | ||
|
|
||
| ### Indexing Process | ||
|
|
||
| When ENSNode indexes onchain events where a subname is created in the ENS Registry: | ||
|
|
||
| 1. **The labelhash is always known** from the onchain event data | ||
| 2. **The label may be unknown** if it wasn't emitted in the event | ||
| 3. **ENSRainbow lookup is attempted**: ENSNode attempts to lookup the label for the labelhash through an attached ENSRainbow server | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 4. **Representation decision**: | ||
| - If the lookup succeeds: ENSNode represents the subname using its true label | ||
| - If the lookup fails: ENSNode represents the "unknown label" using its labelhash in the format `[labelhash]` | ||
|
|
||
| ### Label Mutability Over Time | ||
|
|
||
| The representation of labels can change over time as ENSRainbow's healing capabilities improve: | ||
|
|
||
| - **Time 1**: ENSRainbow cannot heal label X → label is represented as `[labelhash]` | ||
| - **Time 2**: ENSRainbow gains the ability to heal label X → label transitions from unknown to known | ||
|
|
||
| This mutability means that: | ||
| - Label representations should not be used as immutable identifiers | ||
| - The node (computed via `namehash`) should always be used as the stable identifier for querying | ||
| - For deterministic results, pin healing to a specific label set ID + version (see [Label Sets & Versioning](/ensrainbow/concepts/label-sets-and-versioning)) | ||
|
|
||
| ### Subgraph-Unindexable Labels | ||
|
|
||
| The legacy ENS Subgraph specifies that **Unknown Labels** and labels containing certain UTF-8 characters are "invalid" or "subgraph-unindexable". These include: | ||
|
|
||
| 1. `\0` (null byte) - PostgreSQL does not allow storing this character in text fields | ||
| 2. `.` (period) - Conflicts with ENS label separator logic | ||
| 3. `[` (left square bracket) - Conflicts with "unknown label" representations | ||
| 4. `]` (right square bracket) - Conflicts with "unknown label" representations | ||
|
|
||
| In ENSNode's default *Interpreted Labels* mode (`SUBGRAPH_COMPAT=false`), when a `subgraph-unindexable` label is encountered, it will be represented as an **Encoded LabelHash** even if the actual label data is available. This simplifies handling for many edge cases. | ||
|
|
||
| ## How Unknown Labels Influence Apps and User Interfaces | ||
|
|
||
| Unknown labels create challenges for applications building on ENS: | ||
|
|
||
| ### Display Challenges | ||
|
|
||
| Apps must support the possibility of needing to display names containing unknown labels / encoded labelhashes. | ||
|
|
||
| ### Querying Challenges | ||
djstrong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Unknown labels create different challenges depending on which API you're using: | ||
|
|
||
| **Subgraph-compatible GraphQL APIs (ENS Subgraph & ENSNode's `/subgraph` endpoint):** | ||
|
|
||
| When querying ENSNode's Subgraph-compatible GraphQL API or the legacy ENS Subgraph: | ||
|
|
||
| 1. **Use nodes, not names**: Always use the node (computed via `namehash`) as the stable identifier, not the name string | ||
| 2. **Normalization awareness**: When querying from user input, normalize first; when querying from onchain data, don't normalize | ||
| 3. **Encoded LabelHash-aware namehash**: Use implementations like [viem's namehash](https://github.com/wevm/viem/blob/fe558fdef7e2e9cd5f3f57d8bdeae0c7ff67a1b0/src/utils/ens/namehash.ts#L36-L51) that handle encoded labelhashes correctly | ||
|
|
||
| **ENSNode's Resolution API:** | ||
|
|
||
| ENSNode's Resolution API (accessed via the `ENSNodeClient` SDK) accepts names directly without requiring you to compute the node (namehash) yourself. However, you must still normalize the name before passing it to the API. The key difference is that you don't need to manually compute the namehash - you can call methods like `resolveRecords(normalizedName, selection)` directly with the name string. | ||
|
|
||
| ## The Solution: How ENSRainbow Works | ||
|
|
||
| ENSRainbow mitigates the unknown labels problem by providing a **[healing](/ensrainbow/concepts/glossary#heal) service** that converts labelhashes back to human-readable labels via [rainbow table](/ensrainbow/concepts/glossary#rainbow-table) lookups. | ||
|
|
||
| ### What is Healing? | ||
|
|
||
| [**Healing**](/ensrainbow/concepts/glossary#heal) is the act of converting a labelhash back to its original label via a rainbow table lookup. ENSRainbow maintains pre-computed mappings of `labelhash → label` pairs (called [rainbow records](/ensrainbow/concepts/glossary#rainbow-record)) that enable this reverse lookup. | ||
|
|
||
| ### How ENSRainbow Works | ||
|
|
||
| ENSRainbow operates as a **sidecar service** to ENSNode: | ||
|
|
||
| 1. **[Rainbow Table](/ensrainbow/concepts/glossary#rainbow-table) Storage**: ENSRainbow maintains LevelDB databases containing millions of labelhash-to-label mappings | ||
| 2. **HTTP API**: Provides a lightweight HTTP API (`GET /v1/heal/{labelhash}`) that returns the corresponding label if found (optionally scoped via `label_set_id` and `label_set_version` query parameters) | ||
| 3. **Integration with ENSNode**: During indexing, ENSNode automatically queries ENSRainbow when it encounters an unknown labelhash | ||
| 4. **Deterministic Healing**: Uses label set IDs and versions to ensure deterministic healing across time | ||
|
|
||
| ### Healing Process | ||
|
|
||
| When ENSNode encounters an unknown label during indexing: | ||
|
|
||
| ```typescript | ||
| // 1. ENSNode encounters labelhash: 0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc | ||
| // 2. ENSNode queries ENSRainbow: GET /v1/heal/0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc | ||
| // 3. ENSRainbow looks up in rainbow table | ||
| // 4. If found: Returns { "status": "success", "label": "vitalik" } | ||
| // 5. ENSNode stores the name as "vitalik.eth" instead of "[af2c...].eth" | ||
| ``` | ||
|
|
||
| ### Coverage and Limitations | ||
|
|
||
| ENSRainbow significantly improves healing coverage compared to relying solely on services like the ENS Subgraph. However: | ||
|
|
||
| - **Not all labels can be healed**: Some labelhashes may never be recoverable if the label cannot be discovered from any available source (onchain events, offchain APIs, brute-force generation, user submissions, or other data sources) | ||
| - **Growing coverage**: ENSRainbow's goal is to heal as many ENS names as possible, minimizing the probability that end-users encounter unknown labels | ||
| - **Multiple label sets**: Different [label sets](/ensrainbow/concepts/glossary#label-set) (identified by [label set ID](/ensrainbow/concepts/glossary#label-set-id)) can provide different coverage, allowing the ecosystem to contribute additional healing data | ||
|
|
||
| ### Label Sets and Versioning | ||
|
|
||
| ENSRainbow uses a [**label set**](/ensrainbow/concepts/glossary#label-set) system to organize rainbow table data: | ||
|
|
||
| - **[Label Set ID](/ensrainbow/concepts/glossary#label-set-id)**: Identifies a collection of [rainbow records](/ensrainbow/concepts/glossary#rainbow-record) (e.g., `subgraph`, `discovery-a`) | ||
| - **[Label Set Version](/ensrainbow/concepts/glossary#label-set-version)**: Monotonically increasing version numbers that enable incremental updates | ||
| - **Deterministic Results**: Clients can pin to specific versions for reproducible healing results | ||
|
|
||
| This system enables: | ||
| - **Extensibility**: New label sets can be created and published by anyone | ||
| - **Incremental Updates**: New versions add mappings without invalidating previous versions | ||
| - **Deterministic Healing**: Applications can rely on consistent results over time | ||
|
|
||
| For more details, see [Label Sets & Versioning](/ensrainbow/concepts/label-sets-and-versioning). | ||
|
|
||
| ## Related Documentation | ||
|
|
||
| - **[Glossary](/ensrainbow/concepts/glossary)** - Key terminology including [labelhash](/ensrainbow/concepts/glossary#labelhash), [heal](/ensrainbow/concepts/glossary#heal), and [rainbow table](/ensrainbow/concepts/glossary#rainbow-table) | ||
| - **[Label Sets & Versioning](/ensrainbow/concepts/label-sets-and-versioning)** - Understanding how ENSRainbow organizes healing data | ||
| - **[Architecture](/ensrainbow/concepts/architecture)** - High-level system architecture and data flow | ||
| - **[API Reference](/ensrainbow/usage/api)** - Complete HTTP API documentation for ENSRainbow | ||
| - **[Terminology Reference](/docs/reference/terminology)** - Comprehensive ENSNode terminology including [Unknown Label](/docs/reference/terminology#unknown-label) and [Encoded LabelHash](/docs/reference/terminology#encoded-labelhash) | ||
| - **[Querying Best Practices](/docs/usage/querying-best-practices)** - How to handle unknown labels when querying ENSNode | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.