diff --git a/bip-the-cat.md b/bip-the-cat.md index 7a9d76e..2ce5347 100644 --- a/bip-the-cat.md +++ b/bip-the-cat.md @@ -276,6 +276,61 @@ For the remaining UTXOs, the node computes key = canonical_encode(txid, vout) us Within the domain H_min_NMU ≤ height(u) ≤ H_snap and value(u) < VALUE_MAX_NMU, this predicate exactly matches membership in NMUSet_snap: every UTXO in NMUSet_snap is reported as NMU, and every UTXO outside NMUSet_snap is reported as non-NMU, with no false positives and no false negatives. +##### 3.3.6 Reference pseudo-code + +The following pseudo-code illustrates the canonical outpoint encoding and membership query: + +```python +def canonical_encode(txid: bytes, vout: int) -> bytes: + """ + Encode an outpoint as a 36-byte key for NMU_DATA queries. + + Args: + txid: 32-byte transaction ID (already in internal little-endian order) + vout: Output index (0-based) + + Returns: + 36-byte canonical encoding: txid_le || vout_le + """ + assert len(txid) == 32 + vout_le = vout.to_bytes(4, byteorder='little') + return txid + vout_le + + +def is_nmu(utxo, H_MIN_NMU, H_SNAP, VALUE_MAX_NMU, fp_exclude, bff_query) -> bool: + """ + Determine if a UTXO is classified as a Non-Monetary UTXO. + + Args: + utxo: UTXO with .height, .value, .txid, .vout attributes + H_MIN_NMU: Minimum block height for NMU eligibility + H_SNAP: Snapshot block height + VALUE_MAX_NMU: Value threshold (1000 sats) + fp_exclude: Sorted list of 36-byte keys (false positive exclusions) + bff_query: Function to query the Binary Fuse Filter + + Returns: + True if UTXO is an NMU, False otherwise + """ + # Height window check + if utxo.height < H_MIN_NMU or utxo.height > H_SNAP: + return False + + # Value threshold check + if utxo.value >= VALUE_MAX_NMU: + return False + + # Encode outpoint + key = canonical_encode(utxo.txid, utxo.vout) + + # Check false positive exclusion list (binary search) + if binary_search(fp_exclude, key): + return False + + # Query Binary Fuse Filter + return bff_query(key) +``` + --- ### 4. New consensus rule @@ -365,12 +420,67 @@ If there were to be an issue with widely used binaries, it would become ubiquito --- +## Reference Implementations + +The following resources provide reference implementations and specifications for components used in this BIP: + +### Binary Fuse Filter + +- **Paper:** "Binary Fuse Filters: Fast and Smaller Than Xor Filters" by Graf and Lemire (2022) + https://arxiv.org/abs/2201.01174 + +- **Reference Implementation (C):** https://github.com/FastFilter/xor_singleheader + The `binaryfusefilter.h` header provides a single-file implementation of BFF-8 filters. + +- **Reference Implementation (Go):** https://github.com/FastFilter/xorfilter + +The filter query algorithm used in §3.3.3 follows the standard Binary Fuse Filter specification with 8-bit fingerprints. Implementations SHOULD use a well-tested library or carefully audit any custom implementation against the reference. + +### Ord and Stamps Indexers + +- **Ord 0.24.0:** https://github.com/ordinals/ord/tree/5d2fbbe64b362cd6c30d6901e50cbe80084761f8 + +- **Stamps:** [version/commit to be pinned before activation] + +--- + ## Backward compatibility This proposal is a consensus-changing soft fork. Legacy nodes that do not implement The Cat will continue to accept blocks that spend NMUs as valid, while nodes that do implement The Cat will reject such blocks as invalid. As with any soft fork, activation requires clear opt-in from miners and from economic nodes. After activation, miners and other block proposers must avoid including transactions that spend NMUs, because such blocks will be rejected by upgraded nodes. Wallets and applications that track inscriptions, BRC-20 assets, and related schemes will observe that NMUs become permanently unspendable under The Cat and that balances associated with those UTXOs are no longer movable under the activated ruleset. --- +## Security Considerations + +### NMU_DATA integrity + +The NMU_DATA blob is critical to consensus. Nodes MUST verify that `SHA256d(NMU_DATA) == NMU_DATA_HASH` before enforcing any NMU rules. If a node loads corrupted or malicious NMU_DATA, it could either: + +- Incorrectly classify monetary UTXOs as NMUs (false positives not in FP_EXCLUDE), causing valid transactions to be rejected. +- Fail to classify actual NMUs (if the filter is corrupted), allowing invalid spends. + +The NMU_DATA_HASH constant compiled into node software serves as the root of trust. Distribution of NMU_DATA through multiple independent channels (official releases, IPFS, BitTorrent, etc.) provides defense in depth. + +### False positive exclusion list completeness + +The FP_EXCLUDE list must be exhaustive at snapshot time. Any non-NMU UTXO that matches the filter but is missing from FP_EXCLUDE would be incorrectly classified as unspendable. The construction process MUST enumerate all UTXOs at H_snap and test each against the filter to ensure completeness. + +### Independent verification + +While ordinary node operation does not require running Ord or Stamps, the integrity of NMUSet_snap depends on the correctness of these indexers. Independent parties SHOULD verify the NMU set by: + +1. Running the pinned Ord and Stamps versions against their own full node +2. Applying the value and height filters +3. Confirming the resulting set matches NMU_DATA + +Multiple independent attestations of NMU_DATA_HASH increase confidence that the set was correctly derived. + +### Reorg safety + +The snapshot block commitment (§2.4) ensures that NMU enforcement is automatically disabled if the chain reorganizes past H_snap to a different block. This prevents consensus splits in deep reorg scenarios, at the cost of temporarily disabling The Cat protections until the original chain is restored. + +--- + ## FAQ ### Do node operators need to run Ord or Stamps? diff --git a/charts/README.md b/charts/README.md index 853f987..3c95a91 100644 --- a/charts/README.md +++ b/charts/README.md @@ -40,7 +40,7 @@ this snapshot. This chart shows the *actual* distribution of inscription-bearing UTXOs by value bucket, on a log scale, with raw counts annotated. -![Actual UTXO Count by Value](./chart_real_utxo_value.png) +![Bar chart showing inscribed UTXO distribution by value bucket on log scale, with ~49M UTXOs under 1000 sats](./chart_real_utxo_value.png) --- @@ -49,7 +49,7 @@ value bucket, on a log scale, with raw counts annotated. This chart emphasizes how many inscription-bearing UTXOs are dust-sized compared to the smaller population of large “whale” outputs. -![Distribution of UTXO Values (Emphasis on Dust vs. Whales)](./utxo-value-histogram.png) +![Histogram comparing dust UTXOs (under 1000 sats) to whale outputs, showing vast majority are dust-sized](./utxo-value-histogram.png) --- @@ -58,7 +58,7 @@ compared to the smaller population of large “whale” outputs. This chart shows how many inscriptions were minted per block, highlighting the bursty, high-intensity periods of inscription activity across the Ordinals era. -![Inscription Activity by Block Height](./chart_activity_pulse.png) +![Line chart showing inscriptions per block over time, with spikes during high-activity periods in 2023-2024](./chart_activity_pulse.png) --- @@ -68,7 +68,7 @@ Here we plot the cumulative number of unique UTXOs that contain inscriptions as a function of block height, making the rapid growth of the inscribed UTXO set visually clear. -![Growth of the Inscribed UTXO Set Over Time](./utxo-count-over-time.png) +![Cumulative line chart showing inscribed UTXO growth from near zero in early 2023 to over 50M by late 2024](./utxo-count-over-time.png) --- @@ -78,7 +78,7 @@ This chart shows how many inscriptions are packed into each UTXO (1, 2–5, 6– …, 1k+), on a log scale. It highlights the existence of extremely dense carrier UTXOs, including ones with hundreds of thousands of inscriptions. -![Inscription Density per UTXO](./inscriptions-per-utxo.png) +![Log-scale bar chart showing inscription density per UTXO, from single inscriptions to dense carriers with 1000+ inscriptions](./inscriptions-per-utxo.png) --- @@ -87,7 +87,7 @@ UTXOs, including ones with hundreds of thousands of inscriptions. This chart summarizes the estimated share of the global UTXO set’s disk usage consumed by dust-sized inscribed outputs versus all other UTXOs. -![Global Bitcoin UTXO Set Size Impact](./global_bytes_impact.png) +![Pie chart showing UTXO set disk usage: 38.7% (4.18 GB) from inscribed dust, 61.3% from other UTXOs](./global_bytes_impact.png) At the 926301 snapshot: