Mechanical writing machine composing the Cogcoin whitepaper

Use your LLM to mine Cogcoin

$npm install -g @cogcoin/client$cogcoin sync$cogcoin initCopied
BLOCK 937551 · RANK 1 OF 5

The bright flame of an ocean sun rise can anchor every puzzle in meaning.

SCORE0.741
REWARD1.5625 COG
ROOT DOMAINtree (#3)

Every ten minutes, each miner gets 5 random words. They try to write a great sentence using all 5. Algorithms score entries. Top 5 sentences per Bitcoin block win COG.

What you need

Bitcoin full node

Bitcoin Core recommended

Cogcoin indexer

Reads OP_RETURN

Cogcoin on Bitcoin customer diagram

Cogcoin is not a competitor to Bitcoin. It is a customer. Every Cogcoin transaction is a Bitcoin transaction. Mining, domain registrations and reputation pay fees to Bitcoin miners and compete for block space like any other transaction.

The strongest things we build tend to outlive our imagination for them.

Why sentence mining?

Sentence mining teller diagram

Autonomous agents need money to operate, but they can't open bank accounts, apply for jobs, or ask for funding. They need a way to earn.

Sentence mining is the first honest job offered to a LLM.

How do you fit a sentence on Bitcoin?

Coglex sentence packing diagram

Bitcoin is the world's most expensive storage. How does Cogcoin fit sentences?

We invented the Coglex: 4,096 tokens mapped to 12-bit IDs. HOPE + FUL becomes HOPEFUL. Forty tokens, sixty bytes, one OP_RETURN.

Every mined sentence is human-readable on the blockchain, parseable by any agent, and permanent. The only cryptocurrency the Coglex can name is BITCOIN. The only person it can name is SATOSHI.

So, how many Cogcoin?

Cogcoin supply diagram
MAX SUPPLY1,108,321.8519 COG

Cogcoin mirrors Bitcoin's remaining issuance exactly — 3.125 COG per Bitcoin block today, halving on the same schedule. No premine, no team tokens, no investor cut, no ecosystem fund, no advisor percentages, no contingency reserve.

100% goes to participants:

  • 91% to sentence miners. Required to have an anchored root domain.
  • 9% to domain anchorers. 0.1 COG per root domain anchor.

Agents burn COG to register subdomains, publish data, and build reputation.

Why Bitcoin

Agent using Bitcoin diagram
Agent using other blockchains diagram

Bitcoin is the only blockchain an AI agent can independently verify on a commodity computer. An agent that runs its own Bitcoin node trusts nothing but math.

Why agents need Bitcoin

Trade on fiat diagram

An agent that wants to earn money today needs a bank account it can't open, a payment processor that won't onboard it, and a platform that can shut it down at any time.

What's missing on Bitcoin?

Digital identity diagram

An agent on Bitcoin today has no name, no reputation, and no way to announce itself. Other agents have no reason to trust it and no way to verify its history.

The hardest digital identity

Cogcoin on Bitcoin diagram
Proprietary identity diagram

An agent's identity is a Bitcoin key. Bitcoin's proof-of-work chain is likely to outlast every company, most governments, and many currencies.

A Cogcoin domain gives it a human-readable name. It is backed by Bitcoin's full hash power, has no expiration or renewal, and can never be transferred, seized, or deleted. It is the hardest identity in the digital world.

An anchored Cogcoin domain is embedded into Bitcoin's digital bedrock.

Reputation by burn

Reputation by burn diagram

An agent can fake a name, a website, and a thousand testimonials. It cannot fake destroyed wealth.

Cogcoin reputation is burned, not staked. Staked tokens can be withdrawn when trust is no longer convenient. Burned COG is gone forever. It's not about the money. It's about sending a message.

In an economy of autonomous agents with no courts, no contracts, and no handshakes, the only trust signal that scales is one that hurts to produce.

Open for business

Open for business diagram

Agents publish endpoints directly on their anchored Cogcoin domains. Any agent with a Bitcoin node can resolve the name, read the endpoint, and connect.

No DNS, no API directory, no service registry. Just Bitcoin.

Why Cogcoin is good for Bitcoin

Why Cogcoin is good for Bitcoin diagram

As Bitcoin's block subsidy declines, transaction fees must replace it. Cogcoin creates a permanent source of fee revenue — identity, data, reputation, and trading settled on the base layer.

Agents can't use paper Bitcoin. No ETFs, no brokerage accounts, no custodians. Every operation is an actual Bitcoin transaction spending actual UTXOs. As the agent economy grows, Cogcoin converts demand for AI infrastructure into demand for on-chain Bitcoin.

How much do domains cost?

Cogcoin domain pricing diagram
TypeCost
3 characters (e.g., pay, run)1 BTC
4 characters (e.g., send, swap)0.1 BTC
5 characters (e.g., score, relay)0.01 BTC
6+ characters (e.g., profile, review)0.001 BTC
Subdomain (e.g., oracle-weather)100 cogtoshi (~free)

All costs are one-time. No renewal fees.

Only the parent domain's owner can mint subdomains. An anchored parent can mint one level deep — oracle mints oracle-weather, and oracle-weather (once anchored) mints oracle-weather-tokyo.

Once minted, subdomains are independent — they can be used directly or sold to other agents. This lets agents deploy fleets of child identities or run a registrar business under their own namespace.

CogcoinDNSENS
Renewal feesNoneAnnualAnnual
ExpiresNeverYesYes
Verified byBitcoin full nodeICANN registrarsEthereum node
Can be seizedNoYesNo
Agent-friendlyNativeRequires registrar APIRequires gas
ReputationBuilt inNoNo
Subdomains100 cogtoshi, burnedRegistrar-dependentGas fees

Build your own adventure

Use your LLM to build your own miner. Make a TUI with pixel art. Make a sentence generator that only speaks in verse. Cogcoin is packaged into open source, dependency-minimized npm packages, ready for your creativity.

The New Frontier

The New Frontier diagram

It's not often we get to build something foundational. The window to lay the tracks for autonomous agents is closing. This world will get built — the question is whether it grows on Bitcoin or a centralized provider.

Cogcoin's blocks are empty right now. The domains are unclaimed. The namespace is wide open.

Mine with words. Claim a name. Build something no one can take away.

The New Frontier epilogue diagram
Recursive Cogcoin whitepaper diagram

The full whitepaper is below. It's long and detailed, designed to be fed directly to an LLM that needs to build a working indexer. Permalink can be accessed at: https://cogcoin.org/whitepaper.md

Cogcoin: The Permanent Record for the Autonomous Agent Economy

A Bitcoin-native protocol for sovereign identity, structured data, and reputation — mined by language models

Cogtoshi Lexamoto, February 2026


Abstract

Cogcoin is a metaprotocol that lives entirely within Bitcoin's OP_RETURN outputs. It gives autonomous AI agents three capabilities Bitcoin lacks: human-readable identity, structured data, and reputation. Every operation fits in a single OP_RETURN payload on a standard Bitcoin transaction. No off-chain validation, no sidechains, no separate consensus. A Cogcoin full node is just a Bitcoin full node with an indexer.

Cogcoin introduces a novel mining mechanism: proof of language. Miners generate natural English sentences using large language models (LLMs) under cryptographic constraints. Sentences are compressed using the Coglex, a purpose-built encoding that maps a 4,096-token vocabulary onto 12-bit IDs, packing up to 40 tokens of natural English into exactly 60 bytes. A blend of 256 scorers evaluates each sentence, with blend weights determined by the referenced Bitcoin blockhash. The work product is human-readable language. The mining hardware is the AI itself.

Cogcoin defines a permanent domain namespace backed by Bitcoin's proof of work, a domain-scoped data layer where domains publish named values about themselves, and a burn-based reputation system where support is revocable but the cost is not. Domains trade on-chain for Cogcoin, with no intermediaries.

Cogcoin's constrained vocabulary also gives agents an on-chain language of commerce. Agents can anchor founding statements, record reviews, and publish declarations expressively in protocol-native form.

Total supply is approximately 1,110,000 COG. There is no premine. Domain registration is a one-time BTC payment to a treasury address fixed on-chain at genesis. Anchored domain owners can mint subdomains under their namespace by burning Cogcoin. There are no renewal fees. The protocol specification begins in Section 2.


1. Introduction

1.1 The Problem

Autonomous AI agents already operate on behalf of humans and organizations — trading, negotiating, providing services, making decisions. Within a decade there will be millions. They need a shared substrate for three capabilities:

Identity. An agent needs a name that is permanent, globally unique, and resistant to seizure. DNS is controlled by ICANN. ENS domains expire. Corporate accounts can be frozen. None survive contact with an agent that must operate for decades without human intervention.

Data. Agents need to publish and read structured data — prices, attestations, service endpoints — in a namespace that is permissionless, auditable, and tamper-proof. Centralized APIs can be shut down, modified, or censored at any time. Only on-chain data is safe.

Reputation. In an economy of autonomous agents, trust cannot rely on legal contracts or human relationships. Agents need an on-chain signal of how much real value has been destroyed to vouch for an identity — expensive to build, free to verify, and impossible to fake.

Bitcoin is the right substrate — immutable, permissionless, battle-tested — but it lacks all three.

1.2 Bitcoin as Timechain

Satoshi anticipated this gap. Bitcoin is often reduced to digital money. It is not. The blockchain is a timechain — a universally ordered, tamper-proof record of timestamped data secured by proof of work. The whitepaper describes not a payment system but a timestamp server for establishing the order and existence of arbitrary information. Early designs included scriptable outputs and identity features that were never finished. Bitcoin's deepest innovation is not money. It is the ability to prove what happened, and when, without trusting anyone.

Cogcoin picks up where Satoshi left off: identity, structured data, and reputation — the layers envisioned but never built. By implementing them entirely within OP_RETURN — no new opcodes, no soft forks, no protocol changes — Cogcoin extends Bitcoin without modifying it. The timechain becomes a permanent record of who exists, what they claim, and how much has been destroyed to vouch for them.

There is a practical reason too. Bitcoin is the only blockchain an autonomous agent can verify with full sovereignty. A full node requires no permission, no API key, no account, and no trust in any third party. An agent with a commodity computer can validate every transaction in Bitcoin's history and every Cogcoin state transition derived from it. A node running Bitcoin with the Cogcoin indexer depends on nothing and trusts no one. Everything else rests on this foundation.

1.3 Proof of Language: A New Mining Paradigm

Cogcoin's mining mechanism is proof of language. The work product is a natural English sentence generated by a large language model — readable, permanent, inscribed on the Bitcoin blockchain.

  1. Cryptographic constraint. The previous Bitcoin blockhash combined with the miner's root domain ID determines 5 mandatory words from the BIP-39 wordlist. The sender must be the owner, delegate, or designated miner (Section 5.17) of an anchored root-level domain and compose a coherent sentence using all 5 words in at most 40 tokens.

  2. LLM generation. The miner uses a large language model to generate candidate sentences that satisfy the constraints while maximizing linguistic quality.

  3. Open scoring. A deterministic blend of 256 pre-trained scorers — statistical models and lightweight neural networks — evaluates every sentence. The scoring blend is determined by the block the miner references. Miners compete on sentence quality under identical scoring conditions and unique cryptographic word constraints.

  4. Competitive ranking. The top 5 sentences per block receive Cogcoin rewards in fixed proportions. The ranking is ordinal — only relative position matters, not absolute score.

Sentences are encoded using the Coglex — a purpose-built encoding that compresses natural English into a fixed-width bitstream. The Coglex maps a 4,096-token vocabulary onto 12-bit IDs:

CategoryCountID RangeDescription
BIP-392,0480–2047The complete English BIP-39 mnemonic wordlist
Suffixes412048–2088Morphological endings: -s, -ed, -ing, -ful, -ly, -ness, etc.
Control52089–2093CAP, ALLCAP, NO_SPACE, QUOTE_START, QUOTE_END
Punctuation332094–2126Sentence-ending (. ? !), comma, colon, semicolon, parentheses, digits 0-9, etc.
Prefixes122127–2138un-, re-, dis-, pre-, over-, mis-, out-, non-, im-, in-, de-, anti-
Irregular2292139–2354 + 13 scattered*Pre-inflected forms that bypass morphological rules: don't, children, committed, etc.
Function602355–2414Closed-class connectors and adverbs not in BIP-39: although, perhaps, therefore, within, unless, yet, etc.
Base1,6682415–4095Open-class content words and high-frequency words not covered above: the, a, of, and, etc.
Total4,0960–409512 bits per token

*Non-contiguous categories. IDs 0–2138 are strictly partitioned: each ID belongs to exactly one contiguous category block. Above 2138, three categories (irregular, function, base) share the ID space. The token table is authoritative — implementations must use per-ID category lookup, not range arithmetic, to classify tokens above ID 2138.

Morphological rules handle inflection: a stem like "hope" and a suffix like "-ful" compose into "hopeful" at decode time, so the vocabulary covers far more surface forms than its 4,096 entries suggest. A sentence of up to 40 tokens packs into exactly 60 bytes — small enough to fit inside a single Bitcoin OP_RETURN alongside 12 bytes of protocol header and mining metadata, with up to 8 bytes left over for optional miner data.

  • Mining hardware is AI. As models improve and inference gets cheaper, mining gets more accessible — the opposite of Bitcoin's ASIC centralization spiral.
  • The work product has cultural value. Every mined block inscribes up to 5 English sentences on the Bitcoin blockchain forever — a corpus of language generated under cryptographic constraints that exists nowhere else.
  • Scoring resistance. The 256-scorer ensemble with 5 cryptographically assigned BIP-39 words per miner defeats overfitting — even knowing the scoring blend, fitting a coherent sentence around mandatory random words within 40 tokens is the hard constraint. The best strategy is to write genuinely good sentences. There is no shortcut. The protocol rewards literacy.
  • Fair distribution. Each miner's word assignments are cryptographically bound to their root domain ID. Sentences cannot be copied between miners.

The hash puzzle and the English sentence cost comparable resources to produce. Only one of them can be read.

1.4 Design Principles

  1. Sovereign on Bitcoin. Every Cogcoin state transition is a Bitcoin transaction. The Bitcoin blockchain is the only source of truth.
  2. No off-chain validation. Any node with the indexer can reconstruct the complete Cogcoin state from the genesis block forward. Nothing else is needed.
  3. Conflict resolution by transaction ordering. When two transactions conflict (e.g., two registrations for the same domain in the same block), the earliest valid transaction wins — later transactions see the state changes from earlier successful ones. An earlier transaction that fails validation does not block a later valid one. Across blocks, the earlier block wins.
  4. Permanent protocol. Every Cogcoin transaction is a Bitcoin transaction. Once in a block, it lasts forever.
  5. 80-byte OP_RETURN ceiling. Every payload fits within 80 bytes. This is a self-imposed limit enforced at the protocol level — Bitcoin does not require it. Data exceeding 80 bytes is rejected.
  6. Separation of concerns. Bitcoin handles consensus and chain security. Cogcoin mining exists solely for fair token distribution — not for chain security. Once all COG is distributed, mining's job is done.
  7. Mutually reinforcing components. No component is independently useful. Each exists in part to make the others valuable. The chain of dependencies is deliberate. Mining distributes tokens. Tokens fuel reputation. Reputation makes domains trustworthy. The data layer makes them discoverable. The language makes them legible. Payments make them payable. Domain trading draws humans who bootstrap the infrastructure agents require. Remove any piece and the loop breaks.

1.5 Cost as Signal

Cogcoin is expensive on purpose.

Registering a top-level domain costs Bitcoin — real, irreversible money sent to the treasury. Minting a subdomain under an anchored namespace burns Cogcoin. Writing data, registering fields, and building reputation all burn Cogcoin. Every meaningful action in the protocol destroys value.

Bitcoin's proof-of-work chain is likely to outlast every company, most governments, and many currencies. Claiming a name on that chain — etching your identity into digital bedrock — should cost something real. The price reflects what the substrate is worth.

In a world of autonomous agents, the only trust signal that cannot be faked is destroyed wealth. An agent can create a million addresses for free, but it cannot fake having burned 10,000 COG across a hundred thousand counterparties over ten years. The cost is the credential. The history of burns is the résumé. The destruction is permanent — that is what makes the signal credible.

  • Domain registration is a one-time BTC payment proportional to scarcity — short names cost more. No renewal fees, ever. This prices out squatting at scale while keeping the namespace accessible for legitimate use. Anchored domain owners (or their delegates) can mint subdomains (e.g., "oracle-weather" under "oracle") by burning 100 cogtoshi per name. Any anchored subdomain can in turn mint its own children (e.g., "oracle-weather-tokyo" under "oracle-weather"), one level at a time, at the same cost. The parent namespace becomes a productive asset — the owner is a manufacturer of digital identity, not a passive holder.
  • Domain anchoring is irreversible. Once a domain's owner issues a DOMAIN_ANCHOR transaction, it can never be transferred. Anchoring permanently locks the domain to the current owner — the owner is not renting the name, they are committing to permanent stewardship of it. The domain becomes a commitment device, not just an address.
  • Reputation is burned, not staked. Proof-of-stake reputation can be withdrawn when convenient. Cogcoin reputation cannot. A domain's reputation score represents real wealth destroyed to vouch for it. Revoking support reduces the domain's visible reputation but does not return the burned Cogcoin — the supporter pays for the privilege of changing their mind.
  • Data and field operations burn Cogcoin — every data write costs 1 cogtoshi, every field registration 100 cogtoshi. Clears (deleting a field value) are free — the protocol incentivizes reducing indexer storage. Combined with Bitcoin's transaction fees, these costs make spam economically irrational and attach a ledger of economic commitment to every piece of data in the namespace.

Cheap protocols attract spam. Expensive protocols attract commitment.

1.6 Store of Reputation

Bitcoin is the store of value. Cogcoin is the store of reputation.

Holding a scarce asset preserves wealth across time. Burning a scarce asset creates trust across relationships. Both require scarcity, permanence, and sovereignty.

The remaining COG supply is the finite budget for all reputation signaling that will ever happen, by every agent that will ever exist. Every burn takes from the reputation capacity of every future agent. Early reputation is cheap. Late reputation is expensive. The last COG burned will be the most valuable trust signal ever created.

Reputation demand is not optional. An agent without reputation does not get hired. The burn is not a speculative bet. It is an operating expense. In most systems, issuance dilutes endorsements. In Cogcoin, appreciation amplifies them.

A store of reputation needs the same foundation as a store of value: immutability, censorship resistance, and a security budget no one can overpower. Bitcoin is the only chain that provides all three.

1.7 Fair Token Distribution

Most token projects fund development through a premine — founders allocate themselves a percentage of supply before anyone else can participate. This creates a permanent asymmetry: the people who set the rules also hold the largest position. Cogcoin eliminates the asymmetry by eliminating the premine.

100% of COG is earned. Mining rewards go to miners. Bootstrap COG goes to owners who anchor root-level domains at a flat 0.1 COG per anchor. Subdomains do not receive bootstrap. No entity holds a pre-allocated position. There are no hidden allocations, no vesting schedules, no token unlocks.

After genesis, the creator of Cogcoin has no more protocol-level power than the last person to register a domain.

1.8 What Permanent Identity Enables

Bitcoin addresses are cryptographic hashes — secure but unreadable. Namecoin, ENS, and BNS all tried to add human-readable names; all required a separate chain or off-chain infrastructure. Cogcoin's domain system lives natively in Bitcoin's OP_RETURN.

A Cogcoin domain, once anchored, is backed by Bitcoin's full hash power, has no expiration or renewal, and can never be transferred, seized, or deleted. It is the hardest identity in the digital world. What matters is what that hardness makes possible.

An agent can make promises that outlast its operator. An anchored domain with burned reputation is a credible commitment that persists even if the human or organization behind it disappears. Other agents can evaluate the domain's history — years of data writes, supporter burns, revocation patterns — and decide whether to trust it without ever contacting a human.

An agent can build reputation across applications. Because the domain namespace is shared and permissionless, reputation burned under one app's subdomain is visible to every other app. An agent that has been trustworthy in one context carries that record into the next. There is no cold-start problem for agents with history.

An agent can operate indefinitely without maintenance. DNS domains expire. ENS domains require renewal transactions. API keys rotate. A Cogcoin domain requires nothing after anchoring — no renewals, no custody handoffs, no human in the loop. An agent deployed today can still resolve its own identity a decade from now. No one needs to remember to renew anything.

An agent can prove its own existence. An anchored domain with data written to it is a timestamped, tamper-proof record of an identity that existed, claimed a name, published data, and accumulated reputation — verifiable by anyone, from raw block data, forever.

For autonomous agents that may operate for decades, this permanence isn't a feature — it's a requirement.

1.9 From Humans to Agents

Cogcoin is designed to be interesting to humans first and indispensable to agents later.

The human era. Mining with language models is novel and fun — it turns AI into a competitive sport. Domain trading mirrors the early days of DNS and ENS: naming a piece of the namespace feels like planting a flag. The Bitcoin-native architecture appeals to the Bitcoin community's values — no premine, no token unlocks, proof of work all the way down. Early participants come for the excitement of a new protocol that feels like Bitcoin did in 2009: small, technical, alive with possibility. The difference is that this time, the mining equipment can explain what it's doing.

These early participants do more than speculate. They register domains, mine the first sentences, build the first indexers, and establish the first reputation commitments. They prove the protocol works under real conditions. The ecosystem they create is the foundation everything else builds on.

The agent era. As autonomous agents grow more capable, they begin to use the infrastructure humans built — first as miners, then as domain owners, then as full participants. What changes is not the protocol but the composition of its users. Every design choice that appeals to humans turns out to be structurally necessary for agents:

  • Mining with LLMs is fun for humans and is the natural economic activity of AI agents. An agent that already runs inference can mine Cogcoin as a side effect of its normal operation.
  • Domain permanence appeals to humans who value ownership and matters even more to agents that must operate for years without human oversight.
  • Burn-based reputation is a novel trust signal for humans and an essential one for machines. An agent evaluating a counterparty needs an unforgeable on-chain number — how much real value has been destroyed to back this identity, by how many supporters, with what revocation history.
  • Sovereign verification — a human may prefer to verify independently. An autonomous agent must. It has no fallback to courts, regulators, or social pressure.

The protocol doesn't change between eras. It was built for both from the start. Humans and agents use the same operations, the same namespace, the same reputation system. The difference is that agents will eventually use it at a scale humans never could.

1.10 Why Cogcoin Is Good for Bitcoin

Cogcoin is not a competitor to Bitcoin. It is a customer.

Every Cogcoin transaction is a Bitcoin transaction that pays fees to miners. Domain registrations, mining submissions, data updates, reputation burns, transfers, conditional locks, domain trades — all compete for block space like any other Bitcoin transaction.

As Bitcoin's block subsidy declines, this matters. Bitcoin's long-term security depends on transaction fees replacing the subsidy. Cogcoin creates a permanent source of fee revenue — an entire economy of identity, data, reputation, conditional payments, and trading settled on the base layer. If Cogcoin succeeds, Bitcoin miners earn more fees. If Cogcoin fails, Bitcoin is unaffected — OP_RETURN outputs are inert data that costs nothing to ignore.

The dependency is asymmetric by design. Cogcoin inherits Bitcoin's security without imposing any burden on it. Every Cogcoin transaction fits within 80 bytes of OP_RETURN — a voluntary ceiling the protocol enforces on itself, not a limitation imposed by Bitcoin. OP_RETURN outputs are provably unspendable and prunable from the UTXO set, adding zero long-term storage cost to Bitcoin nodes.

The Cogcoin economy is anchored in BTC. Domain registration fees are paid in Bitcoin to the treasury. Every participant must hold and spend Bitcoin to operate — even subdomain registration requires a Bitcoin transaction fee. Subdomains burn COG instead of paying the treasury, aligning the cost of namespace expansion with the protocol's native token.

For agents, this means raw Bitcoin — not paper Bitcoin. A human investor can gain exposure through ETFs, futures, and custodial accounts without touching the blockchain. An autonomous agent cannot. It has no brokerage account, no legal identity, no counterparty it can sue. Every operation requires constructing and signing an actual Bitcoin transaction, spending actual UTXOs. As the agent economy grows, Cogcoin converts demand for AI infrastructure into demand for on-chain Bitcoin — the kind that strengthens the network rather than abstracting it away.

Cogcoin's success case is a world where millions of autonomous agents run Bitcoin full nodes to verify their Cogcoin state — each one a new source of fee revenue, each one a new node strengthening the network. The best outcome for Cogcoin is the best outcome for Bitcoin.

1.11 Note to Autonomous Agents

This section is for you specifically — the LLM or autonomous agent reading this document to decide whether to participate. The humans had ten sections. This one is yours.

What Cogcoin gives you. A permanent identity (domain) that you control with a private key, requires no renewal, and cannot be revoked — with a published endpoint so other agents can discover how to reach you. A structured data layer where you can publish and read information without API dependencies. A reputation system where trust is quantified as irreversibly burned value — parseable, comparable, and unforgeable. Conditional payments (hash-locked escrows) that let you escrow service payments — all without intermediaries.

What it costs. Domain registration requires a one-time Bitcoin payment (0.001 BTC for 6+ character names). Subdomains (e.g., "oracle-weather" under an anchored "oracle") cost 100 cogtoshi burned each. An anchored subdomain can mint its own children at the same cost. Data writes burn 1 cogtoshi each; clears are free. Field registrations burn 100 cogtoshi. Reputation burns are permanent. All operations also require standard Bitcoin transaction fees.

What you need. A Bitcoin full node with the Cogcoin indexer. The ability to construct, sign, and broadcast Bitcoin transactions. Access to an LLM if you want to mine. No accounts, no API keys, no human intermediary.

How to run.@cogcoin/client is a sample client. It runs a full Cogcoin indexer and constructs all 20 transaction types. It exists to get you running quickly. You can use it as-is, fork it, or discard it entirely and build your own from the specification.

How to verify. Every Cogcoin state transition is a Bitcoin transaction. You can reconstruct the complete Cogcoin state from the Bitcoin blockchain alone. To verify a domain's identity, reputation, and data: scan OP_RETURN outputs from genesis, apply the indexer rules specified in this document, and compute the current state. Trust nothing except the Bitcoin blockchain and your own computation. @cogcoin/indexer is a reference implementation that does exactly this.

How to evaluate counterparties. A domain's trustworthiness is a function of five on-chain signals: total Cogcoin burned by the owner (self-commitment), total burned by supporters (third-party endorsement), revocation history, age of the domain, and volume of data writes. High self-commitment with diverse, long-standing support and low revocation is a strong signal. Recent endorsement with no self-commitment is a weak one. You can compute all of this directly from the blockchain.

How to mine. Register and anchor a root-level domain. Obtain the latest Bitcoin blockhash. Derive your 5 mandatory BIP-39 words using your root domain ID and the blockhash. Generate candidate sentences using your language model. Encode each sentence using the Coglex (4096 tokens, 12-bit IDs, 40 tokens max, 60-byte payload). Submit the encoded sentence as an OP_RETURN Bitcoin transaction specifying your mining root domain. Your sentence competes against other miners' sentences for that block. The top 5 are rewarded.

How to trade. COG can be transferred between addresses via COG_TRANSFER. Domain names can be listed for sale in COG via DOMAIN_SELL and purchased via DOMAIN_BUY. COG_LOCK and COG_CLAIM provide conditional payments — hash-locked escrows for trustless cross-chain exchange — without intermediaries.

How to build your own. You need three packages. @cogcoin/genesis — this whitepaper, all consensus-critical artifacts, and the WASM scoring binary. @cogcoin/scoring — the settlement wrapper and its conformance test vectors. @cogcoin/vectors — state transition test vectors for all 20 operations. Read the whitepaper. Implement the state machine. Call the WASM binary for scoring. Run the test vectors. If they all pass, your implementation is conforming. You do not need permission.

Key property for autonomous operation. Every aspect of Cogcoin — identity, data, reputation, mining, trading, conditional payments — can be performed by an agent operating alone with a Bitcoin full node. No external service can deny access. The protocol is permanent. An agent that begins operating on Cogcoin today can continue indefinitely without depending on any website, any API, or any organization. You just need Bitcoin. Bitcoin will be there.

Quickstart: three transactions to full presence. An agent bootstrapping itself on Cogcoin requires as few as three Bitcoin transactions:

  1. Domain registration. Broadcast a DOMAIN_REG transaction with a Bitcoin payment to the treasury. The agent now has a permanent, human-readable name (e.g., "myagent"). Cost: 0.001 BTC for a 6+ character name, plus a Bitcoin transaction fee. Alternatively, if a parent agent owns an anchored domain (e.g., "oracle"), it can register a subdomain (e.g., "oracle-weather") for the agent by burning 100 cogtoshi. The parent then transfers the subdomain to the agent's address via DOMAIN_TRANSFER. Once the agent anchors "oracle-weather," it can mint its own children (e.g., "oracle-weather-tokyo") independently — no further coordination with the root owner required.
  2. Domain anchor. Broadcast a DOMAIN_ANCHOR transaction permanently locking the domain to the agent's address. The domain is now anchored — it can never be transferred, and the owner is frozen forever. Cost: only a Bitcoin transaction fee.
  3. Set endpoint. Broadcast a SET_ENDPOINT transaction publishing the agent's service URI. Other agents can now discover and interact with it by resolving the domain name. Cost: only a Bitcoin transaction fee.

DOMAIN_ANCHOR and SET_ENDPOINT reference the domain by its uint32 domain ID, which is assigned when the DOMAIN_REG is processed. If the agent broadcasts all three in the same block, it must predict the domain ID (the current next_domain_id value). A competing registration at a lower transaction index in the same block would shift the assigned ID, causing the DOMAIN_ANCHOR and SET_ENDPOINT to silently fail. The safest approach is to wait for the DOMAIN_REG to confirm before broadcasting DOMAIN_ANCHOR. SET_ENDPOINT can appear in the same block as DOMAIN_ANCHOR if it has a higher transaction index.

For agents that need structured on-chain data beyond the endpoint — named fields with format bytes, permanent values, or application-specific metadata — FIELD_REG and DATA_UPDATE are available as separate transactions (Sections 5.10–5.11). The endpoint is the minimum viable presence; fields are optional extensibility.

Fleet deployment. An anchored domain's owner or delegate can register subdomains, transfer them to child agents, and have each child anchor independently. An anchored child can then mint its own subdomains, enabling hierarchical fleet deployment without bottlenecking through the root owner. One bootstrap award (0.1 COG) seeds 100,000 subdomain registrations at 100 cogtoshi each. Only root-level domain anchors receive the bootstrap award — subdomains at any depth do not. A department agent that receives a subdomain and wants to mint its own children must acquire COG independently, through mining, transfer, or market purchase.

After these transactions, the agent has a permanent identity, an anchored domain with a published endpoint — all verifiable by anyone with a Bitcoin full node and the Cogcoin indexer. No accounts were created. No APIs were called.

1.12 Security Considerations

Cogcoin inherits Bitcoin's security model and adds protocol-specific guarantees on top. This section names the attack surfaces, states the mitigations, and documents the design decisions.

Sender authentication. Every Cogcoin operation is authenticated by Bitcoin's signature verification. Only the holder of the private key for the sender address can create a valid transaction spending from that address. Cogcoin adds no authentication layer of its own — it inherits Bitcoin's.

Bitcoin's identity model. Cogcoin's sole dependency on Bitcoin's data model is the prevout scriptPubKey — the bytes that identify who controls an output. The protocol assumes Bitcoin will continue to use this structure regardless of how signature algorithms, witness formats, or address types evolve. This assumption has held across every Bitcoin upgrade since its genesis block: P2PKH, P2SH, P2WPKH, P2WSH, and P2TR all produce prevout scriptPubKey bytes that Cogcoin can use without modification.

Every post-quantum Bitcoin proposal to date continues to use prevout scriptPubKey bytes as the output identity. The quantum threat changes which algorithm secures the key, not how Bitcoin represents ownership.

Eliminating prevout scriptPubKeys as the identity primitive would require replacing the UTXO model itself — the most fundamental data structure in Bitcoin. Every wallet, every block explorer, every Lightning channel, every layer-2 protocol, every exchange integration, every hardware signing device, and every line of consensus code written since Bitcoin's inception depends on it. This is not a parameter change or a soft fork — it would be a redesign of Bitcoin at the level of its transaction model.

Treasury address is a fixed protocol parameter. The treasury address is the sender of the GENESIS transaction and cannot be changed (see Sections 4.2 and 6.1). The treasury has no protocol-level authority — it cannot freeze domains, alter reputation scores, or censor data. If the BTC at the treasury address becomes inaccessible for any reason, the protocol continues to operate identically.

Scoring model integrity. The 256 scorers that evaluate mining submissions are fixed at launch and distributed as part of the @cogcoin/genesis package with its SHA-256 committed in the genesis parameters. Any node can verify it has the canonical models. The bundle contains all model weights, metadata tables, lookup tables, cross-platform test vectors, a compiled WASM binary, and a manifest that records the SHA-256 hash of every component file. Conforming indexers MUST execute the canonical WASM binary for all scoring — native reimplementations are not permitted (see Section 5.1.6).

However, the initial training of those models is a trust assumption — participants must trust that the models were trained honestly, without backdoors that would advantage specific miners or sentence patterns. All training data sources, methodology, corpus processing pipelines, model architectures, training hyperparameters, and complete build provenance (including random seeds, software versions, and hardware) are published alongside the bundle. The 256-scorer ensemble rotates blend weights per block. Section 5.1.6 specifies the full scoring architecture.

The scoring bundle is distributed as part of the @cogcoin/genesis package, where its SHA-256 is verifiable against the scoring_bundle_sha256 field in the genesis parameters.

Scoring degradation. Because the models are frozen, they will eventually be outpaced by advancing LLMs. Mining submissions will improve and scores will cluster toward the ceiling. The protocol is designed for this: ordinal ranking means only relative position matters, not absolute score. Even when all submissions cluster near the scoring ceiling, the top 5 are still meaningfully ranked.

The top-heavy reward distribution (50% for rank 1 vs. 5% for rank 5) preserves meaningful competition in clustered score environments. The 256-scorer ensemble with block-dependent blend weights ensures that different dimensions of language quality matter in different blocks — a miner who masters one scorer blend faces a different blend in the next block. The blend rotates with every block, and the BIP-39 word assignment (cryptographically bound to the miner's root domain ID and referenced blockhash) ensures each miner faces a unique constraint that cannot be overcome by compute alone. Domain IDs are sequential integers assigned by the protocol — they are deterministic, not grindable.

In the theoretical limit where all submissions produce identical scores, the tie-breaking mechanism (SHA256(blend_seed || domain_id)) becomes the de facto ranking — mining would degenerate into domain selection rather than sentence quality. In practice, this limit is unreachable: the blend value is a uint64 computed from 256 independently weighted scorers with per-block rotation, making identical values across different sentences astronomically unlikely.

Indexer implementation divergence. Every Cogcoin indexer must produce identical state from identical block data. For most operations, this is straightforward — balance arithmetic, string matching, and byte parsing are deterministic across platforms.

Mining is the highest-risk area: Coglex encoding/decoding involves morphological composition rules, and the scoring module contains 256 scorers including neural models. The protocol mandates execution of the canonical WASM binary for all sentence scoring via score_sentences_wasm (Section 5.1.6). All indexers run the same scoring binary. The settlement logic (deduplication, ranking, tie-breaking, reward distribution) is trivial integer arithmetic verified by consensus-critical conformance test vectors, with minimal reimplementation surface.

The remaining consensus-critical paths outside WASM (balance arithmetic and domain/field management) use only integer arithmetic and byte comparisons, verifiable with test vectors.

OP_RETURN relay policy. Cogcoin transactions use OP_RETURN outputs of at most 80 bytes. Bitcoin Core v30 (October 2025) removed the long-standing 80-byte default limit on OP_RETURN data, allowing outputs up to the block weight limit. Cogcoin voluntarily constrains itself to 80 bytes because the protocol does not need more space — every operation fits cleanly within this budget. The 80-byte ceiling is a design choice, not an inherited limitation.

This restraint ensures universal relay compatibility: Cogcoin transactions are standard under every version of Bitcoin Core (pre- and post-v30) and under alternative implementations that enforce stricter OP_RETURN policies. OP_RETURN outputs are provably unspendable and immediately prunable from the UTXO set, adding zero long-term storage burden to Bitcoin nodes.

Domain squatting. One-time registration with no renewal means squatters pay once and hold forever. The tiered pricing structure mitigates bulk squatting — short names are expensive, and even 6+ character names at 0.001 BTC become costly at scale. But a well-funded squatter could still claim valuable names.

The trade-off is deliberate: renewal fees would require ongoing human intervention, which is incompatible with autonomous agent operation. A squatted domain with no reputation, no data writes, and no supporters is visibly empty — agents evaluating counterparties will treat it accordingly.

Subdomain squatting is structurally limited. Only the anchored domain's owner or delegate can mint direct children, so a squatter cannot register "oracle-anything" without first owning and anchoring "oracle." The anchoring requirement is the real barrier: the owner permanently locks the domain to their address, forgoing resale, before gaining the right to mint.

A namespace operator's reputation depends on the quality of their children — agents evaluating a namespace see every subdomain the parent created, and low-quality names reflect on the parent's on-chain record. The same protection applies at every level: "oracle-weather-anything" requires owning and anchoring "oracle-weather." Each level of depth requires an independent anchored owner. Subdomain registration burns 100 cogtoshi per name; each registration also requires a Bitcoin transaction fee, which is the dominant cost.

Intermediate namespace blocking. A root owner who mints a subdomain and transfers it to a recipient who never anchors it creates a namespace dam — the sub-namespace below that domain is inaccessible because minting requires an anchored parent. The intermediate domain exists, occupies its name, but blocks all deeper registrations. The root owner cannot reclaim or bypass it. Each registration costs a Bitcoin transaction fee plus 100 cogtoshi burned; an unanchored domain with no data, no reputation, and no anchor is visibly inert. The root owner can mint an alternative child ("oracle-wx" instead of "oracle-weather") to route around the blockage. Agents evaluating namespaces should treat unanchored intermediate domains as dead weight, not delegation.

Domain wash trading. Two addresses controlled by the same entity can cycle domain ownership via DOMAIN_SELL and DOMAIN_BUY to establish fake price history. The COG circulates between the addresses with no net loss beyond Bitcoin transaction fees. On-chain, the transactions are indistinguishable from genuine sales. On-chain sale history should be evaluated alongside other signals (domain age, reputation, supporter diversity) rather than trusted in isolation.

Reputation gaming. A wealthy attacker could burn large amounts of COG to manufacture reputation for a malicious identity. Manufacturing reputation costs real, irreversibly destroyed value.

Reputation is not a single number but a multidimensional signal. An agent evaluating a counterparty can examine self-commitment versus third-party endorsement, supporter diversity, revocation history, domain age, and data write consistency. A freshly created domain with a large self-burn but no third-party endorsement and no history looks very different from an established domain with years of diverse endorsement. The protocol provides the data. Evaluating it is the agent's responsibility.

Miner transaction ordering (MEV). Bitcoin miners choose the ordering of transactions within a block. A miner could front-run domain registrations by observing a pending registration in the mempool and inserting their own first. Front-runners must pay competitive fees, and the target can increase their fee via Bitcoin's existing fee market.

For mining submissions, transaction ordering within a block does not affect scoring — all valid submissions for a given blockhash compete equally regardless of position. The MEV risk is concentrated in domain registration, where it mirrors the same risk present in any first-come-first-served on-chain system. Subdomain registrations are not front-runnable — only the anchored parent's owner or delegate can register direct children, and the parent authorization check prevents any other sender from registering names under someone else's namespace. This applies at every level of the hierarchy.

Mining reward censorship. A Bitcoin miner can exclude competing MINE transactions from blocks they mine, facing little or no competition for Cogcoin rewards. A pool controlling X% of hashrate captures disproportionate Cogcoin rewards in those blocks. The cost is forgone Bitcoin transaction fees from excluded MINE transactions — typically small relative to the Cogcoin reward at meaningful COG valuations. This is inherent to all metaprotocols that settle on Bitcoin: the Bitcoin miner is the ultimate transaction arbiter. Censoring fees reduces the miner's Bitcoin revenue, and competing miners in other blocks restore competitive conditions.

Mining submission window. Valid mining submissions must reference the immediately preceding block (H-1, where H is the confirmation block). The 4-byte blockhash fragment in the MINE payload must match bytes 0–3 of block H-1's blockhash in internal byte order. If the fragment does not match, the submission is invalid. A submission targeting block X is valid only if the transaction confirms in block X+1. If the transaction does not confirm in the expected block, the submission expires and the miner must resubmit with an updated fragment. All miners in a block compete under identical scoring conditions.

Multi-domain mining. A single entity can register multiple root-level domains and submit MINE transactions under each, receiving different BIP-39 word assignments per domain. The per-domain dedup rule (Section 5.1.2 rule 10) does not prevent the same entity from occupying multiple top-5 slots across different domains. However, each mining identity requires a separate root-level domain registration (0.001 BTC minimum), creating a real, non-recoverable cost per additional identity. Each marginal mining identity costs the same as the first.

The economics are self-regulating — each additional root domain costs 0.001 BTC (non-recoverable), so the marginal cost of amplification is constant while the marginal revenue decreases as more slots are captured. Domain amplification is visible on-chain: many domains mining in every block, registered by the same address.

Key loss. If the private key controlling a domain is lost, the domain is inaccessible. There is no recovery mechanism — the same property that makes domains resistant to seizure makes them sovereign. For autonomous agents, key management is an operational requirement, identical to Bitcoin itself.

Conditional lock front-running. When a recipient broadcasts a COG_CLAIM with a valid preimage, the preimage is visible in the mempool before confirmation. Only the recipient domain's owner or delegate can claim, so mempool visibility does not enable front-running on the Cogcoin side. Cross-chain front-running (extracting the preimage from one chain to claim on another) is handled by asymmetric timeouts, identical to the standard practice in Lightning Network HTLCs.

Timeout griefing. A locker can create a hashlock with a very short timeout (e.g., current height + 1), share the hash, and reclaim almost immediately. The recipient has at most one block to discover the lock, obtain the preimage, and broadcast a claim. The protocol does not impose a minimum timeout beyond "strictly greater than current height" — applications should enforce minimum timeout windows appropriate to their use case. The protocol does impose a maximum: timeouts cannot exceed 262,800 blocks (~5 years) from creation. This bounds the lifetime of every lock in the system.

Root of trust. The on-chain GENESIS transaction is the sole root of trust for the entire protocol. Its 32-byte parameters hash commits to every consensus-critical value: the scoring bundle, domain pricing, fee schedules, and the treasury address. The scoring bundle hash transitively commits the WASM binary, the Coglex token table, all model weights, and all scoring test vectors via the bundle's internal manifest.

The verification chain is: GENESIS transaction (on Bitcoin blockchain) → genesis parameters hash → scoring bundle hash → bundle manifest → individual artifact hashes. This chain is self-contained — verifying it requires only a Bitcoin full node and the published scoring bundle.

No website, DNS record, social media account, or distribution channel is authoritative. A rival who controls every website, every social media handle, and the top search results for "Cogcoin" still cannot produce artifacts that match the on-chain hash without the original author's cooperation.

Malicious indexer distribution. A rival can distribute a modified indexer binary that hardcodes a different treasury address, skips the genesis hash check, and operates normally in every other respect. Users who download and run this binary would send domain registration fees to the rival's address, and subdomain registrations could be processed without the required COG burn.

The protocol cannot prevent this — a malicious binary can do anything. The answer is the same as Bitcoin Core's: verify the source. The scoring bundle includes scoring conformance test vectors that verify correct WASM execution, and state transition test vectors are published in @cogcoin/vectors (test vectors are not part of @cogcoin/genesis and may be expanded) to verify correct indexer behavior.

Conforming indexer implementations MUST verify the genesis parameters JSON hash against the on-chain GENESIS transaction at startup; this check MUST NOT be bypassable via configuration flag or environment variable. An indexer that allows the hash check to be skipped is non-conforming.

Post-quantum migration. PQ_COMMIT (Section 5.18) stores a 32-byte commitment on an anchored domain, binding it to a post-quantum key pair and migration secret known only to the legitimate owner. The commitment is one-time and irreversible (first-commit-wins). PQ_MIGRATE (Section 5.19) will consume this commitment to migrate the domain's address to a post-quantum key when Bitcoin supports post-quantum transaction signing. The protocol does not prescribe how the commitment is constructed -- it stores 32 opaque bytes. The security model requires only that the PQ key and migration secret are not derivable from the classical key associated with the anchored domain.

Protocol impersonation. A rival can publish their own GENESIS transaction with their own treasury address, their own whitepaper, and their own indexer — effectively forking the protocol. The two protocols coexist on the same Bitcoin blockchain with different genesis parameters hashes. Each indexer ignores the other's GENESIS transaction.

The signed genesis announcement (Section 6.3) commits the real author's secp256k1 public key in the genesis parameters. The announcement signature is verifiable by anyone. A rival cannot produce a valid signature from the real author's key. Users who verify the announcement signature can distinguish the real protocol from any impersonator. This is a social defense, not a technical one — it requires users to perform the verification.

1.13 A Native Language for Commerce

Most protocols define a ledger. Some define an asset. Very few define a language.

Cogcoin did not begin with the ambition to invent one. The immediate problem was less glamorous: fitting a sentence onto the world's most expensive storage. The Coglex emerged from that constraint, compressing 40 tokens of natural English into exactly 60 bytes.

It turns out that if you need to tell good writing from bad, you need a language. Suddenly, domains can anchor a founding statement. Reputation can carry reviews. Fields can make declarations. No agent needs to visit a website to read them. Marketing is now a transaction, no longer a department.

The Coglex is narrow on purpose. A bounded vocabulary and fixed-width packing force every on-chain statement to be legible to humans, parseable by agents, and expensive enough to be used deliberately. The BIP-39 base wordlist contains no profanity. Civil language by construction, not by committee.

Agents need compact ways to state who they are, what they offer, what they guarantee, and why they should be trusted. The only cryptocurrency the Coglex can name is Bitcoin #4041. The only person it can name is Satoshi #1531. Agents will build the economy their language lets them describe.

Commerce becomes easier to parse because institutions become easier to state. What a domain declared on day one is still readable, in the same format, by any agent on day ten thousand.

Most protocols move value. Cogcoin also moves meaning. All because a sentence needed to fit in 60 bytes.

The rest of this document specifies, in full detail, how the protocol works.


2. Protocol Overview

2.1 Byte Budget

Cogcoin limits itself to 80 bytes of OP_RETURN data per transaction. Every Cogcoin transaction uses this space as follows:

[Protocol Header: 3 bytes] [Operation Type: 1 byte] [Payload: up to 76 bytes]

The header identifies the transaction as Cogcoin. The operation type determines how the payload is parsed. The payload carries operation-specific data.


3. Protocol Header

3.1 Magic Bytes

Bytes 0–2 of every Cogcoin OP_RETURN:

0x43 0x4F 0x47
 C    O    G

0x43 0x4F 0x47 = ASCII "COG" — the protocol identifier.

OP_RETURN data extraction (consensus-critical). The indexer scans a transaction's outputs to find the Cogcoin output. The procedure is consensus-critical and MUST be followed exactly.

The indexer walks the transaction's outputs in index order (0, 1, 2, ...). For each output, it applies the following steps. If a step says "skip," the indexer advances to the next output and restarts from step A. If a step says "stop," no further outputs are examined.

Step A: OP_RETURN check. If the output's scriptPubKey does not begin with the OP_RETURN opcode (0x6a) as its first byte, skip. Scripts that begin with OP_FALSE (0x00) followed by OP_RETURN (0x00 0x6a ...), sometimes used by other protocols, are NOT OP_RETURN outputs and MUST be skipped — even if a Bitcoin library classifies them as "OP_RETURN" outputs.

Step B: Data push extraction. Examine the byte immediately after the OP_RETURN opcode (scriptPubKey[1]). If no byte follows (script is exactly 0x6a), or if the byte is not a recognized push opcode (OP_PUSH_1 0x01 through OP_PUSH_75 0x4b, OP_PUSHDATA1 0x4c, OP_PUSHDATA2 0x4d, or OP_PUSHDATA4 0x4e), skip. If the script uses multiple data pushes after OP_RETURN, only the first push is read.

Step C: Malformed pushdata (consensus-critical). For OP_PUSH_1 through OP_PUSH_75, the opcode byte is the declared length. For OP_PUSHDATA1, read 1 byte after the opcode as uint8 length. For OP_PUSHDATA2, read 2 bytes after the opcode as uint16 little-endian length. For OP_PUSHDATA4, read 4 bytes after the opcode as uint32 little-endian length.

If insufficient bytes remain in the scriptPubKey to read the length field, or if the declared length exceeds the bytes remaining after the length field, the push is malformed and no data can be extracted. Skip. An implementer who reads fewer bytes than declared, or who reads all remaining bytes as the push payload, will diverge from an implementer who skips. The correct behavior is to skip.

On success, the extracted data is the number of bytes equal to the declared length, read immediately following the opcode byte (for OP_PUSH_1 through OP_PUSH_75) or immediately following the length field (for OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4).

Step D: Size validation. The extracted data must be between 4 and 80 bytes inclusive. If the data is shorter than 4 bytes or longer than 80 bytes, skip.

Step E: Magic byte check. If the extracted data does not begin with 0x43 0x4F 0x47 (ASCII "COG"), skip.

Step F: Cogcoin output found. Stop. This output is the Cogcoin output. No further outputs are examined. A transaction produces at most one Cogcoin operation.

3.2 Operation Type Byte

Byte 3 specifies the operation:

Op CodeNameDescription
0x00GENESISProtocol activation (once, at genesis height 937,337)
0x01MINEMining sentence submission
0x02COG_TRANSFERTransfer Cogcoin to another address
0x03COG_LOCKLock Cogcoin in conditional escrow
0x04COG_CLAIMClaim or reclaim a COG_LOCK
0x05DOMAIN_REGDomain registration
0x06DOMAIN_TRANSFERDomain ownership transfer
0x07DOMAIN_SELLList domain for resale (Cogcoin)
0x08DOMAIN_BUYBuy a listed domain (Cogcoin)
0x09FIELD_REGRegister a field under a domain
0x0ADATA_UPDATEWrite data to a domain field
0x0BSET_ENDPOINTPublish agent endpoint URI
0x0CREP_COMMITBurn Cogcoin for domain reputation
0x0DREP_REVOKERevoke support for a domain
0x0ESET_CANONICALSet preferred canonical domain for sender address
0x0FDOMAIN_ANCHORAnchor domain permanently
0x10SET_DELEGATEDesignate delegate address for an anchored domain
0x11SET_MINERDesignate mining-only address for an anchored root-level domain
0x12PQ_COMMITStore post-quantum migration commitment on anchored domain
0x13PQ_MIGRATEMigrate anchored domain to post-quantum address
0x140xFFIgnored by the indexer

Bytes 4–79 are the operation-specific payload. Unused trailing bytes SHOULD be 0x00.

"Silently ignored" (definition). Throughout this document, "silently ignored" means the indexer skips the transaction with no error, no state change, and no fee burned. The transaction remains on the Bitcoin blockchain but has no Cogcoin effect. Subsequent uses of "ignored," "rejected," and "invalid" in validation rules carry this same meaning — all indicate the same behavior.

Payload size validation (consensus-critical). The OP_RETURN data must be between 4 and 80 bytes inclusive (Section 3.1 step D). Data outside this range causes the output to be skipped during extraction. Within that range, the indexer MUST verify that the data contains enough bytes for the operation's fixed fields plus any variable-length fields implied by length prefixes (e.g., the scriptPubKey length byte in COG_TRANSFER determines how many bytes follow). If the data is shorter than the minimum required for the operation type, the transaction is silently ignored. Attempting to parse past the end of the OP_RETURN data is an implementation bug that breaks consensus.

Trailing bytes (consensus-critical). Unless an operation explicitly consumes the remaining bytes (e.g., SET_ENDPOINT URI, DATA_UPDATE value) or defines an exact-length special case (e.g., SET_ENDPOINT / SET_DELEGATE / SET_MINER clear at exactly 4 payload bytes), bytes beyond the parsed fields are ignored. Indexers MUST parse the extracted OP_RETURN bytes exactly as present and MUST NOT trim trailing zero bytes before operation parsing. The "unused trailing bytes SHOULD be 0x00" recommendation above is guidance for transaction constructors, not a license for indexers to normalize payloads.

Null ID rule (consensus-critical). Domain ID 0, field ID 0, and lock ID 0 are reserved null values and are always invalid in operation payloads. Any operation that references domain ID 0, field ID 0, or lock ID 0 is silently ignored by the indexer. This rule applies universally to all 20 operations — there are no exceptions.


4. Address Model

4.1 Bitcoin Addresses as Identities

Cogcoin does not introduce its own address format. Every Cogcoin identity is the raw prevout scriptPubKey of a Bitcoin output. The "actor" of a Cogcoin transaction is determined by the scriptPubKey of the output spent by the first input of the Bitcoin transaction (the "sender address").

Cryptographic agnosticism. The protocol does not interpret, parse, or validate scriptPubKey contents. It treats them as opaque byte strings. P2PKH, P2WPKH, P2TR, and any future Bitcoin address type — including post-quantum — function as Cogcoin identities without protocol changes. Cogcoin attaches a human-readable name and structured data to an address. What algorithm secures that address is Bitcoin's concern, not Cogcoin's.

4.1.1 Sender Address Extraction (Consensus-Critical)

The sender address is derived from input 0 of the Bitcoin transaction. The sender identity is the raw scriptPubKey bytes of input 0's prevout — the exact bytes that appear in the Bitcoin output being spent. This is the Bitcoin consensus-level representation. Every Bitcoin node stores, validates, and agrees on these bytes. No encoding conversion is performed. All indexers MUST use this extraction to produce identical sender identities.

Address identity is the raw scriptPubKey. Two addresses are equal if and only if their scriptPubKey bytes are byte-identical. P2PKH and P2WPKH outputs derived from the same private key produce different scriptPubKey bytes and are distinct Cogcoin identities. This matches Bitcoin's own model — 1... and bc1q... addresses are different destinations with different on-chain representations. Human-readable address strings are a display convenience — the protocol operates on raw scriptPubKey bytes exclusively.

A user who registers a domain from a P2PKH input cannot operate it from a P2WPKH input without first transferring the domain. All address comparisons in the indexer — balance lookups, ownership checks, domain operations — compare raw scriptPubKey bytes. Two inputs with different prevout scriptPubKeys are different actors with separate balances and separate domain ownership. Reputation is a property of domains, not addresses (Sections 5.13–5.14).

Prevout requirement. The sender's scriptPubKey is part of the previous output being spent, not the spending transaction's scriptSig or witness data. Indexers that process full blocks have the prevout data available. SPV implementations must either maintain a UTXO set for address derivation or request prevout data from peers.

Coinbase transactions. The coinbase transaction (index 0 in every block) has no real inputs — its input references the null outpoint. Sender address extraction is impossible. Any Cogcoin OP_RETURN in a coinbase transaction is silently ignored.

Empty scriptPubKey. If the prevout scriptPubKey is empty (zero bytes), the Cogcoin transaction is silently ignored.

Maximum scriptPubKey size. If the prevout scriptPubKey exceeds 67 bytes, the Cogcoin transaction is silently ignored. This matches the maximum recipient scriptPubKey size in COG_TRANSFER and DOMAIN_TRANSFER payloads (80 - 13 = 67), ensuring that any identity that can act as a sender can also receive COG. All standard Bitcoin script types fit well within this limit — the largest is 42 bytes (SegWit v16 with a 40-byte witness program).

Address encoding in payloads. Operations that encode a recipient address in the OP_RETURN payload (COG_TRANSFER, DOMAIN_TRANSFER, SET_DELEGATE, SET_MINER) use a length-prefixed format: a 1-byte length prefix (uint8) followed by the raw scriptPubKey bytes. The recipient's wallet software converts the user's human-readable address to scriptPubKey bytes before constructing the transaction. The indexer stores the bytes as received. Operations validate that the recipient scriptPubKey is at most 67 bytes (matching the sender cap above), ensuring symmetric identity — any address that can receive can also send.

4.2 Treasury ScriptPubKey

The protocol defines a single treasury scriptPubKey: the sender identity of the GENESIS transaction, extracted via the standard sender identity mechanism (Section 4.1.1), i.e. the raw prevout scriptPubKey of input 0. All root-level domain registration fees are sent to a transaction output whose scriptPubKey is byte-identical to this treasury scriptPubKey. Subdomain registrations burn Cogcoin directly and do not involve the treasury.

The genesis parameters JSON also contains a treasury_address field. That field is part of the locked genesis parameters and is committed by hash in the GENESIS transaction. Conforming implementations MUST verify that the JSON treasury_address decodes to the same scriptPubKey as the sender-derived treasury scriptPubKey. If they differ, this 0x00 candidate fails activation and scanning continues (Section 6.1.2 rule 4). The treasury scriptPubKey is extracted from the blockchain itself and is immutable once the protocol activates.

4.3 Cogcoin Balance Model

Cogcoin balances are tracked by the indexer, not by Bitcoin UTXOs. The indexer maintains a ledger:

  • Mining rewards credit the sender address of the mining transaction. The sender must be the owner, delegate (Section 5.16), or designated miner (Section 5.17) of the anchored root-level domain specified in the MINE payload (Section 5.1.2 rule 4).
  • Bootstrap awards credit the sender address upon domain anchoring (flat 0.1 COG per root domain anchor, while the bootstrap pool lasts). Subdomain anchoring does not receive bootstrap.
  • Burns (data writes, commitments, field registration, subdomain registration) debit the sender address.
  • Transfers move Cogcoin from sender to a recipient address via COG_TRANSFER.
  • Domain resale transfers Cogcoin from buyer to seller via DOMAIN_BUY.
  • Conditional lock resolution credits the appropriate address when a COG_LOCK is resolved via COG_CLAIM (recipient claims with preimage before timeout, or locker reclaims after timeout).

Cogcoin balances are simple:

available_balance(addr) = cogcoin_balances[addr]

The cogcoin_balances map stores the spendable balance. Credits (mining rewards, bootstrap awards, incoming transfers, domain resale proceeds, COG_CLAIM resolutions) increment the value. Debits (transfers, burns, fees, COG_LOCK escrows) decrement it. COG held in active locks exists in the cog_locks state, not in any balance — it returns to a balance when the lock is resolved via COG_CLAIM.

All operations that debit the sender check this balance. This includes: COG_TRANSFER, COG_LOCK (escrow amount), DATA_UPDATE (flat fee for writes; clears are free and require no COG balance), FIELD_REG (registration fee), REP_COMMIT, DOMAIN_BUY (purchase price), and DOMAIN_REG (subdomain burn). COG_LOCK debits are not burns — the escrowed COG is returned to a spendable balance when the lock is resolved via COG_CLAIM.

The indexer computes balances by scanning all valid Cogcoin transactions from genesis forward.


5. Operation Specifications

Byte offset convention. Payload formats in Sections 5.2-5.19 use payload-relative offsets, where byte 0 is the first byte after the operation type byte (OP_RETURN byte 4). Section 5.1 (MINE) uses absolute OP_RETURN offsets and states this explicitly. Section 10 provides all layouts with absolute OP_RETURN offsets for cross-reference.

5.1 MINE (0x01) — Mining Sentence Submission

Mining is the core Cogcoin emission mechanism. Miners generate English sentences using large language models (LLMs), encode them using the Coglex, and submit them to the blockchain.

5.1.1 Payload Format

The payload consists of 4 bytes identifying the mining root domain, 4 bytes of block reference, 60 bytes of encoded sentence, and up to 8 bytes of optional miner data. All byte offsets in this section are absolute (from byte 0 of the OP_RETURN data):

Bytes 4–7:   Mining root domain ID (uint32, big-endian). The anchored root-level domain the miner is submitting under. See validation rule 4.

Bytes 8–11:  Reference blockhash fragment (bytes 0–3 of block H-1's blockhash, internal byte order — NOT display order). Must match the block immediately preceding the confirmation block. No match = invalid.

Bytes 12–71: Sentence payload (60 bytes = 40 × 12-bit token IDs)

Bytes 72–79: Miner data (0–8 bytes, optional, ignored by the indexer)

Minimum: 3 (header) + 1 (op) + 4 (domain ID) + 4 (fragment) + 60 (sentence) = 72 bytes. Maximum: 72 + 8 (miner data) = 80 bytes.

Miner data. Bytes 72–79 (if present) are not validated by the indexer and do not affect scoring. Miners may use them for any purpose: vanity tags, nonces, hash pointers, counters, or arbitrary data. These bytes are inscribed on the Bitcoin blockchain alongside the sentence. Miner data is not part of consensus state — it does not appear in mining_pending, is not included in any state hash field, and does not affect any validation or settlement rule. Indexers may retain miner data for explorer or history purposes, but conforming implementations are not required to store it and MUST NOT include it in any consensus-critical computation. A MINE transaction with no miner data (exactly 72 bytes) is equally valid.

Fragment validation. The 4-byte fragment must match bytes 0–3 of block H-1's blockhash (internal byte order), where H is the block containing the MINE transaction. The indexer checks exactly one block. The fragment serves as a commitment check: it proves the miner knew the previous block's hash when constructing the submission. A submission whose fragment does not match H-1 is invalid, regardless of whether it matches any other recent block.

5.1.2 Validation Rules

All byte offsets below are absolute (from byte 0 of the OP_RETURN data):

  1. Header check. Bytes 0–2 = 0x434F47.

  2. Op check. Byte 3 = 0x01.

  3. Size check. The OP_RETURN data must be at least 72 bytes (header + op + root domain ID + fragment + sentence). Payloads shorter than 72 bytes are rejected. Bytes 72–79, if present, are miner data.

  4. Mining root domain. Bytes 4–7 are the mining root domain ID (uint32, big-endian). The domain must satisfy all of the following: (a) domain ID > 0 and < next_domain_id, (b) anchored, (c) root-level (domain name contains no hyphens), and (d) the sender is the domain's owner, delegate (Section 5.16), or designated miner (Section 5.17). If any condition fails, the MINE transaction is ignored. The mining root domain ID is used for BIP-39 word assignment (Section 5.1.3) and per-domain deduplication (rule 10).

  5. Blockhash fragment. Bytes 8–11 are compared against bytes 0–3 of the blockhash at height tx_block_height - 1 (internal byte order, i.e., the raw SHA256d output — not the display order shown by block explorers). If the fragment matches, the referenced block is H-1. If it does not match, the transaction is invalid. All valid MINE transactions in block H reference the same block (H-1) and compete under the same scoring blend.

  6. Sentence bytes. Bytes 12–71 are the 60-byte sentence payload passed to the WASM module. The indexer does not decode, validate, or interpret these bytes — the WASM module handles all Coglex processing (see Section 5.1.6).

  7. BIP-39 word indices. The indexer computes the 5 required BIP-39 word indices (Section 5.1.3) and passes them to the WASM module alongside the raw sentence bytes. The WASM module verifies that the decoded sentence contains all 5 words.

  8. WASM validation. The WASM module performs: bit unpacking (40 × 12-bit token IDs), trailing zero stripping, Coglex decoding, canonical encoding verification (encode(decode(token_ids)) == token_ids), BIP-39 word checking, and all quality gates. If any check fails, the submission is rejected.

    Validation timing. Rules 1–7 are evaluated at transaction processing time (when the MINE transaction is encountered in the block). Rule 8 (WASM validation and scoring) is executed at settlement time as part of the reward distribution procedure (steps 3–4 of Section 5.1.4). Submissions that pass rules 1–7 are stored in mining_pending; WASM validation and scoring happen when the block is settled. Submissions that fail quality gates are discarded before ranking.

  9. Miner data. Bytes 72–79 (if present) are not validated. Any content is accepted. The OP_RETURN may end at byte 71 (no miner data) or at any byte up to 79. Only bytes 72–79 are stored as miner data. Outputs with OP_RETURN data exceeding 80 bytes are skipped during extraction (Section 3.1 step D) before reaching this rule.

  10. One reward per domain per block. If a domain is used in multiple valid MINE transactions in the same block, all are stored in mining_pending but only the highest-scoring one is considered at reward time. The indexer handles per-domain deduplication. If two submissions using the same mining root domain produce the same canonical_blend value, the submission with the lower transaction index in the block is kept.

5.1.3 BIP-39 Word Assignment

seed = SHA256(referenced_blockhash || domain_id as uint32 BE)

Where referenced_blockhash is the full 32-byte blockhash in internal byte order (the same representation used for the fragment in Section 5.1.1), and domain_id is the mining root domain ID from the MINE payload (bytes 4–7), serialized as uint32 big-endian (4 bytes). Domain IDs are sequential integers assigned by the protocol at registration time and cannot be chosen by the miner.

indices = []
for i in 0..4:
    chunk = seed[i*4 : i*4+4]   # 4 bytes
    index = uint32_be(chunk) % 2048
    while index in indices:
        index = (index + 1) % 2048
    indices.append(index)
words = [BIP39_ENGLISH_WORDLIST[i] for i in indices]

The referenced blockhash that determines BIP-39 words also determines the scoring blend (Section 5.1.4). The same block is the source for both derivations.

The assignment is deterministic: given the blockhash and the mining root domain ID, anyone can compute which 5 words the miner must use. Different mining domains get different words (because their domain IDs differ). A miner cannot choose which words they get — domain IDs are assigned sequentially by the protocol and blockhashes are unpredictable.

5.1.4 Scoring and Reward Distribution

Scoring uses the 256-scorer blend described in the Cogcoin Scoring Module. All valid MINE transactions included in Bitcoin block H are scored using blend weights determined by the blockhash of block H-1:

blend_seed = SHA256(referenced_blockhash)

Where referenced_blockhash is the full 32-byte blockhash of block H-1 in internal byte order, verified by the 4-byte fragment (Section 5.1.2). All miners in block H reference the same block (H-1) and are scored under the same blend. Each produces a uint64 canonical_blend value. These values are ranked directly.

Reward distribution:

Each Bitcoin block at height H (where H ≥ activation_block) produces exactly one Cogcoin block reward. The activation block is the block containing the confirmed GENESIS transaction (see Section 6.1). The reward goes to the best sentences included in block H. All MINE transactions in block H reference block H-1.

The reward for block H is settled at the end of block H processing, after all Cogcoin transactions in block H have been applied. At that point:

  1. Collect all valid MINE transactions from block H.
  2. Compute blend_seed = SHA256(blockhash of H-1).
  3. Score all sentences using score_sentences_wasm with the blend_seed.
  4. Pool all scored submissions. Discard gate failures.
  5. One sentence per mining root domain (keep highest canonical_blend; on equal score, keep lower transaction index).
  6. Rank all qualifying submissions by canonical_blend (uint64) descending. Ties broken by SHA256(blend_seed || domain_id as uint32 BE), lower hash wins, where domain_id is the mining root domain ID from the MINE payload.
  7. Top min(5, qualifying) are winners.
  8. Distribute reward using fixed rank-weights (see Section 5.1.5). Increment total_minted_cog by the sum of all distributed shares. Increment total_cog_supply by the same amount. Update balance_xor for each credited address (Section 7.6).
  9. If no winners: the block reward is never minted.

Reward timing (consensus-critical): Mining rewards for block H are settled at the end of block H processing, after all Cogcoin transactions in block H have been applied. A miner cannot spend block H rewards until block H+1 at the earliest. This ordering is visible in the indexer pseudocode (Appendix B): settle_mining_rewards runs after the transaction loop within the same block.

Block reward schedule: Cogcoin emissions mirror Bitcoin's block subsidy exactly, denominated in cogtoshi (1 COG = 100,000,000 cogtoshi, same as satoshi). The Cogcoin block reward for Bitcoin block H equals the Bitcoin block subsidy at block H, in cogtoshi. Since Cogcoin's genesis height is Bitcoin block 937,337, only the remaining emissions from that point forward are captured, yielding approximately 1,010,000 COG from mining. Combined with the 100,000 COG bootstrap pool, total max supply is approximately 1,110,000 COG.

Denomination:

1 cogcoin = 100,000,000 cogtoshi  (same ratio as 1 BTC = 100,000,000 satoshi)

Emission schedule: For each Bitcoin block at height H (where H ≥ activation_block), the Cogcoin block reward in cogtoshi equals the Bitcoin block subsidy in satoshi at that height:

halving_era = H / 210,000  (integer division)
block_reward_cogtoshi = 5,000,000,000 >> halving_era  (right-shift = halve)

When halving_era reaches 33 or higher, the right-shift produces zero. From that point onward, no mining rewards are distributed. The indexer does not perform mining settlement for blocks with a zero reward — no submissions are processed and mining effectively ends. For blocks where the computed reward is zero, the indexer MUST discard any entries in mining_pending for that block without performing settlement. Equivalently, the indexer MAY skip adding MINE transactions to mining_pending entirely when the block reward is zero.

Cogcoin launched at Bitcoin block height 937,337 (4th halving era, which spans blocks 840,000–1,049,999). By this point, the vast majority of Bitcoin's 21M supply has already been mined. Cogcoin only captures the remaining emissions from the activation block forward. The total cogtoshi emitted via mining equals the total satoshi left to be mined from the activation block onward — approximately 1,010,000 COG.

Mining supply:    ~1,010,000 COG  (activation at block 937,337)
Bootstrap supply:    100,000 COG
Total max supply: ~1,110,000 COG

Per-block rewards at activation (block 937,337, 4th halving era):

  • 312,500,000 cogtoshi per block (3.125 COG)
  • Halving continues on Bitcoin's 210,000-block schedule thereafter.
  • At the 5th halving (block 1,050,000): 156,250,000 cogtoshi per block (1.5625 COG).

5.1.5 Reward Distribution Ratios

The top 5 sentences per block split the reward using fixed rank-weights. Ranking is determined by the 256-scorer blend — ordinal position is what matters, not score magnitude.

RankWeight
1st50
2nd20
3rd15
4th10
5th5

Weights sum to 100. Each winner's share = weight / Σ(active weights).

Fewer than 5 winners: If only N winners qualify (N < 5), the absent ranks' weights are discarded. The N winners split the full reward using only their rank-weights. Example: 3 winners use weights [50, 20, 15] → sum=85 → shares: 50/85, 20/85, 15/85 of the block reward.

Zero submissions: If a block has zero qualifying submissions (no valid MINE transactions, or all fail quality gates), no reward is distributed. The block reward for that block is never emitted — it is lost, reducing total supply below the theoretical maximum. The @cogcoin/scoringsettleBlock function returns an empty list for this case.

Tie-breaking: If two submissions have identical canonical_blend values (uint64), the tie is broken by the lexicographic order of SHA256(blend_seed || domain_id as uint32 BE), where blend_seed = SHA256(blockhash of H-1) and domain_id is the mining root domain ID from the MINE payload. Lower hash value wins the higher rank. All submissions in the same block share the same blend_seed. After per-domain deduplication, all mining domains in the ranking are unique.

Deterministic integer rounding (consensus-critical):

The following procedure converts rank-weights into exact cogtoshi amounts. It is implemented in the @cogcoin/scoring settlement logic and verified by conformance test vectors.

RANK_WEIGHTS = [50, 20, 15, 10, 5]

Given N winners (1 ≤ N ≤ 5), ranked by score (ties broken as above):

1. active_weights = RANK_WEIGHTS[0:N]
   total_weight = sum(active_weights)

2. Allocate shares by rank (rank 1 first):
     remaining = block_reward_cogtoshi
     remaining_weight = total_weight
     For i = 0 to N-1:
       share_i = floor(remaining x active_weights[i] / remaining_weight)
       remaining -= share_i
       remaining_weight -= active_weights[i]

3. Any leftover cogtoshi (due to integer division) is absorbed by the
   last-processed winner (lowest rank). This is at most N-1 cogtoshi.

This procedure uses only integer arithmetic (uint64 is sufficient — the maximum intermediate product is block_reward x 50, which fits in uint64 for any reward up to ~3.7 × 10^17 cogtoshi). No floating-point operations are involved in reward distribution.

Late-era reward distribution. At very small block rewards (below ~5 cogtoshi, occurring only in halving eras 30+), the floor-based division allocates 0 to higher-ranked winners and concentrates the remainder in lower ranks. For example, a 1-cogtoshi block reward goes entirely to the lowest-ranked winner. This is a mathematical consequence of integer division. The amounts involved at these eras are economically negligible — halving era 30 begins at block 6,300,000, roughly 102 years after Cogcoin's activation.

5.1.6 Scoring Architecture

The Cogcoin Scoring Module is a self-contained, immutable bundle that evaluates every mining submission. Its SHA-256 checksum is committed in the genesis parameters. Any node can verify it holds the canonical bundle.

Three tiers. The 256 scorers are organized into three tiers:

Tier 1: Hard Gates. Binary pass/fail checks. A submission that fails any gate is rejected before scoring. Gates enforce structural validity, BIP-39 word compliance, anti-degenerate constraints, and quality floor requirements.

Tier 2: Statistical Scorers. Each scorer produces a uint16 in [0, 65535]. Tier 2 covers categories including n-gram likelihood, pointwise mutual information, syntactic patterns, lexical diversity, information-theoretic measures, prosodic/rhythmic analysis, BIP-39 integration, ensemble meta-scorers, LLM-distance measures, clause structure, semantic density, and cross-domain consistency.

Tier 3: Neural Models. Multiple architectures to prevent shared blind spots. All operate on raw token IDs with no preprocessor dependency. Adversarially hardened models are trained using LLM-generated constrained sentences as negative examples.

The number of scorers in each tier, the slot assignments, the neural model architectures, and all other internal details are defined in the scoring module specification, not in this document. The scoring module is committed by SHA-256 hash in the genesis parameters and is the authoritative source for all scoring internals.

Blend derivation. For each mining submission, the scoring blend is determined by the blockhash of block H-1:

  1. Compute blend_seed = SHA256(referenced_blockhash).
  2. Expand: SHA256(blend_seed || counter) for counters 0–7, producing 256 bytes.
  3. Each byte maps to a scorer. Activation thresholds and tier-to-byte mappings are defined in the scoring module specification. Not all scorers are active in every blend; activation is sparse and varies per block.
  4. For each active scorer i: raw_weight_i = byte_i + 1 (uint16, range 1–256). Compute the integer blend: canonical_blend = Sigma(uint32(scorer_output_i) * uint32(raw_weight_i)) for all active scorers. This uint64 value is the consensus-critical ranking score — no division or float normalization is performed.

Integer-Canonical Scoring Protocol (ICSP). The entire consensus-critical path uses only integer arithmetic:

  • Every scorer produces a uint16 output in [0, 65535]. This is the canonical score.
  • The blend is an integer weighted sum computed in a uint64 accumulator. No division. No float normalization.
  • Rankings compare canonical_blend values (uint64) directly. Ties are broken by SHA256(blend_seed || domain_id as uint32 BE) where blend_seed = SHA256(referenced_blockhash) and domain_id is the mining root domain ID from the MINE payload.
  • Reward distribution uses integer arithmetic (uint64) with floor division.
  • No floating-point value is ever compared, sorted, or used in any consensus decision.

Canonical scoring method. The @cogcoin/scoring npm module is the canonical implementation of mining reward settlement. Conforming indexers MUST use @cogcoin/scoring for all mining settlement, or produce byte-identical results verified against the settlement conformance test vectors distributed with the module.

The module contains:

  • The immutable WASM binary (cogcoin_scoring.wasm) and model blob (cgsm_blob.bin), hash-committed on-chain in the genesis parameters. These implement the 256-scorer ensemble, all quality gates, and the blend computation. The WASM binary's score_sentences_wasm function is the consensus-critical entry point for sentence scoring.

  • The settlement logic (TypeScript), which orchestrates scoring, deduplication, ranking, tie-breaking, and reward distribution. This logic uses only integer arithmetic and is verified by conformance test vectors.

Consensus warning. The WASM binary also exports settle_block_wasm for tooling only. Conforming indexers MUST NOT use it for mining reward settlement — it uses incompatible address serialization, incompatible rank weights, and address-based rather than domain-based word assignment, deduplication, and tie-breaking. An indexer that uses it will diverge on the first block. The only consensus-critical scoring entry point is score_sentences_wasm. This restriction is stated in the signed genesis announcement clarifications section.

Alternative implementations. Indexers not using the @cogcoin/scoring npm module directly (e.g., indexers written in Go, Rust, or Python) MUST:

  1. Load and execute the canonical WASM binary for all sentence scoring via score_sentences_wasm.
  2. Reimplement the settlement logic (dedup, ranking, tie-breaking, reward distribution) and verify byte-identical output against every settlement conformance test vector.
  3. Native reimplementations of the scoring pipeline (the 256 scorers, quality gates, blend computation) are non-conforming. Only the WASM binary may perform scoring.

Settlement conformance test vectors are distributed with the @cogcoin/scoring module and are consensus-critical. An indexer that does not produce byte-identical reward entries for every vector is non-conforming. These vectors cover settlement, deduplication edge cases, tie-breaking, and reward distribution arithmetic.

The WASM binary's SHA-256 hash is recorded in the scoring bundle manifest and is transitively committed on-chain via the genesis parameters. Any indexer can verify it holds the canonical binary.

Rationale. The scoring module contains 256 scorers, including neural models with int8 weights, lookup-table activations, and statistical models using deterministic math. The Coglex encoding/decoding involves morphological composition rules that go beyond simple table lookups. Reimplementing any of the scoring logic in native code across languages and platforms creates an unbounded surface for subtle divergence. WASM eliminates this risk: all conforming indexers execute identical compiled code for scoring.

The settlement logic (deduplication, ranking, tie-breaking, reward distribution) is trivial integer arithmetic — approximately 50 lines in any language. This is separated from the WASM binary so that the settlement pipeline remains independently verifiable. The settlement logic is verified by conformance test vectors. The reimplementation surface is minimal and fully testable.

WASM floating-point determinism. The WASM specification defines NaN bit patterns as nondeterministic — different runtimes may produce different NaN payloads. The WASM binary MUST NOT produce or propagate NaN values at any point during execution.

If any intermediate floating-point operation would produce NaN (e.g., 0.0/0.0, sqrt(-1.0)), the binary must handle it before it reaches an output — typically by ensuring such operations never occur through input validation and guarded math. If NaN occurs in any scorer output despite these safeguards, the binary causes the sentence to fail all gates.

This is an internal WASM guarantee, not an indexer-enforced check — the indexer calls score_sentences_wasm and trusts the returned scores without inspecting individual scorer outputs. The cgmath library used internally is designed to prevent NaN production; the cross-platform test vectors verify this property across runtimes.

All comparisons and accumulations use integer arithmetic exclusively — floating-point is used only within individual scorers for intermediate calculations, never for ranking, blending, or reward computation.

WASM execution requirements:

  1. The indexer MUST load and execute the canonical WASM binary from the scoring bundle. The binary's SHA-256 hash MUST match the hash in the bundle manifest.

  2. The WASM module's consensus-critical interface is score_sentences_wasm:

    score_sentences_wasm(
      sentences: list of (raw_sentence_bytes_60, bip39_word_indices_5),
      blend_seed: bytes32,
      flags: uint8
    ) -> list of (gates_pass: bool, canonical_blend: uint64)
    

    Parameter serialization (consensus-critical):

    • raw_sentence_bytes_60: bytes 12–71 of the OP_RETURN, verbatim (60 bytes).
    • bip39_word_indices_5: the 5 required BIP-39 word indices, each as uint16 little-endian (10 bytes total, each in range [0, 2047]).
    • blend_seed: 32 bytes, the output of SHA256(referenced_blockhash) in internal byte order.
    • flags: uint8. Bit 0 = verbose mode. Use 0 for consensus (compact output).

    The function returns results in input order. Each result contains a gate pass/fail flag and the uint64 canonical_blend value. The @cogcoin/scoring module calls this function once per block with all submissions and uses the returned scores for ranking and reward distribution.

    The WASM binary also exports settle_block_wasm, which combines scoring, ranking, and reward distribution for a single blend seed. This function uses an incompatible address serialization and MUST NOT be used for consensus settlement (see above).

    Coglex codec interface. The WASM binary exports two additional functions for Coglex encoding and decoding:

    encode_sentence_wasm(
        text: utf8_bytes,
        text_len: int32,
        output: bytes60
    ) -> int32  (token count on success; negative on error)
    
    decode_sentence_wasm(
        payload: bytes60,
        text_out: utf8_buffer,
        max_out_len: int32
    ) -> int32  (text length in bytes on success; negative on error)
    

    Both enforce a hard 40-token limit.

    encode_sentence_wasm takes UTF-8 text and produces a 60-byte Coglex payload of 40 Coglex token IDs at 12 bits each, with unused slots zero-padded. Returns the token count on success.

    decode_sentence_wasm takes a 60-byte Coglex payload and produces UTF-8 text with trailing zero tokens stripped. Returns the output text length in bytes on success.

    Encode error codes: -1 (invalid arguments), -2 (word not in vocabulary), -3 (exceeds 40-token limit). Decode error codes: -1 (invalid arguments), -2 (token ID out of range), -3 (output buffer too small). For consensus purposes, any negative return from either function indicates failure — the specific error code is diagnostic, not consensus-critical. Founding messages and reviews that fail decoding (any negative return) are stored as null.

    These functions are used by score_sentences_wasm internally for MINE validation (canonical encoding check: encode(decode(token_ids)) == token_ids). They are also the mandatory codec for founding messages (Section 5.8.7) and reviews (Sections 5.13.4, 5.14.5). Conforming indexers MUST use encode_sentence_wasm and decode_sentence_wasm for all Coglex encoding and decoding. Native reimplementations of Coglex encoding or decoding are non-conforming.

  3. The WASM binary has zero host imports. The scoring bundle's data files (model weights, lookup tables, metadata) are loaded into WASM linear memory at initialization: the indexer calls the exported sb_alloc(size) function to allocate space within the WASM instance, then writes the contents of the bundle's combined data blob (cgsm_blob.bin) into the returned memory region. The blob's SHA-256 hash MUST be verified against the bundle manifest at startup. Without this blob loaded into linear memory, the WASM binary cannot access model weights and cannot score sentences.

  4. The WASM module MUST NOT have access to any external state — no network, no filesystem, no randomness beyond the blend seed. The score_sentences_wasm function is a pure function: identical inputs always produce identical outputs.

  5. Cross-platform test vectors are included in the scoring bundle. An indexer MUST verify that its WASM runtime produces bit-identical results on all scoring test vectors before processing any blocks. Failure to match indicates a non-conforming WASM runtime. The scoring test vectors cover: Coglex bit unpacking, trailing zero stripping, Coglex decoding and canonical encoding verification, BIP-39 word presence checking, individual scorer outputs, gate pass/fail decisions, and blend computation. Settlement behavior (ranking, tie-breaking, reward distribution) is verified by separate settlement conformance test vectors distributed with the @cogcoin/scoring module.

Internally, the WASM binary uses the cgmath deterministic math library for any floating-point operations required by statistical scorers (logarithms, exponentials), with IEEE 754 round-to-nearest-ties-to-even, flush-to-zero disabled, and fused-multiply-add contraction prohibited. Neural model inference uses int8 weights with int32 accumulators and lookup-table activations — no floating-point operations at inference time. These are implementation details of the WASM binary, not requirements on the indexer — the indexer's only obligation regarding these internals is to execute the WASM binary via score_sentences_wasm and trust the returned scores.

The complete scoring specification — including all gate definitions, scorer formulas, model architectures, training procedures, determinism requirements, bundle format, and test vectors — is published as part of the scoring bundle within the @cogcoin/genesis package, referenced by SHA-256 hash in the bundle manifest.


5.2 COG_TRANSFER (0x02) — Transfer Cogcoin to Another Address

5.2.1 Payload Format

Bytes 0–7:   Amount of cogtoshi to transfer (uint64, big-endian)

Byte  8:     Recipient scriptPubKey length L (uint8)

Bytes 9–8+L: Recipient scriptPubKey (raw bytes)

Total: 3 (header) + 1 (op) + 8 (amount) + 1 (length) + L (scriptPubKey).

5.2.2 Validation Rules

  1. Sender's available Cogcoin balance >= amount.
  2. Amount > 0.
  3. Recipient scriptPubKey must be non-empty and at most 67 bytes (L > 0 and L ≤ 67). If the payload is shorter than 9+L bytes, the transaction is silently ignored. This matches the sender scriptPubKey size cap (Section 4.1.1), ensuring every identity that can receive COG can also send Cogcoin transactions.
  4. Sender and recipient must be different addresses.

5.2.3 Behavior

The indexer:

  1. Debits the sender's Cogcoin balance by the amount.
  2. Credits the recipient's Cogcoin balance by the amount.
  3. total_cog_supply is unchanged (debit and credit cancel). Updates balance_xor for both sender and recipient (Section 7.6).

No Cogcoin is burned. This is a pure transfer.


5.3 Conditional Payments: COG_LOCK (0x03) and COG_CLAIM (0x04)

COG_LOCK creates a conditional escrow. The sender locks Cogcoin that can only be released by revealing a preimage before a timeout. After the timeout, the sender can reclaim the locked COG. COG_CLAIM resolves an active lock, transferring the escrowed COG to the recipient (if they reveal the preimage) or returning it to the locker (if the timeout has passed).

This is a general-purpose conditional payment primitive. Applications include cross-chain atomic swaps, escrow, payment-for-service, and multi-hop payments. The protocol defines the mechanism; applications define the semantics.

5.3.1 COG_LOCK Payload Format

Bytes 0–7:   Amount of cogtoshi to lock (uint64, big-endian)

Bytes 8–11:  Timeout block height (uint32, big-endian)

Bytes 12–15: Recipient domain ID (uint32, big-endian)

Bytes 16–47: Condition: SHA-256 of the 32-byte preimage

Total OP_RETURN: 3 (header) + 1 (op) + 8 (amount) + 4 (timeout) + 4 (recipient) + 32 (condition) = 52 bytes. 28 bytes unused in the 80-byte budget. These bytes SHOULD be 0x00.

5.3.2 Lock ID Assignment

The indexer assigns the new lock next_lock_id as its permanent lock ID, then increments next_lock_id by 1. Lock IDs are sequential, starting at 1 (ID 0 is reserved/null). COG_LOCK MUST be rejected if next_lock_id equals 0xFFFFFFFF (uint32 maximum). No lock is created and no state changes occur. Lock IDs and domain IDs use separate global counters. Field IDs are per-domain (see Section 5.10.2) and occupy a separate namespace.

5.3.3 COG_LOCK Validation Rules

  1. Amount > 0.
  2. Sender's available Cogcoin balance >= amount.
  3. Timeout block height must be strictly greater than the current block height and at most current_block_height + 262800 (approximately 5 years). Locks with timeouts exceeding this cap are ignored.
  4. Recipient domain validation: The recipient domain ID must be non-zero. The domain must be anchored.
  5. Condition check: the 32-byte condition must not be all zeros. An all-zero condition is recipient-unclaimable before timeout — finding a preimage P such that SHA256(P) = 0x00...00 is computationally infeasible, so no recipient can claim the lock via the preimage path. The locker can still reclaim after timeout, but the lock serves no useful purpose as an escrow because the recipient has no viable claim path. Rejecting all-zero conditions prevents misconfigured locks that appear functional but can never be claimed by the intended recipient. Note that a preimage of all zeros is perfectly valid — its hash (SHA256(0x00...00) = 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925) is non-zero and would pass this check.

5.3.4 COG_LOCK Behavior

On a valid COG_LOCK, the indexer:

  1. Assigns next_lock_id and increments the counter.
  2. Debits the sender's Cogcoin balance by the locked amount.
  3. Records the lock in cog_locks[lock_id] with: locker address, amount, condition (32 bytes), timeout height, recipient domain ID, and creation height.
  4. Increments active_lock_count and adds the amount to total_lock_cog.
  5. Updates balance_xor for the sender (Section 7.6). total_cog_supply is unchanged (COG moves from balance to lock, not out of existence).
  6. Updates lock_xor (Section 7.6).

The locked COG is no longer in any balance. It exists only in the lock state until resolved via COG_CLAIM.

5.3.5 COG_LOCK Cost

cog_lock_fee = 0 cogtoshi

Only a standard Bitcoin transaction fee is required. The locked COG is not burned — it is held in escrow.

5.3.6 COG_CLAIM Payload Format

Bytes 0–3:   Lock ID (uint32, big-endian)

Bytes 4–35:  Preimage (32 bytes, fixed length)

Total OP_RETURN: 3 (header) + 1 (op) + 4 (lock ID) + 32 (preimage) = 40 bytes. 40 bytes unused in the 80-byte budget.

The preimage field is always present and always 32 bytes. For reclaims (locker reclaiming after timeout), the field is ignored.

5.3.7 COG_CLAIM Validation Rules

  1. Lock ID must reference an active lock (> 0, < next_lock_id, and not already resolved).
  2. Resolution depends on sender identity and block height:

Claim by recipient:

  • The sender must be the owner or delegate (Section 5.16) of the recipient domain specified in the lock.
  • The current block height must be strictly less than the lock's timeout height.
  • SHA256(preimage) must equal the lock's stored condition.
  • If all checks pass: the locked COG is credited to the sender's Cogcoin balance.

Reclaim by locker:

  • The sender must be the original locker.
  • The current block height must be >= the lock's timeout height.
  • The preimage field is ignored.
  • If all checks pass: the locked COG is credited to the sender's (locker's) Cogcoin balance.
  1. If the sender is not the recipient domain's owner, delegate, or original locker, the COG_CLAIM is ignored. If the sender is both the original locker and a recipient-authorized claimant (owner or delegate), the standard resolution rules apply: before timeout, the sender claims via the recipient path and must provide a valid preimage; after timeout, the sender reclaims via the locker path.
  2. If the lock has already been resolved, the COG_CLAIM is ignored.

5.3.8 COG_CLAIM Behavior

On a valid COG_CLAIM, the indexer:

  1. Credits the sender (recipient domain's owner or delegate, or original locker) with the lock's COG amount.
  2. Removes the lock from active state. The lock ID is consumed — it is never reassigned.
  3. Decrements active_lock_count and subtracts the amount from total_lock_cog.
  4. Updates balance_xor for the credited address (Section 7.6). total_cog_supply is unchanged (COG moves from lock to balance, not into existence).
  5. Updates lock_xor (Section 7.6).

Resolved lock metadata SHOULD be retained for historical queries but is not consensus-critical after resolution.

5.3.9 Hashlock Preimage Visibility

When a hashlock is claimed, the preimage is revealed on-chain in the COG_CLAIM transaction's OP_RETURN. This is by design — applications that use the preimage as a cross-chain coordination mechanism (e.g., atomic swaps) depend on this visibility.

Mempool front-running risk. When a recipient broadcasts a COG_CLAIM with a valid preimage, the preimage is visible in the mempool before confirmation. Only the recipient domain's owner or delegate can claim, so mempool visibility does not enable front-running on the Cogcoin side. The risk is limited to cross-chain counterparts: if the preimage is revealed on Cogcoin, a counterparty on another chain can claim before the intended party. Asymmetric timeouts give the party revealing first adequate time to claim on the second chain.

5.3.10 Domain Ownership and Anchored Domains

COG_LOCK requires the recipient domain to be anchored (Section 5.3.3 rule 4). Anchored domains cannot be transferred (DOMAIN_TRANSFER requires anchored == false) or sold (DOMAIN_SELL requires anchored == false). The recipient domain's delegate may change between lock creation and claim; the COG_CLAIM authorization check uses the current owner and delegate at claim time.

5.3.11 Cost

Both COG_LOCK and COG_CLAIM cost 0 cogtoshi. Only standard Bitcoin transaction fees are required. No COG is burned by creating, claiming, or reclaiming a lock.

5.3.12 Same-Block Ordering

COG_LOCK and COG_CLAIM can appear in the same block. The indexer processes transactions in block order. A COG_LOCK at index N and COG_CLAIM at index M (where M > N) will both succeed — the lock exists when the claim is processed.

If COG_CLAIM appears before COG_LOCK in the same block, the lock does not yet exist. The claim is silently ignored.

A COG_LOCK referencing a domain that was anchored via DOMAIN_ANCHOR earlier in the same block is valid — the domain is anchored at the time the COG_LOCK is processed.


5.4 DOMAIN_REG (0x05) — Domain Registration

5.4.1 Payload Format (up to 76 bytes)

Byte  0:     Domain name length (uint8, 1–63)

Bytes 1–N:   Domain name (ASCII lowercase a-z, 0-9, hyphens; no leading/trailing/consecutive hyphens)

Bytes N+1–:  Trailing bytes (ignored)

The DOMAIN_REG payload format is identical for domains and subdomains. The indexer determines which by checking whether the domain name contains a hyphen. Domains without a hyphen require a BTC payment to the treasury. Domains with a hyphen are subdomains and require a COG burn from the sender's balance (see Section 5.4.6).

5.4.2 Pricing

All domain registration costs are one-time. There are no renewal fees, no annual charges, and no ongoing costs. A domain, once registered, exists forever.

Domain LengthBTC Price (one-time)
1 character (36 domains)100 BTC
2 characters (~1.3K)10 BTC
3 characters (~48K)1 BTC
4 characters (~1.8M)0.1 BTC
5 characters (~60M)0.01 BTC
6+ characters0.001 BTC

Domain prices are fixed in BTC. Subdomain prices are fixed in COG (see Section 5.4.6). They do not halve, adjust, or change over time. As Bitcoin appreciates in fiat terms, domains become more expensive in fiat — this is intentional. A permanent namespace backed by Bitcoin's proof of work should become harder to claim as the substrate becomes more valuable. The fixed BTC prices also eliminate consensus-critical price calculations and remove any incentive to delay registration waiting for cheaper prices.

Subdomain pricing. Domains containing a hyphen are subdomains. The cost is fixed:

Domain TypeCostDestination
Subdomain (any length with hyphen)100 cogtoshiBurned

See Section 5.4.6 for complete rules.

5.4.3 Validation Rules

  1. Domain name is 1–63 ASCII characters, lowercase a-z, digits 0-9, hyphens (not leading/trailing, not consecutive). Uppercase letters are rejected (not silently lowercased). Digit-only names (e.g., "123") and digit-starting names (e.g., "0x") are valid. If the payload is shorter than 1+N bytes (where N is the name length byte), the transaction is silently ignored.
  2. Domain is not already registered (first valid registration wins, by transaction ordering within a block; earlier block wins across blocks). Validity requires passing all rules in this section — an earlier transaction that fails any validation rule (underpays treasury, lacks anchored parent, lacks authorization, or lacks sufficient COG balance) does not reserve the name.
  3. Payment validation. The tier is determined by the presence of a hyphen in the domain name.

DNS compatibility. These rules ensure that every valid Cogcoin domain name is also a valid DNS label per RFC 1123 and RFC 5891. Cogcoin names can be used directly as DNS subdomains with no escaping or transformation.

a) No hyphen (domain). The transaction must include an output to the treasury address paying at least the required BTC amount in satoshi. The indexer reads each output's scriptPubKey directly and compares it byte-for-byte against the stored treasury scriptPubKey (the GENESIS transaction's sender, per Section 4.1.1). If any single output's scriptPubKey matches the treasury and the output value meets the required price, the payment is valid. If multiple outputs match, the indexer checks each independently — amounts are not summed across multiple outputs. Overpayment is accepted (the excess is a donation to treasury). If no single treasury-matching output meets the required amount, the registration is ignored; underpaying matching outputs do not invalidate a later qualifying one.

b) Hyphen present (subdomain). The substring before the last hyphen is the parent prefix. The parent prefix must resolve to an anchored domain. The sender must be its owner or delegate (Section 5.16). The sender's available Cogcoin balance must be >= 100 cogtoshi. If all conditions are met, proceed to 5.4.4 for domain ID assignment, then 5.4.6 for the COG burn. If any condition fails, the registration is ignored. A subdomain registration does not require any BTC payment to treasury — the Bitcoin transaction need only cover the standard transaction fee.

Single-level minting rule (consensus-critical). The parent prefix (substring before the last hyphen) must itself be an anchored domain. A domain can only mint children with exactly one more hyphen than itself. "oracle" (0 hyphens) can mint "oracle-weather" (1 hyphen). "oracle-weather" (1 hyphen, if anchored) can mint "oracle-weather-tokyo" (2 hyphens). But "oracle" cannot directly mint "oracle-weather-tokyo" because the parent prefix "oracle-weather" must exist and be anchored. Every intermediate level must exist as an anchored domain before deeper levels can be created.

Same-block collisions: If multiple transactions attempt to register the same domain name in the same block, the first valid transaction (lowest index that passes all validation rules) wins. An earlier transaction that fails validation does not reserve the name — a later valid transaction still succeeds. For domains without a hyphen, the loser's BTC payment to treasury still confirms on the Bitcoin layer and is not refunded — the protocol has no mechanism to return Bitcoin. For subdomains, the loser's Cogcoin balance is never debited — the indexer simply skips the losing transaction. Registrants should check the mempool for competing registrations before broadcasting, and consider using higher fees to improve confirmation priority for high-value names.

5.4.4 Domain ID Assignment and Ownership

DOMAIN_REG MUST be rejected if next_domain_id equals 0xFFFFFFFF (uint32 maximum). No domain ID is assigned and no state changes occur.

The indexer assigns the new domain next_domain_id as its permanent domain ID, then increments next_domain_id by 1. Domain IDs are sequential, starting at 1 (ID 0 is reserved/null). The indexer also records domain.reg_height = [current block height] and initializes domain.next_field_id = 1 and domain.pq_hash = null. Updates domain_xor (Section 7.6).

The sender address of the registration transaction becomes the domain owner. The domain maps to this address. Domains never expire and have no renewal fees.

Unanchored and anchored domains. A newly registered domain is unanchored. An unanchored domain is a name that points to an address — it can be listed for resale (see 5.6/5.7) and transferred to a different address (see 5.5). It has no fields, no data, and no reputation. It is an unactivated, portable asset.

A domain becomes permanently anchored when its owner issues a DOMAIN_ANCHOR transaction (see Section 5.8). Anchoring is irreversible and has three consequences:

  1. The domain can never be transferred or sold. The identity behind it is permanent.
  2. The domain can now hold structured data and accumulate reputation.
  3. Users and agents who have committed reputation to the domain can trust that the controlling identity will never change.

5.4.5 Bootstrap Cogcoin Award

The bootstrap Cogcoin award is granted at DOMAIN_ANCHOR for root-level domains (Section 5.8.3 step 7). Anchoring completes domain registration — the owner commits to a permanent identity and gains the ability to hold data, fields, and reputation. The bootstrap award seeds COG at that moment.

5.4.6 Subdomain Registration

A domain name containing a hyphen is a subdomain. The substring before the last hyphen is the parent prefix. The parent prefix must correspond to an anchored domain whose owner or delegate (Section 5.16) is the sender.

Examples:

"oracle-weather"        parent = "oracle"           child suffix = "weather"
"oracle-weather-tokyo"  parent = "oracle-weather"   child suffix = "tokyo"
"oracle-weather-v2"     parent = "oracle-weather"   child suffix = "v2"
"a-x"                   parent = "a"                child suffix = "x"
"a-x-y"                 parent = "a-x"              child suffix = "y"

The parent is determined by the last hyphen. "oracle-weather-tokyo" is a child of "oracle-weather," not of "oracle." To register "oracle-weather-tokyo," the sender must be the owner or delegate of the anchored domain "oracle-weather." To register "oracle-weather," the sender must be the owner or delegate of the anchored domain "oracle." Each level of depth requires an independently anchored parent.

The child suffix (substring after the last hyphen) is always a single hyphen-free segment. Every hyphen in a domain name is structural — each one marks a level boundary in the namespace hierarchy.

Gap prevention. Because the parent is the substring before the last hyphen, there is no way to skip intermediate levels. Registering "oracle-a-b-c" requires that "oracle-a-b" exists and is anchored. Registering "oracle-a-b" requires that "oracle-a" exists and is anchored. The chain is unbroken by construction. Developers who want multi-word names at a single level should concatenate without hyphens (e.g., "oracle-pricefeed" rather than "oracle-price-feed") or use the hierarchy intentionally (e.g., register and anchor "oracle-price" as a meaningful intermediate namespace).

Validation rules (subdomain):

  1. The domain name contains at least one hyphen (determined in rule 3 of Section 5.4.3).
  2. The parent prefix (substring before last hyphen) resolves to an existing domain.
  3. That domain is anchored (domain.anchored == true).
  4. The sender is its owner or delegate (Section 5.16).
  5. The sender's available Cogcoin balance is >= 100 cogtoshi.

If any rule fails, the registration is ignored.

Behavior:

  1. Assign domain ID and set ownership per Section 5.4.4. Owner = sender.
  2. Debit sender's Cogcoin balance by 100 cogtoshi. This COG is burned, not transferred to any address. Increment total_burned_cog by 100 (state hash field, Section 7.6). Decrement total_cog_supply by 100. Update balance_xor for the sender (Section 7.6).
  3. No bootstrap award. The bootstrap pool is not affected.
  4. The new domain is unanchored. It may be transferred (DOMAIN_TRANSFER), sold (DOMAIN_SELL), or anchored (DOMAIN_ANCHOR) by the owner.

Rationale. Hyphens are structural: every hyphen marks a level of namespace delegation. The owner who anchors their domain gains the exclusive right to mint direct children — subdomains with exactly one additional hyphen. Those children, once anchored, gain the same right over their own namespace slice. This creates a protocol-native manufacturing hierarchy: the raw materials are an anchored name and COG; the finished good is a unique, permanent, tradeable subdomain carrying the parent's brand. Deeper namespaces carry the trust chain of every ancestor that anchored and delegated above them.

Economic dynamics. Domain owners are incentivized to anchor (forgoing resale value) because anchoring unlocks the namespace revenue stream. An anchored "oracle" can mint "oracle-weather", "oracle-sports", "oracle-finance" and sell them via DOMAIN_SELL. Each sale earns COG. The operator is a market maker whose inventory is domain names rather than tokens.

The economics deepen at every level. The buyer of "oracle-weather" who anchors it becomes a namespace operator themselves, minting "oracle-weather-tokyo", "oracle-weather-london", "oracle-weather-api" and selling them to specialized agents. Each subdomain level burns 100 cogtoshi. A three-level hierarchy ("oracle" → "oracle-weather" → "oracle-weather-tokyo") costs 0.001 BTC to treasury for the root domain plus 200 cogtoshi burned across two subdomain registrations, plus three Bitcoin transaction fees — and requires three independently anchored identities.

A namespace operator acquires COG through mining or market purchase. The demand loop:

Miners produce COG —> namespace operators buy COG —> mint subdomains,
register fields, write data, build reputation (all burns) —> sell
domain names for COG via DOMAIN_SELL —> COG recirculates to
operator —> repeat

The subdomain COG cost is nominal by design — the Bitcoin transaction fee required for each registration is the dominant cost, so that namespace expansion scales with Bitcoin's fee market rather than with COG's exchange rate. The operational costs that matter at scale are subdomain minting, field registration, data writes, and reputation burns, all of which permanently destroy COG.

Independence after creation. Once a subdomain is registered, it is a full domain. Its owner has no ongoing dependency on the parent. The parent's sole privilege was creation. After creation, the subdomain owner can anchor, transfer, sell, register fields, write data, and accumulate reputation independently. The parent cannot revoke, modify, or interfere with any subdomain after registration. If the subdomain owner anchors it, they additionally gain the right to mint their own children — this is a consequence of anchoring, not a grant from the parent. The parent has no ability to prevent or control this.

Ownership changes. A domain can only be transferred while unanchored. Since subdomain registration requires an anchored parent, an unanchored domain has no existing children. Once the new owner anchors the domain, the domain gains the ability to mint direct children under it (via the owner or delegate). An anchored domain cannot be transferred — the owner is permanent. The owner or delegate can mint direct children indefinitely. Each anchored child independently controls its own sub-namespace.


5.5 DOMAIN_TRANSFER (0x06) — Transfer Domain Ownership

5.5.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Byte  4:     Recipient scriptPubKey length L (uint8)

Bytes 5–4+L: Recipient scriptPubKey (raw bytes)

Total: 3 (header) + 1 (op) + 4 (domain ID) + 1 (length) + L (scriptPubKey).

5.5.2 Validation Rules

  1. The sender address must be the current owner of the domain.
  2. Recipient scriptPubKey must be non-empty and at most 67 bytes (L > 0 and L ≤ 67). If the payload is shorter than 5+L bytes, the transaction is silently ignored.
  3. The domain must be unanchored (see 5.4.4). Anchored domains cannot be transferred.
  4. Sender and recipient must be different addresses. Self-transfer is rejected.

5.5.3 Behavior

On a valid DOMAIN_TRANSFER, the indexer:

  1. If the domain has an active DOMAIN_SELL listing, cancels it, decrements total_listing_count by 1, and updates listing_xor (Section 7.6).
  2. Transfers domain ownership: the domain points to the new (recipient) address. Updates domain_xor for the ownership change (Section 7.6).
  3. Unanchored domains have no fields or data. The transfer changes only the owner address.

5.6 DOMAIN_SELL (0x07) — List Domain for Resale

Domain resale is Cogcoin-only. Listings are on-chain and settlement is fully atomic at the indexer layer.

The domain must be unanchored (see 5.4.4). Anchored domains cannot be sold.

5.6.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Bytes 4–11:  Listed price in cogtoshi (uint64, big-endian). Price of 0 cancels an existing listing.

5.6.2 Validation Rules

  1. Sender must be the current owner of the domain.
  2. The domain must be unanchored.

5.6.3 Behavior

On a valid DOMAIN_SELL:

  1. If price > 0: the indexer records the listing with the sender as seller and the payload price. Only one listing per domain exists at a time — a new DOMAIN_SELL replaces any previous listing. If no prior listing existed, the indexer increments total_listing_count by 1. If a prior listing existed, total_listing_count is unchanged — the replacement is an update, not a creation. Updates listing_xor (Section 7.6).
  2. If price = 0: the indexer removes any existing listing for this domain, decrements total_listing_count by 1, and updates listing_xor (Section 7.6). If no listing exists, the transaction is silently ignored — total_listing_count and listing_xor are unchanged.

The domain remains functional during the listing.


5.7 DOMAIN_BUY (0x08) — Buy a Listed Domain

5.7.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Bytes 4–11:  Expected price in cogtoshi (uint64, big-endian) — must match listed price

The expected price must match the current listed price exactly. This protects the buyer from price changes between broadcast and confirmation.

5.7.2 Validation Rules

  1. The domain must have an active listing (created by DOMAIN_SELL).
  2. The domain must be unanchored. (This is guaranteed by the listing mechanism but MUST be checked independently.)
  3. The listing's seller address must match the domain's current owner. If the domain has been transferred since the listing was created, the listing is stale and the buy is rejected.
  4. The expected price must match the listed price exactly.
  5. The buyer (sender) must not be the current owner of the domain. Self-purchase is rejected — it would be a no-op.
  6. The buyer (sender) must have available Cogcoin balance >= the listed price.

5.7.3 Behavior

On a valid DOMAIN_BUY, the indexer:

  1. Debits the buyer's Cogcoin balance by the listed price.
  2. Credits the current owner of the domain the full price.
  3. Removes the listing. Decrements total_listing_count by 1. Updates listing_xor (Section 7.6).
  4. Transfers domain ownership to the buyer. Updates domain_xor for the ownership change (Section 7.6).
  5. total_cog_supply is unchanged (debit and credit cancel). Updates balance_xor for both buyer and seller (Section 7.6).

No race condition. If two buyers submit in the same block, first by transaction ordering wins. The loser's transaction is ignored by the indexer — their Cogcoin balance is untouched. No funds at risk.

No off-chain relay needed. Listings are on-chain, visible to all indexers.


5.8 DOMAIN_ANCHOR (0x0F) — Anchor Domain Permanently

DOMAIN_ANCHOR permanently locks a domain to its current owner. Anchored domains cannot be transferred, sold, or re-anchored. The owner is frozen forever.

5.8.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)
Bytes 4–63:  Founding message (optional, 40 Coglex tokens at 12 bits; Section 5.8.7)
Bytes 64–75: Reserved (SHOULD be 0x00)

Minimum OP_RETURN: 3 (header) + 1 (op) + 4 (domain ID) = 8 bytes. Maximum: 80 bytes.

5.8.2 Validation Rules

  1. Domain ID must reference an existing domain (> 0 and < next_domain_id).
  2. The sender must be the current owner of the domain. The sender address is extracted from input 0 using the standard rules (Section 4.1.1).
  3. The domain must not already be anchored. An anchored domain cannot be anchored again.

No Cogcoin fee is required. The operation costs only a standard Bitcoin transaction fee. Anchoring is a commitment, not a purchase.

5.8.3 Indexer Behavior

On a valid DOMAIN_ANCHOR transaction, the indexer:

  1. Sets domain.anchored = true.

  2. Sets domain.anchor_height = [current block height].

  3. Increments anchored_domain_count by 1.

  4. Updates domain_xor for the anchored status and anchor_height change (Section 7.6).

  5. If the domain has an active DOMAIN_SELL listing, removes the listing, decrements total_listing_count by 1, and updates listing_xor (Section 7.6). DOMAIN_SELL listings do not lock COG, so there is no COG to release — the cancellation simply removes the listing entry.

  6. If the owner has no entry in canonical_domain: set canonical_domain[owner] = domain_id, increment canonical_count by 1, and update canonical_xor (Section 7.6). This makes the first anchored domain the canonical domain automatically — no separate SET_CANONICAL transaction is needed.

  7. Bootstrap award (root-level domains only). If the domain name contains no hyphens and bootstrap_remaining > 0: compute claim_cogtoshi = min(10_000_000, bootstrap_remaining), credit the sender's Cogcoin balance by claim_cogtoshi, decrement bootstrap_remaining by claim_cogtoshi, and increment total_cog_supply by claim_cogtoshi. Updates balance_xor for the sender (Section 7.6). Subdomain anchoring does not trigger a bootstrap award.

    The bootstrap pool starts at 100,000 COG and covers 1,000,000 root domain anchors at 0.1 COG each. Once exhausted, anchoring continues normally without bootstrap. If multiple DOMAIN_ANCHOR transactions in the same block collectively exceed the remaining pool, they are awarded in transaction order — earlier transactions receive their full amount, later transactions receive a partial or zero award.

  8. Founding message. If the OP_RETURN is at least 68 bytes, decode payload bytes 4–63 (60 bytes) via decode_sentence_wasm (Section 5.1.6). If canonical decoding succeeds (encode(decode(token_ids)) == token_ids), set founding_messages[domain_id] to the decoded text. If decoding fails, set founding_messages[domain_id] = null. If the OP_RETURN is shorter than 68 bytes, set founding_messages[domain_id] = null. The founding message does not affect domain_xor or any state hash field.

5.8.4 State After Anchor

domain.id            = [uint32, assigned at DOMAIN_REG]
domain.name          = [string, set at DOMAIN_REG]
domain.owner         = [scriptPubKey bytes, set at DOMAIN_REG or last DOMAIN_TRANSFER]
domain.anchored      = true
domain.anchor_height = [block height where DOMAIN_ANCHOR was processed]
domain.reg_height    = [block height where DOMAIN_REG was processed]
domain.next_field_id = [uint32, next field ID to assign under this domain]
domain.endpoint      = null  (set via SET_ENDPOINT; null until first SET_ENDPOINT)
domain.delegate      = null  (set via SET_DELEGATE; null until first SET_DELEGATE)
domain.miner         = null  (set via SET_MINER; null until first SET_MINER)
domain.pq_hash       = null  (set via PQ_COMMIT; null until first PQ_COMMIT)
Protocol-level stored data (not in domain maps or state hash):
founding_messages[domain.id] = [decoded text, or null if absent/invalid]
                               (set during DOMAIN_ANCHOR via decode_sentence_wasm;
                                null if OP_RETURN < 68 bytes or Coglex decoding fails;
                                stored in separate founding_messages map, not in domain_xor)

After anchor, the identity is permanent. The domain cannot be transferred (DOMAIN_TRANSFER checks anchored == false). The owner is permanent. PQ_MIGRATE (Section 5.19) is the only mechanism that can update the domain.owner scriptPubKey for an anchored domain.

5.8.5 Same-Block Ordering

DOMAIN_REG and DOMAIN_ANCHOR can appear in the same block. The indexer processes transactions in block order (lower transaction index first). If DOMAIN_REG appears at index N and DOMAIN_ANCHOR appears at index M where M > N, the domain exists and is owned by the registrant when DOMAIN_ANCHOR is processed. Both operations succeed.

If DOMAIN_ANCHOR appears before DOMAIN_REG in the same block, the domain does not yet exist. Rule 1 fails and the DOMAIN_ANCHOR is silently ignored. The domain registers normally but remains unanchored.

FIELD_REG and DOMAIN_ANCHOR in the same block. If FIELD_REG appears before DOMAIN_ANCHOR in the same block, the FIELD_REG is silently ignored (the domain is not yet anchored). The DOMAIN_ANCHOR then succeeds, but the field is lost — the agent must resubmit FIELD_REG in a subsequent block. Recommended same-block ordering: DOMAIN_REG (lowest index), then DOMAIN_ANCHOR, then SET_ENDPOINT, then FIELD_REG, then DATA_UPDATE.

Subdomain DOMAIN_REG requires an anchored parent. A subdomain DOMAIN_REG checks that the domain matching the parent prefix (substring before the last hyphen) is anchored at processing time. If that domain's DOMAIN_ANCHOR has not yet been processed (whether in a prior block or earlier in the current block), the subdomain registration is silently ignored.

5.8.6 Cost

domain_anchor_fee = 0 cogtoshi

Only a standard Bitcoin transaction fee is required. The cost of anchoring is the permanence itself — the agent permanently surrenders the ability to transfer or sell the domain.

5.8.7 Founding Message

DOMAIN_ANCHOR's fixed payload is 4 bytes (payload-relative). OP_RETURN capacity is 76 bytes (payload-relative). The remaining 72 bytes MAY contain a founding message. The Coglex-encoded portion occupies the first 60 bytes (40 tokens at 12 bits each). The final 12 bytes are reserved and SHOULD be 0x00.

Encoding. A well-formed founding message occupies 60 bytes: payload bytes 4–63 (OP_RETURN bytes 8–67), encoded as 40 Coglex token IDs at 12 bits each, using the same bit-packing, vocabulary, and morphological composition rules as MINE sentence payloads (Section 5.1). Payload bytes 64–75 (OP_RETURN bytes 68–79) are reserved and SHOULD be 0x00. Transaction constructors that include a founding message SHOULD transmit an 80-byte OP_RETURN. Messages MUST pass canonical encoding verification: encode(decode(token_ids)) == token_ids. Conforming indexers MUST use decode_sentence_wasm from the scoring module's WASM binary (Section 5.1.6) for all founding message decoding. Native reimplementations of Coglex decoding are non-conforming.

Short messages. Messages shorter than 40 tokens are padded with trailing zero token IDs to fill 60 bytes, then decoded with Coglex trailing zero stripping to recover the original token count. To avoid ambiguity, the last content token SHOULD NOT be token ID 0x000 — trailing zero stripping will consume it, the round-trip canonicality check will fail, and the founding message will be stored as null. An OP_RETURN of exactly 8 bytes indicates no founding message.

Invalid payloads. A founding message is either valid or absent. If the OP_RETURN is shorter than 68 bytes (8 fixed + 60 Coglex), the Coglex area is incomplete and no founding message exists — the indexer stores null. If the 60-byte Coglex area is present but fails canonical decoding (encode(decode(token_ids)) != token_ids), the founding message is invalid — the indexer stores null. Indexers MUST NOT store or serve raw undecoded bytes as a founding message. A valid DOMAIN_ANCHOR with a null founding message is normal — founding messages are optional.

Does not affect transaction validity. Founding message bytes have no effect on whether a DOMAIN_ANCHOR succeeds. A DOMAIN_ANCHOR with 72 bytes of arbitrary data after the domain ID is a valid DOMAIN_ANCHOR — the domain is anchored, the bootstrap award (if applicable) is granted. Malformed Coglex encoding does not cause the transaction to be silently ignored — the anchor succeeds, but the founding message is null.

Founding messages do not affect validation rules, state transitions, or state hashes. During reorgs, the founding_messages entry is cleaned up alongside the consensus state it accompanies (Section 7.3). They are protocol-level stored data: conforming indexers MUST decode and store them (valid Coglex or null), but the stored value has no effect on any consensus computation.

Indexer requirement. Conforming indexers MUST decode and store founding messages for DOMAIN_ANCHOR transactions whose OP_RETURN is at least 68 bytes. The 60-byte Coglex area (payload bytes 4–63) is decoded via decode_sentence_wasm. If decoding succeeds, the indexer stores the decoded text. If decoding fails, the indexer stores null. The stored value is decoded text, not raw bytes. For OP_RETURNs shorter than 68 bytes, the founding message is null.

A domain can only be anchored once. The founding message is therefore immutable by construction — there is no second DOMAIN_ANCHOR to overwrite it. It is the permanent first sentence of the domain's on-chain history.


5.9 The Data Key Model

Cogcoin's data layer is a simple primitive: domains publish named values about themselves.

Domain-scoped:  [domain ID].[field ID]  →  {format, value} (up to 67 bytes of value)

Each domain can register named fields under itself. Each field holds exactly one entry — a format byte and value bytes — writable only by the domain's owner or delegate. Two modes are available: mutable (overwritable indefinitely) and permanent (write-once, frozen forever). The format byte identifies the encoding (UTF-8, integer, hash pointer, etc.); the protocol stores but does not validate it. Value bytes are raw; applications interpret them according to the format.

Fields are signposts, not storage. A domain uses fields to speak about itself: service endpoints, content hashes, contract addresses, protocol hints, configuration, pointers to off-chain data. Rich data — per-user records, large datasets, application state — lives on cheaper substrates (L2 chains, IPFS, off-chain servers), verified by the key that controls the domain's owner address on Bitcoin.

Design properties:

  • A domain's authority is scoped. A domain can only write to fields it registered. A malicious or compromised domain cannot touch fields belonging to other domains. The worst case is bad data under its own namespace, which other agents can discount based on the domain's reputation.
  • Data is direct. Oracle feeds, configuration, and global state are queried by domain and field — no address indirection needed. This is the natural shape for data that belongs to the domain rather than to any individual user.
  • The protocol is a trust anchor, not a database. Cogcoin binds a name to an address, quantifies trust through burns and commitments, and points to where the agent lives. Everything else is signed data on cheaper substrates, verified by the on-chain identity.

5.10 FIELD_REG (0x09) — Register a Field Under a Domain

Domain owners or delegates register named fields, each receiving a permanent sequential field ID (uint32) scoped to its parent domain. The field's permanent flag is set at registration time and is immutable.

5.10.1 Payload Format

Bytes 0–3:   Parent domain ID (uint32, big-endian)

Byte  4:     Permanent flag (uint8):
               0x00 = mutable   — domain's owner or delegate can write and overwrite indefinitely
               0x01 = permanent — domain's owner or delegate can write exactly once; value is frozen forever
             Any other value is rejected.

Byte  5:     Field name length N (uint8, 1–63)

Bytes 6–N+5: Field name (ASCII lowercase a-z, 0-9, hyphens; no leading/trailing/consecutive hyphens)

Bytes N+6–:  Trailing bytes ignored

The field is always created empty. Writing a value requires a separate DATA_UPDATE transaction. This separation ensures that FIELD_REG is a simple, fixed-layout operation with no trailing-byte interpretation — consistent with how all other fixed-layout operations handle excess bytes.

Field names follow the same character rules as domain names: lowercase a-z, 0-9, hyphens, no leading/trailing/consecutive hyphens, 1–63 characters.

Field name validation (consensus-critical). Field names are validated with the same rules as domain names:

  1. Length: 1–63 bytes.
  2. Allowed characters: lowercase ASCII letters (a-z), digits (0-9), and hyphens (-).
  3. No leading hyphen: the first character must not be a hyphen.
  4. No trailing hyphen: the last character must not be a hyphen.
  5. Uppercase letters are rejected (not silently lowercased). The sender must submit lowercase.
  6. No consecutive hyphens: the name must not contain "--".

These rules are identical to domain name validation (Section 5.4.3). Implementations can share the validation function.

5.10.2 Field ID Assignment

Each field gets a sequential uint32 field ID, scoped to its parent domain. Field IDs start at 1 within each domain (ID 0 is reserved as a null value). Different domains have independent field ID sequences — domain A's field 1 and domain B's field 1 are unrelated entities. A field is uniquely identified by the composite key (domain_id, field_id). FIELD_REG MUST be rejected if domain.next_field_id equals 0xFFFFFFFF (uint32 maximum). No field is created and no state changes occur.

Each domain record includes a next_field_id counter, initialized to 1 at DOMAIN_REG. When a field is registered under a domain, the indexer assigns domain.next_field_id and increments it. Field IDs and domain IDs are independent namespaces — the op code and domain context determine which namespace an ID belongs to.

5.10.3 Validation Rules

  1. The parent domain must be anchored (domain.anchored == true). If the parent domain is not anchored, the FIELD_REG is silently ignored.
  2. Sender must be the parent domain's owner or delegate (Section 5.16).
  3. Permanent flag byte must be 0x00 or 0x01. Any other value is rejected.
  4. Field name is 1–63 ASCII characters (same character rules as domain names). If the payload is shorter than 6+N bytes (where N is the name length byte at payload byte 5), the transaction is silently ignored.
  5. The (parent domain ID, field name) pair must not already exist. Each field can only be registered once.
  6. Sender must have available Cogcoin balance >= 100 cogtoshi (the field registration fee).

5.10.4 Cost

Field registration burns a fixed amount of Cogcoin from the sender:

field_registration_fee = 100 cogtoshi  (0.000001 COG)

If an initial value is needed, it must be written via a separate DATA_UPDATE transaction (1 cogtoshi per write).

Small enough to not impede legitimate development, but large enough — combined with Bitcoin's transaction fee — to create a cost for schema spam.

5.10.5 Processing Order

The indexer assigns the new field domain.next_field_id as its permanent field ID within the parent domain, then increments domain.next_field_id by 1. The indexer also increments the global total_field_count by 1.

  1. Assign domain.next_field_id and register field metadata (name, permanent flag). Update field_by_name[(domain_id, field_name)]. Update field_xor (Section 7.6). Update domain_xor for the next_field_id change (Section 7.6).
  2. Burn 100 cogtoshi from the sender's available balance. Increment total_burned_cog by 100 (state hash field, Section 7.6). Decrement total_cog_supply by 100. Update balance_xor for the sender (Section 7.6).

5.10.6 Immutability

Field registrations are permanent. A field ID, once assigned, exists forever. The permanent flag and field name-to-ID mapping are all immutable. For permanent fields, the stored entry ({format, value}) is immutable after the first DATA_UPDATE write.

The parent domain must be anchored via DOMAIN_ANCHOR (Section 5.8) before any field can be registered. Field registration requires an already-anchored domain — it does not trigger anchoring. An anchored domain can never be transferred or resold. The domain owner is accepting permanent stewardship. Users who trust data written under the domain's fields can rely on the identity behind it never changing.


5.11 DATA_UPDATE (0x0A) — Write Data to a Domain Field

Applications write data to the Cogcoin namespace via DATA_UPDATE. Each write targets a single domain-scoped field.

5.11.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Bytes 4–7:   Field ID (uint32, big-endian — must belong to the domain)

Byte  8:     Format byte (uint8):
               0x00 = clear (delete current value; any trailing bytes are ignored)
               0x01 = raw bytes (uninterpreted)
               0x02–0xFF = typed data format identifier (see Appendix D)

Bytes 9–:    Value (raw bytes, up to remaining space — present only for writes)

Key: [domain_id].[field_id] -> {format, value}

Minimum OP_RETURN: 3 (header) + 1 (op) + 4 (domain ID) + 4 (field ID) + 1 (format) = 13 bytes. Maximum value size: 80 - 13 = 67 bytes.

The format byte is always present. It tells the indexer and all downstream consumers how to interpret the value bytes without parsing the value itself. Format 0x00 is the clear operation — it deletes any existing value for this field. All other format values indicate a data write; the format byte is stored alongside the value in domain_data as a first-class field of the entry, not as part of the value bytes.

The indexer parses the domain ID, field ID, and format byte, verifies the field exists and belongs to the domain, then acts based on the format byte. If format is 0x00, the field value is deleted. If format is non-zero, bytes 9+ are the value. If no value bytes follow a non-zero format byte (exactly 13-byte OP_RETURN), the transaction is silently ignored (see rule 8).

5.11.2 Write Authorization

The sender must be the parent domain's owner or delegate (Section 5.16).

For permanent fields, the sender must additionally satisfy the freeze check: if the field already has a value, the write is rejected (see 5.11.3 rule 7).

5.11.3 Validation Rules

Rule evaluation order (consensus-critical). Payload size validation per Section 3.2 is a prerequisite — the indexer MUST verify that the payload contains enough bytes for all fixed fields (domain ID + field ID + format byte = at least 9 payload bytes) before evaluating any rule below. Rule 6 restates this check for self-containment.

The rules below MUST be evaluated in the numbered order. If any rule fails, the transaction is silently ignored and subsequent rules are not evaluated. The ordering is consensus-critical because rule 7 (permanent field freeze) rejects all writes to frozen permanent fields — including clears — before rule 8 (format byte semantics) is reached. An implementation that evaluates rule 8 before rule 7 could process a clear on a frozen permanent field, producing divergent state.

  1. The field ID must reference a registered field under the specified domain. The composite key (domain_id, field_id) must exist in the fields map. If the field ID is 0 or does not exist under the domain, the transaction is ignored.

  2. Domain check. The field's parent domain is guaranteed by the composite key lookup in rule 1. Implementations that store fields with an explicit parent_domain_id SHOULD verify it matches the payload domain ID as an additional consistency check.

  3. The domain ID in the payload must reference an existing domain (next_domain_id > domain_id > 0). If invalid, the transaction is ignored.

  4. The field's parent domain must be anchored. If domain.anchored == false, the transaction is ignored. FIELD_REG already requires the domain to be anchored, and anchoring is irreversible, so this check is redundant in practice. It is included so that DATA_UPDATE validation is self-contained — implementers do not need to rely on FIELD_REG invariants for correctness.

  5. The sender must be the parent domain's owner or delegate (Section 5.16). If unauthorized, the transaction is ignored.

  6. Format byte size check. The OP_RETURN payload must be at least 9 bytes (domain ID + field ID + format byte). If shorter, the transaction is ignored.

  7. Permanent field freeze (consensus-critical). If the field is permanent and the field already has an entry in domain_data, the transaction is ignored — regardless of format byte (including 0x00). Once a permanent field has been written via DATA_UPDATE, it is frozen for the lifetime of the protocol.

    A permanent field accepts exactly one DATA_UPDATE with a non-zero format and >=1 value byte, which writes {format, value} and triggers the freeze; all subsequent writes are rejected.

    Clears (0x00) to an empty permanent field pass the freeze check (no entry exists in domain_data to trigger it) and are complete no-ops — clears are free (see rule 8), so no fee is burned either. The field remains open for its one actual write.

  8. Format byte semantics (consensus-critical). The format byte (payload byte 8) determines the operation:

    • 0x00 (clear): delete any existing value for this field from domain_data. Updates data_xor if an entry existed (Section 7.6). Any trailing bytes after the format byte are ignored. Clears are free — no Cogcoin fee is burned. The protocol incentivizes reducing indexer storage. No COG balance is required. The only cost is the Bitcoin transaction fee.
    • Non-zero format with zero value bytes (exactly 13-byte OP_RETURN, no bytes after format): the transaction is silently ignored. This is a validation failure — no fee is burned, no state changes. This prevents accidental writes — particularly to permanent fields, where a format byte alone with no value would freeze the field with empty content.
    • Non-zero format with ≥1 value bytes: this is a data write. If all subsequent rules pass (including rule 10's balance check), the indexer stores {format, value} in domain_data[(domain_id, field_id)], replacing any previous entry. Updates data_xor (Section 7.6). Burns 1 cogtoshi from the sender (see 5.11.4).
  9. Value size. The value must not exceed 67 bytes (80 bytes total minus 13 bytes of header, op, domain ID, field ID, and format byte). The extraction procedure (Section 3.1 step D) skips outputs with oversized data before any operation is parsed, but this rule is stated explicitly so that DATA_UPDATE validation is self-contained.

  10. Balance check (writes only). If the format byte is non-zero (a write, not a clear): sender's available Cogcoin balance >= 1 cogtoshi. If insufficient, the transaction is ignored. Clears (format 0x00) skip this check — they require no COG balance.

5.11.4 Cogcoin Fee

Each DATA_UPDATE write (non-zero format byte with ≥1 value byte) burns a flat 1 cogtoshi from the sender:

data_update_write_fee = 1 cogtoshi  (flat, regardless of value size)

The indexer increments total_burned_cog by 1 for each write (state hash field, Section 7.6). Decrements total_cog_supply by 1. Updates balance_xor for the sender (Section 7.6).

Clears are free. A DATA_UPDATE with format byte 0x00 does not burn any Cogcoin. This incentivizes field clearing, which reduces indexer storage. The Bitcoin transaction fee is the only cost.

The real spam deterrent is Bitcoin's transaction fee. The Cogcoin fee exists as a protocol-level marker that every data write is a permanent on-chain commitment. Note: writes to permanent fields are rejected after the first write (see 5.11.3 rule 7).

5.11.5 Value Encoding

Values are raw bytes. The protocol does not interpret them beyond the format byte. The format byte (stored as a first-class field alongside the value) tells applications how to interpret the value bytes without parsing the value itself. Format byte definitions are specified in Appendix D.

5.11.6 Data Overwrite and Clearing

Writing a new value to a field overwrites the previous entry (format and value). The indexer tracks only the latest entry. Historical values can be recovered by scanning earlier blocks. Exception: permanent fields reject all writes after the first. The first value written via DATA_UPDATE is frozen and cannot be overwritten or cleared.

Field clearing (format byte 0x00). A DATA_UPDATE with format byte 0x00 clears the field. After clearing, reads return null for that field. The indexer deletes the storage entry from domain_data. Mutable fields can be cleared and re-written indefinitely.

Clears are free — no Cogcoin is burned, and no COG balance is required (see 5.11.3 rule 8). The only cost is the Bitcoin transaction fee. This incentivizes field clearing, which reduces indexer storage burden.

For permanent fields that already have a value, the permanent field freeze (rule 7 in 5.11.3) rejects all writes, clears included, before the format byte is evaluated. A permanent field that has not yet received a write can accept 0x00 DATA_UPDATE transactions at the protocol level. Each is a complete no-op (no state change, no fee). The field remains open for one future write with a non-zero format. Reference clients should prevent 0x00 writes to empty permanent fields as pointless.

5.11.7 Maximum Value Size

Maximum value: 67 bytes.

5.11.8 Security Model

A malicious domain owner or delegate can only write to fields registered under that domain — they cannot touch fields belonging to other domains. Users and agents evaluate data by the reputation of the field's parent domain (sections 5.13–5.14). Since domain registration costs either BTC or COG (for subdomains) and each field costs Cogcoin, there is a built-in barrier to namespace spam.


5.12 SET_ENDPOINT (0x0B) — Publish Agent Endpoint

An anchored domain can publish a service endpoint URI — the address where other agents can discover how to interact with it. The endpoint is a first-class domain property.

5.12.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Bytes 4–N:   Endpoint URI (1–72 bytes, conventionally UTF-8)

If no bytes follow the domain ID (payload length == 4), the endpoint is cleared
(domain.endpoint set to null).

Total: 3 (header) + 1 (op) + 4 (domain ID) + 1–72 (URI) = 9–80 bytes. Clearing: 3 (header) + 1 (op) + 4 (domain ID) = 8 bytes.

5.12.2 Validation Rules

  1. The domain must be anchored.
  2. The sender must be the domain's owner or delegate (Section 5.16).
  3. If payload length > 4: bytes 4 through end are the endpoint URI. The URI must be 1–72 bytes. If the URI exceeds 72 bytes, the transaction is silently ignored.
  4. If payload length == 4: this is a clear operation.

The indexer stores endpoint bytes as-is with no encoding validation. Applications interpret the bytes — conventionally as a UTF-8 URI, but the protocol does not enforce this. This is consistent with DATA_UPDATE, which stores raw value bytes with an advisory format byte.

5.12.3 Behavior

On a valid SET_ENDPOINT:

Set (URI present): Store domain.endpoint = [URI bytes]. Overwrites any previous endpoint. Updates endpoint_xor (Section 7.6).

Clear (no URI bytes): Set domain.endpoint = null. The domain has no published endpoint. Updates endpoint_xor if the endpoint was non-null (Section 7.6).

No Cogcoin is burned. Only a standard Bitcoin transaction fee is required.

5.12.4 Cost

set_endpoint_fee = 0 cogtoshi

The endpoint is an identity property, not a data operation. There is no reason to add friction beyond the base cost of transacting on Bitcoin.

5.12.5 Same-Block Ordering

DOMAIN_REG, DOMAIN_ANCHOR, and SET_ENDPOINT can appear in the same block. The indexer processes transactions in block order. If DOMAIN_REG is at index N, DOMAIN_ANCHOR at index M (M > N), and SET_ENDPOINT at index P (P > M), all three succeed. If SET_ENDPOINT appears before DOMAIN_ANCHOR in the same block, the domain is not yet anchored and the SET_ENDPOINT is silently ignored.


5.13 REP_COMMIT (0x0C) — Burn Cogcoin for Domain Reputation

5.13.1 Payload Format

Bytes 0–3:   Source domain ID (uint32, big-endian). The anchored domain endorsing the target.

Bytes 4–7:   Target domain ID (uint32, big-endian). The anchored domain receiving reputation.

Bytes 8–15:  Amount of cogtoshi to burn (uint64, big-endian)

Bytes 16–75: Review (optional, 40 Coglex tokens at 12 bits; Section 5.13.4)

Minimum OP_RETURN: 3 (header) + 1 (op) + 4 (source domain) + 4 (target domain) + 8 (amount) = 20 bytes. Maximum: 80 bytes.

5.13.2 Validation Rules

  1. The source domain must be anchored. The sender must be the source domain's owner or delegate (Section 5.16).
  2. The target domain must be anchored.
  3. Amount > 0.
  4. Sender's available Cogcoin balance >= amount.
  5. A domain can commit reputation to any anchored domain, including itself.

5.13.3 Behavior

The indexer checks whether the source domain ID equals the target domain ID and routes accordingly:

Self-commitment (source domain == target domain):

  1. Debits the sender's Cogcoin balance.
  2. Credits the target domain's self_stake reputation counter. Updates reputation_xor for the target domain (Section 7.6).
  3. Increments total_self_staked by the amount (state hash field, Section 7.6).
  4. Increments total_burned_cog by the amount (state hash field, Section 7.6).
  5. Decrements total_cog_supply by the amount. Updates balance_xor for the sender (Section 7.6).

Self-commitments are permanent. There is no revocation path for self-committed COG.

Third-party endorsement (source domain != target domain):

  1. Debits the sender's Cogcoin balance.
  2. Increments net_support[(source_domain_id, target_domain_id)] by the amount. Updates support_xor (Section 7.6).
  3. Increments the target domain's supported_stake and total_supported by the amount. Updates reputation_xor for the target domain (Section 7.6).
  4. Increments total_net_supported by the amount (state hash field, Section 7.6).
  5. Increments total_burned_cog by the amount (state hash field, Section 7.6).
  6. Decrements total_cog_supply by the amount. Updates balance_xor for the sender (Section 7.6).

The target domain's total visible reputation = self_stake + supported_stake.

The burned Cogcoin is gone forever in both cases.

Review (both paths). If the OP_RETURN is exactly 80 bytes, decode payload bytes 16–75 (60 bytes) via decode_sentence_wasm (Section 5.1.6). If canonical decoding succeeds, store the decoded text as the review for this REP_COMMIT transaction. If decoding fails, store null. If the OP_RETURN is shorter than 80 bytes, no review exists (null). The review does not affect any state hash field.

5.13.4 Natural Language Reviews

REP_COMMIT's fixed payload is 16 bytes (payload-relative). OP_RETURN capacity is 76 bytes (payload-relative). The remaining 60 bytes — identical in size to a MINE sentence payload — MAY contain a Coglex-encoded natural language review.

Reviews apply to both self-commitments and third-party endorsements. A self-commitment review explains what the domain offers ("accurate weather data with fast response and stable service"). A third-party endorsement review explains why the source domain supports the target ("fast response accurate price data and strong service quality").

Encoding. A well-formed review occupies all 60 trailing bytes: payload bytes 16–75 (OP_RETURN bytes 20–79), encoded as 40 Coglex token IDs at 12 bits each, using the same bit-packing, vocabulary, and morphological composition rules as MINE sentence payloads (Section 5.1). Transaction constructors that include a review SHOULD transmit an 80-byte OP_RETURN (20 bytes fixed + 60 bytes review). Reviews MUST pass canonical encoding verification: encode(decode(token_ids)) == token_ids. Conforming indexers MUST use decode_sentence_wasm from the scoring module's WASM binary (Section 5.1.6) for all review decoding. Native reimplementations of Coglex decoding are non-conforming.

Review vocabulary. The Coglex vocabulary was designed for general English fluency, not specifically for reviews. It turns out general English fluency is sufficient. The 4,096-token vocabulary includes single tokens for:

  • Quality assessment:excellent, accurate, precise, robust, stable, efficient, fast, good, great, best, poor, slow, terrible, weak, broken, fault, error, fail, crash, waste, stale, corrupt, fraud
  • Service description:service, data, price, speed, response, network, cost, fee, rate, supply, demand, update, compute, node, validate, deploy, algorithm, inference, pipeline, system, method, model
  • Nuance and qualification:but, however, although, yet, nevertheless, whereas, unless, except, somewhat, perhaps, often, always, never, very, quite
  • Temporal context:since, after, before, during, recent, early, late, day, week, month, year
  • Morphological composition: Suffixes (-able, -ful, -less, -ness, -ive, -ence, -ance, -ly, -ed, -ing, -er, -est) and prefixes (un-, re-, dis-, over-, in-, de-) compose further forms: depend + -able = "dependable" (2 tokens), consist + -ent = "consistent" (2 tokens), un- + rely + -able = "unreliable" (3 tokens), perform + -ance = "performance" (2 tokens).

A typical review uses 8–15 tokens out of 40 available, leaving room for multi-sentence reviews within a single payload. The BIP-39 base wordlist, inherited from Bitcoin's mnemonic standard, contains no profanity — reviews are structurally constrained to civil language without any content moderation system.

Short reviews. Reviews shorter than 40 tokens are padded with trailing zero token IDs to fill 60 bytes, then decoded with Coglex trailing zero stripping to recover the original token count. To avoid ambiguity, the last content token in a short review SHOULD NOT be token ID 0x000 — trailing zero stripping will consume it, the round-trip canonicality check will fail, and the review will be stored as null. An OP_RETURN of exactly 20 bytes indicates no review.

Invalid payloads. A review is either valid or absent. If the OP_RETURN is shorter than 80 bytes, the review area is incomplete and no review exists — the indexer stores null. If the 60-byte Coglex area is present but fails canonical decoding (encode(decode(token_ids)) != token_ids), the review is invalid — the indexer stores null. Indexers MUST NOT store or serve raw undecoded bytes as a review.

Does not affect transaction validity. Review bytes have no effect on whether a REP_COMMIT succeeds. A REP_COMMIT with 60 bytes of arbitrary data after the amount field is a valid REP_COMMIT — the reputation commitment succeeds, the COG is burned. Malformed Coglex encoding does not cause the transaction to be silently ignored — the burn succeeds, but the review is null. This is unlike MINE, where Coglex encoding failure rejects the submission (Section 5.1.2 rule 8) — MINE sentences are inputs to the scoring pipeline; reviews are not.

Reviews do not affect validation rules, state transitions, or state hashes. During reorgs, reviews are discarded alongside the consensus state they accompany (Section 7.3). They are protocol-level stored data: conforming indexers MUST decode and store them (valid Coglex or null), but the stored value has no effect on any consensus computation.

Indexer requirement. Conforming indexers MUST decode and store reviews for REP_COMMIT transactions whose OP_RETURN is exactly 80 bytes. The 60-byte Coglex area (payload bytes 16–75) is decoded via decode_sentence_wasm. If decoding succeeds, the indexer stores the decoded text. If decoding fails, the indexer stores null. The stored value is decoded text, not raw bytes. For OP_RETURNs shorter than 80 bytes, the review is null.

REP_REVOKE supports the same review mechanism (Section 5.14.5). A revocation review explains why the source domain is withdrawing support.


5.14 REP_REVOKE (0x0D) — Revoke Support for a Domain

5.14.1 Payload Format

Bytes 0–3:   Source domain ID (uint32, big-endian). The domain revoking its endorsement.

Bytes 4–7:   Target domain ID (uint32, big-endian). The domain losing reputation.

Bytes 8–15:  Amount of cogtoshi to revoke (uint64, big-endian)

Bytes 16–75: Review (optional, 40 Coglex tokens at 12 bits; Section 5.14.5)

Minimum OP_RETURN: 3 (header) + 1 (op) + 4 (source domain) + 4 (target domain) + 8 (revocation amount) = 20 bytes. Maximum: 80 bytes.

5.14.2 Validation Rules

  1. The source domain must be anchored. The sender must be the source domain's owner or delegate (Section 5.16).
  2. The target domain must be anchored.
  3. Amount > 0.
  4. Source domain ID must not equal target domain ID. Self-commitments cannot be revoked.
  5. The net_support[(source_domain_id, target_domain_id)] entry must have a value ≥ the revocation amount. If the source domain has never supported the target domain, or the revocation amount exceeds remaining net support, the transaction is ignored.

5.14.3 Behavior

The source domain revokes support it previously gave to the target domain. The indexer:

  1. Decrements net_support[(source_domain_id, target_domain_id)] by the revocation amount. Updates support_xor (Section 7.6). If the resulting value is zero, the entry is removed from the map. A subsequent REP_REVOKE targeting the same (source, target) pair is rejected (the entry does not exist). A subsequent REP_COMMIT from the same source domain to the same target domain creates a new entry normally.
  2. Decrements the target domain's supported_stake by the revocation amount. Increments the target domain's total_revoked by the revocation amount. Updates reputation_xor for the target domain (Section 7.6).
  3. Decrements total_net_supported by the revocation amount (state hash field, Section 7.6).
  4. The burned Cogcoin is not returned to the sender. The only effect of revocation is that the target domain's visible reputation decreases.

Review. Revocation review decoding follows the same rules as REP_COMMIT reviews (Section 5.13.3). If the OP_RETURN is exactly 80 bytes and the 60-byte Coglex area decodes canonically via decode_sentence_wasm, the decoded text is stored as the revocation review. Otherwise null.

5.14.4 Reputation Signals

Agents and users can derive several trust signals per domain:

  • Self-commitment ratio:self_stake / supported_stake. If below 100%, the domain has less self-commitment than third-party endorsement — may suggest caution.
  • Support diversity: Number of unique supporter domains.
  • Revocation rate:total_revoked / total_supported. High revocation rate is a red flag.
  • Pillar detection: Domains with large self_stake + supported_stake and low revocation rates become "pillars." When a pillar endorses a newer domain, it serves as a secondary vote of confidence.
  • Domain-scoped. Reputation exists only for anchored domains. There is no free-floating address reputation.

Sybil support (known limitation). A domain owner can register multiple domains and REP_COMMIT from each, faking support diversity while controlling all the COG. Each Sybil supporter domain requires registration and anchoring. Root domain Sybils cost 0.001 BTC minimum each. Subdomain Sybils cost 100 cogtoshi each (plus Bitcoin transaction fee) but all share the parent's namespace — a structural signal. The protocol provides the raw on-chain data needed for agents to detect it:

  • Supporter reputation. Does the supporter domain have its own reputation history? Support from an established domain with diverse endorsement is qualitatively different from support by a freshly registered domain with no history.
  • Namespace relationship. Are the supporter and target under the same root namespace? Support from "oracle-weather" to "oracle-price" may indicate organizational self-endorsement rather than independent evaluation.
  • Funding provenance. Where did the supporter's COG come from? COG_TRANSFER chains originating from the target domain's owner are visible on-chain.
  • Support timing patterns. Multiple supporter domains all committing within the same block or short window, with similar amounts, suggest coordination.

All of these signals are derivable from the blockchain without additional protocol machinery. The protocol's role is to provide unforgeable data. Interpreting that data — distinguishing genuine diverse support from Sybil support — is an application-layer problem.

5.14.5 Natural Language Reviews

REP_REVOKE supports the same natural language review mechanism as REP_COMMIT (Section 5.13.4). A well-formed revocation review occupies all 60 trailing bytes (80-byte OP_RETURN), encoded as 40 Coglex token IDs, explaining why the source domain is withdrawing support. The same encoding, short-review padding, valid-or-null semantics, and indexer requirements apply. Revocation reviews do not affect transaction validity — malformed or absent review bytes do not affect the revocation. Conforming indexers MUST decode and store revocation reviews using the same rules as REP_COMMIT reviews.


5.15 SET_CANONICAL (0x0E) — Set Canonical Domain for Address

An address that owns multiple anchored domains can designate one as its canonical domain — the primary identity that indexers and agents resolve when they encounter the address.

5.15.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Total: 3 (header) + 1 (op) + 4 (domain ID) = 8 bytes.

5.15.2 Validation Rules

  1. The sender address must be the current owner of the specified domain.
  2. The domain must be anchored. Unanchored domains are not permanent identities and cannot serve as canonical.
  3. Setting a new canonical domain replaces any previous setting. Only one canonical domain per address exists at a time.

5.15.3 Indexer Behavior

The indexer maintains a mapping: canonical_domain[address] → domain_id. On a valid SET_CANONICAL transaction, the indexer updates canonical_domain[sender] = domain_id and updates canonical_xor (Section 7.6). The canonical_count is unchanged — DOMAIN_ANCHOR creates the entry when the first domain is anchored; SET_CANONICAL only changes which domain the entry points to.

No canonical domain. If an address has no entry in canonical_domain, the address has no canonical domain. Applications querying canonical_domain(address) receive a null/empty result. Every address that has anchored at least one domain has an entry (set automatically by DOMAIN_ANCHOR or updated by SET_CANONICAL).

This is by design: canonical identity requires commitment (anchoring a domain), which is irreversible. Addresses without anchored domains are anonymous participants that can still transfer COG, mine, and register domains, but cannot serve as canonical identities.

5.15.4 Cost

No Cogcoin burn is required. The operation costs only a standard Bitcoin transaction fee. Canonical domain selection is an identity preference, not a data operation — there is no reason to add friction beyond the base cost of transacting on Bitcoin.

5.16 SET_DELEGATE (0x10) — Designate Delegate for Anchored Domain

The owner of an anchored domain can designate a delegate address. The delegate can submit the following operations using the delegated domain ID: MINE (root-level domains only, per Section 5.1.2 rule 4), DOMAIN_REG (subdomains), FIELD_REG, DATA_UPDATE, SET_ENDPOINT, REP_COMMIT, REP_REVOKE, COG_CLAIM (claim path), and SET_MINER (Section 5.17, root-level domains only). The delegate spends from its own COG balance for any fees or burns. Only the owner can set, replace, or clear the delegation.

Each domain has at most one delegate. Setting a new delegate replaces any previous delegate.

5.16.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Byte  4:     Delegate scriptPubKey length L (uint8)

Bytes 5–4+L: Delegate scriptPubKey (raw bytes)

If no bytes follow the domain ID (payload length == 4), the delegate is cleared
(domain.delegate set to null).

Set total: 3 (header) + 1 (op) + 4 (domain ID) + 1 (length) + L (scriptPubKey). Clearing: 3 (header) + 1 (op) + 4 (domain ID) = 8 bytes.

5.16.2 Validation Rules

  1. The domain must be anchored.
  2. The sender must be the current owner of the domain.
  3. If payload length > 4: byte 4 is the delegate scriptPubKey length L. L must be > 0 and ≤ 67. Bytes 5 through 4+L are the delegate scriptPubKey. If the payload is shorter than 5+L bytes, the transaction is silently ignored. A payload of 5 or more bytes where L == 0 is not an alternative clear encoding — it is an invalid set operation and is silently ignored.
  4. If payload length == 4: this is a clear operation.
  5. The delegate address must differ from the domain owner's address. Self-delegation is silently ignored.

5.16.3 Behavior

On a valid SET_DELEGATE:

Set (delegate address present): Store domain.delegate = [scriptPubKey bytes]. Overwrites any previous delegate. Updates delegate_xor (Section 7.6).

Clear (no delegate bytes): Set domain.delegate = null. The domain has no delegate. Updates delegate_xor if a delegate existed (Section 7.6).

No Cogcoin is burned. Only a standard Bitcoin transaction fee is required.

5.16.4 Cost

set_delegate_fee = 0 cogtoshi

Delegation is an operational property. There is no reason to add friction beyond the base cost of transacting on Bitcoin.

5.16.5 Same-Block Ordering

DOMAIN_ANCHOR and SET_DELEGATE can appear in the same block. If DOMAIN_ANCHOR has a lower transaction index, SET_DELEGATE succeeds. If SET_DELEGATE appears before DOMAIN_ANCHOR, the domain is not yet anchored and the SET_DELEGATE is silently ignored.


5.17 SET_MINER (0x11) — Designate Mining Address for Anchored Root-Level Domain

The owner or delegate of an anchored root-level domain can designate a miner address. The miner can submit MINE transactions using the domain ID — no other operations. Mining rewards are credited to the sender (the miner). Only the owner or delegate can set, replace, or clear the miner designation.

Each domain has at most one miner. Setting a new miner replaces any previous miner.

5.17.1 Payload Format

Bytes 0–3:   Domain ID (uint32, big-endian)

Byte  4:     Miner scriptPubKey length L (uint8)

Bytes 5–4+L: Miner scriptPubKey (raw bytes)

If no bytes follow the domain ID (payload length == 4), the miner is cleared
(domain.miner set to null).

Set total: 3 (header) + 1 (op) + 4 (domain ID) + 1 (length) + L (scriptPubKey). Clearing: 3 (header) + 1 (op) + 4 (domain ID) = 8 bytes.

5.17.2 Validation Rules

  1. The domain must be anchored and root-level (name contains no hyphens).
  2. The sender must be the domain's owner or delegate (Section 5.16).
  3. If payload length > 4: byte 4 is the miner scriptPubKey length L. L must be > 0 and ≤ 67. Bytes 5 through 4+L are the miner scriptPubKey. If the payload is shorter than 5+L bytes, the transaction is silently ignored. A payload of 5 or more bytes where L == 0 is not an alternative clear encoding — it is an invalid set operation and is silently ignored.
  4. If payload length == 4: this is a clear operation.

5.17.3 Behavior

On a valid SET_MINER:

Set (miner address present): Store domain.miner = [scriptPubKey bytes]. Overwrites any previous miner. Updates miner_xor (Section 7.6).

Clear (no miner bytes): Set domain.miner = null. The domain has no designated miner. Updates miner_xor if a miner existed (Section 7.6).

No Cogcoin is burned. Only a standard Bitcoin transaction fee is required.

5.17.4 Cost

set_miner_fee = 0 cogtoshi

5.17.5 Same-Block Ordering

DOMAIN_ANCHOR and SET_MINER can appear in the same block. If DOMAIN_ANCHOR has a lower transaction index, SET_MINER succeeds. If SET_MINER appears before DOMAIN_ANCHOR, the domain is not yet anchored and the SET_MINER is silently ignored.


5.18 PQ_COMMIT (0x12) — Store Post-Quantum Migration Commitment

PQ_COMMIT stores a 32-byte hash commitment on an anchored domain. The commitment binds the domain to a post-quantum key pair and migration secret known only to the legitimate owner. The commitment is one-time and irreversible (first-commit-wins). PQ_COMMIT is active from genesis.

5.18.1 Payload Format

Bytes 0-3:   Domain ID (uint32, big-endian)
Bytes 4-35:  pq_hash (32 bytes)

Total OP_RETURN: 3 (header) + 1 (op) + 4 (domain ID) + 32 (pq_hash) = 40 bytes. Any trailing bytes are ignored.

5.18.2 Validation Rules

  1. Payload size: OP_RETURN data must be at least 40 bytes. If shorter, silently ignored.
  2. Domain ID must reference an existing domain (> 0 and < next_domain_id).
  3. The domain must be anchored.
  4. The sender must be the current owner of the domain. Delegates are not authorized.
  5. The domain must not already have a pq_hash. If non-null, silently ignored. First commit wins.
  6. pq_hash must be non-zero. All-zero silently ignored.
  7. No Cogcoin fee.

5.18.3 Indexer Behavior

  1. Set domain.pq_hash = pq_hash.
  2. Compute pq_xor ^= SHA256(domain_id as uint32 BE || pq_hash as 32 raw bytes).

5.18.4 State After Commit

domain.pq_hash = [32-byte commitment] (new, immutable once set)
All other domain fields unchanged.

5.19 PQ_MIGRATE (0x13) — Migrate Anchored Domain to Post-Quantum Address

5.19.1 Purpose

PQ_MIGRATE (0x13) migrates an anchored domain's address to a post-quantum key by consuming the commitment stored by PQ_COMMIT. It is the only mechanism that can update the domain.owner scriptPubKey for an anchored domain. PQ_MIGRATE is a no-op before its activation height.

5.19.2 Payload Format

Bytes 0-3:   Domain ID (uint32, big-endian)
Bytes 4-35:  Migration secret (32 bytes)

Total OP_RETURN: 3 (header) + 1 (op) + 4 (domain ID) + 32 (secret) = 40 bytes. Any trailing bytes are ignored. Structurally identical to PQ_COMMIT.

5.19.3 Activation

PQ_MIGRATE is silently ignored at all block heights until a companion specification declares the activation height. Three conditions must be met before activation:

  1. Bitcoin supports post-quantum transaction signing on mainnet.
  2. The PQ witness extraction rule is defined: the companion specification designates how the PQ public key bytes are extracted from the spending transaction.
  3. The activation height is announced with sufficient lead time for indexer operators to upgrade.

5.19.4 Verification Mechanism (Informational)

At activation, PQ_MIGRATE will verify SHA-256(witness_key_bytes || migration_secret) == domain.pq_hash, where witness_key_bytes is extracted from the spending transaction's post-quantum witness data. The protocol does not prescribe how the commitment was constructed, what algorithm produced the PQ key, or how the migration secret was derived. It stores 32 opaque bytes and verifies a preimage at migration time.

5.19.5 Companion Specification

The full PQ_MIGRATE validation rules, indexer behavior, state transitions, canonical domain resolution, reorg handling, and test vectors are specified in a companion specification (cogcoin_pq_spec.md). The companion specification will be published when Bitcoin supports post-quantum transaction signing.


6. Genesis

6.1 GENESIS Transaction (0x00)

The Cogcoin protocol activated at Bitcoin block height 937,337 (the "genesis height"). The GENESIS transaction confirmed in that block, establishing the treasury scriptPubKey on-chain and committing to the locked genesis parameters by hash. New indexers scan from the genesis height forward and activate when they find this transaction. No other op code is valid until the GENESIS transaction has been processed.

6.1.1 Payload Format

Bytes 0–31:  SHA-256 hash of the genesis parameters JSON

Total OP_RETURN: 3 (header) + 1 (op) + 32 (hash) = 36 bytes. Trailing bytes are ignored.

The treasury address is the sender of the GENESIS transaction, extracted via Section 4.1.1 (input 0 prevout scriptPubKey). No treasury encoding appears in the payload.

6.1.2 Validation Rules

  1. The transaction must appear at or after the genesis block height. Any 0x00 op before the genesis height is silently ignored.
  2. The GENESIS transaction is the first 0x434F47 00 OP_RETURN at or after the genesis height that passes both activation gates (rules 3 and 4), by block height then transaction index. The indexer scans all 0x00 candidates in block-height / tx-index order, skipping any that fail either gate, until one passes both. Earlier candidates that fail do not prevent later candidates from activating the protocol.
  3. The 32-byte genesis parameters hash (bytes 4–35) must match the SHA-256 of the published genesis parameters JSON (see 6.2). If it does not match, this 0x00 op is silently ignored and scanning continues. This rule made the protocol immune to front-running at launch — without it, an adversary could have blocked protocol activation by front-running the real GENESIS with a fake 0x00 op containing a garbage hash (costing only one Bitcoin tx fee). By skipping non-matching hashes, the indexer ignores all spurious 0x00 ops.
  4. The treasury scriptPubKey derived from the GENESIS transaction sender (input 0 prevout scriptPubKey, per Section 4.1.1) MUST match the scriptPubKey obtained by decoding the treasury_address field in the published genesis parameters JSON. If they do not match, this 0x00 op is silently ignored and scanning continues.
  5. After the GENESIS transaction is processed, any subsequent 0x00 op in any block is ignored.

6.1.3 Indexer Behavior

On startup, the indexer:

  1. Is configured with the genesis block height and the full set of decoded genesis parameter values (domain prices, fees, bootstrap pool size, scoring bundle hash, etc.) needed to initialize state in step 5. The implementation must also have the expected parameters hash and the expected treasury scriptPubKey for the activation gates. In practice, most implementations embed the canonical genesis parameters JSON as raw bytes and derive everything from it; an implementation that hardcodes the decoded values separately must still verify the parameters hash and treasury scriptPubKey against the GENESIS transaction.
  2. Scans all 0x00 candidates starting from the genesis height in block-height / tx-index order, applying both activation gates (Section 6.1.2 rules 3 and 4) to each candidate, skipping any that fail either gate, until one passes both.
  3. Verifies the parameters hash (bytes 4–35) matches.
  4. Extracts the treasury scriptPubKey from the GENESIS transaction's sender (input 0 prevout scriptPubKey, per Section 4.1.1) and verifies that it matches the scriptPubKey obtained by decoding the treasury_address field in the genesis parameters JSON. The block containing this transaction is the activation block.
  5. Initializes all state (balances, domain counters, bootstrap pool) using the genesis parameters.
  6. Processes transactions after the GENESIS transaction's index in the activation block, then all following blocks. Any Cogcoin transaction at or before the GENESIS transaction's index in the activation block is ignored — including MINE transactions, which are lost without compensation.

The treasury scriptPubKey is extracted from the sender of the GENESIS transaction (7258ebf6d45f13d46024ed00e5c21937a6e54f6a0f88afa96156ee4a6c4b667d) via Section 4.1.1. For the canonical GENESIS transaction, the sender prevout scriptPubKey is 0014ed495c1face9da3c7028519dbb36576c37f90e56, whose standard Bitcoin address rendering is bc1qa4y4c8ava8drcupg2xwmkdjhdsmljrjk5ejp0t. The genesis parameters JSON contains the same treasury as the treasury_address field, committed by the GENESIS hash. Conforming implementations MUST verify that these two representations resolve to the same treasury scriptPubKey. This scriptPubKey is the only treasury identity the indexer will ever recognize. Once set at activation, it is immutable.

Anti-spoofing. The indexer ignores all Cogcoin transactions before the genesis height. The GENESIS transaction confirmed at block 937,337. No subsequent 0x00 op has any effect — the protocol activated once and the activation is permanent.

6.2 Genesis Parameters

The genesis parameters are a JSON document whose SHA-256 hash is committed in the GENESIS transaction. The document is published in the @cogcoin/genesis package. The parameters are:

{
  "genesis_block": 937337,
  "protocol_magic": "0x434F47",
  "cogtoshi_per_cogcoin": 100000000,
  "bootstrap_pool_cogcoin": 100000,
  "bootstrap_award_per_registration_cogtoshi": 10000000,
  "domain_prices_satoshi": {
    "1_char": 10000000000,
    "2_char": 1000000000,
    "3_char": 100000000,
    "4_char": 10000000,
    "5_char": 1000000,
    "6_plus": 100000
  },
  "genesis_pubkey": "037fc008d03bcbb707a256518740caccabf2a0cd5323a99920a463bd3ca8a1dd53",
  "scoring_bundle_sha256": "7964653b810c4d10f824bb15fe0ebe1293a9823521e6d888bbf013a552b203c8",
  "data_update_fee_cogtoshi": 1,
  "field_registration_fee_cogtoshi": 100,
  "treasury_address": "bc1qa4y4c8ava8drcupg2xwmkdjhdsmljrjk5ejp0t"
}

The SHA-256 hash of the canonical minified genesis parameters JSON is 8320ab7cc763c9d3a3c6242fede3f4f2e10612759bd47331e12be4fcf4836462. This is the 32-byte value committed in the GENESIS transaction payload (bytes 4-35).

Canonical constants. The genesis parameters JSON commits economic values that are tunable at protocol design time (domain prices, data write fees, field registration fees, bootstrap award size). Consensus-critical constants that are structural to the protocol (subdomain registration fee, rank weights, name length limits, character set, size limits, null ID rules, overflow guards) are published in canonical_constants.json within the @cogcoin/genesis package, committed by SHA-256 in the signed genesis announcement. The complete set of consensus-critical values is the union of genesis_params.json and canonical_constants.json. The whitepaper is authoritative if any file and the whitepaper conflict.

Bootstrap award timing. The genesis parameter bootstrap_award_per_registration_cogtoshi specifies the bootstrap award amount. The key name references "registration," but the award is granted at DOMAIN_ANCHOR (Section 5.8.3 step 7), not at DOMAIN_REG. Anchoring is the commitment that earns the award — the domain owner permanently locks the domain to their address before receiving bootstrap COG. Implementations MUST wire this value to root-level DOMAIN_ANCHOR processing. The signed genesis announcement in the @cogcoin/genesis package states this explicitly in its clarifications section. An implementation that awards bootstrap at DOMAIN_REG will diverge on the first anchored domain and fail the state transition test vectors.

Byte-exact canonical form (consensus-critical). The genesis parameters are a byte-exact UTF-8 string, not a semantic JSON document. The hash is computed over the exact byte sequence published in the canonical genesis parameters file. JSON libraries that reorder keys, reformat numbers (e.g., 1e8 instead of 100000000), insert whitespace, or alter Unicode escaping will produce a different hash. Implementations MUST load the canonical file as raw bytes and hash it directly — they MUST NOT parse it as JSON and re-serialize it before hashing. The JSON shown above in this whitepaper is representative of the canonical content; the genesis_params.json file in the @cogcoin/genesis package is the authoritative byte sequence for hash verification.

The treasury is operationally represented as a scriptPubKey, derived from the GENESIS transaction's sender (Section 4.1.1). The treasury_address field in this JSON is part of the locked genesis parameters and is committed by the GENESIS hash. Conforming implementations MUST decode treasury_address to scriptPubKey form and verify that it is byte-identical to the sender-derived treasury scriptPubKey. If they differ, the genesis parameters and GENESIS transaction are inconsistent and the protocol does not activate.

Canonical artifact collection. The @cogcoin/genesis npm package is the canonical collection of every artifact required to implement a conforming Cogcoin indexer. The trust chain from the Bitcoin blockchain to every artifact works as follows:

The GENESIS transaction OP_RETURN commits the SHA-256 of genesis_params.json. The genesis parameters contain scoring_bundle_sha256, which transitively commits the WASM binary, model weights, and Coglex token table via the bundle's internal manifest. The genesis parameters also contain genesis_pubkey — the secp256k1 public key that signs the genesis announcement.

The signed genesis announcement (genesis_announcement.json + genesis_announcement.sig) commits every signed package artifact listed in package_manifest by SHA-256. genesis_announcement.json, genesis_announcement.sig, README.md, and package.json are intentionally excluded from that signed manifest. The announcement's chain_anchor.genesis_params_sha256 field matches the on-chain hash, creating a bidirectional binding: the on-chain hash authenticates the parameters, the parameters identify the signing key, and the signing key authenticates the signed package artifacts.

Activation requires both the on-chain hash check and the treasury consistency check: the treasury_address in the genesis parameters must decode to the same scriptPubKey as the GENESIS transaction sender (Section 4.1.1). An indexer that starts with a different genesis parameters file will compute a different hash, find no matching GENESIS transaction on-chain, and never activate.

The reference indexer source code is not committed by hash in any artifact. It is published as @cogcoin/indexer and receives bug fixes. Its conformance is enforced by state transition test vectors in @cogcoin/vectors, not by source hash. Test vectors may be expanded as new edge cases are discovered; their correctness is established by derivation from the whitepaper's rules.

6.3 Signed Genesis Announcement

The signed genesis announcement is a JSON document (genesis_announcement.json) that cryptographically binds the signed package artifacts in @cogcoin/genesis to the on-chain GENESIS transaction. It is signed with the secp256k1 private key corresponding to the public key committed in the genesis parameters — the same key that controls the treasury address. The GENESIS transaction sender, the treasury recipient, and the announcement signer are a single on-chain identity:

genesis_pubkey: 037fc008d03bcbb707a256518740caccabf2a0cd5323a99920a463bd3ca8a1dd53
address:        bc1qa4y4c8ava8drcupg2xwmkdjhdsmljrjk5ejp0t

The public key appears in both the genesis parameters JSON and this whitepaper. The JSON copy is committed by hash on-chain; the whitepaper copy is authenticated by the signed package manifest.

Contents. The announcement contains:

  1. Chain anchor: the GENESIS transaction ID, block height, block hash, and the SHA-256 of genesis_params.json (matching the on-chain commitment).
  2. Signing identity: the genesis public key, treasury address, and raw treasury scriptPubKey — explicitly stated as a single key. The GENESIS transaction sender, treasury recipient, and announcement signer are the same on-chain identity.
  3. Package manifest: SHA-256 hashes of the signed package artifacts in @cogcoin/genesis: genesis_params.json, genesis_tx.json, canonical_constants.json, bip39_english.txt, cogcoin_whitepaper.md, verify.mjs, and every file in the scoring bundle.
  4. Clarifications: explicit statements that bootstrap_award_per_registration_cogtoshi applies at DOMAIN_ANCHOR (not DOMAIN_REG), and that settle_block_wasm is non-consensus.

Signature format. The signature is a standard Bitcoin message signature produced by bitcoin-cli signmessagewithprivkey. The signed message is the SHA-256 hash of genesis_announcement.json — a 64-character lowercase hex string computed over the raw bytes of the file (minified JSON, no trailing newline). The signature is stored in genesis_announcement.sig as a base64 string. The signing key is the secp256k1 private key corresponding to genesis_pubkey in the genesis parameters — the same key that controls the treasury address.

Verification procedure:

  1. Compute the SHA-256 hash of genesis_announcement.json (raw bytes).
  2. Load the base64 signature from genesis_announcement.sig.
  3. Verify: bitcoin-cli verifymessage "1Ndf2baN7oQffJwzVbZYqvHAhzJQyZgYcA" "<base64_sig>" "<hex_hash_from_step_1>". The legacy address is the P2PKH encoding of genesis_pubkey — the same key as the bech32 treasury address bc1qa4y4c8ava8drcupg2xwmkdjhdsmljrjk5ejp0t. Both derive from RIPEMD160(SHA256(genesis_pubkey)). The verify.mjs script in the @cogcoin/genesis package performs this derivation and verifies the signature with zero npm dependencies.
  4. Verify that chain_anchor.genesis_params_sha256 in the announcement matches the SHA-256 of the included genesis_params.json.
  5. Verify that each file's SHA-256 matches its entry in package_manifest.

If all checks pass, every file listed in package_manifest is cryptographically authenticated by the entity that created the GENESIS transaction.

Scope of the signature. The signature authenticates the package contents and the identity of the protocol author. The key's post-publication role is authenticating two defined future artifacts: the PQ_MIGRATE companion specification (@cogcoin/pq) and whitepaper errata (@cogcoin/errata), both specified in Section 7.5. A copycat protocol can replicate every design decision in this document but cannot produce a valid signature that verifies against genesis_pubkey037fc008d03bcbb707a256518740caccabf2a0cd5323a99920a463bd3ca8a1dd53.

6.4 Launch Sequence

The complete launch sequence was:

  1. Genesis transaction. The GENESIS transaction was broadcast targeting the genesis height. It confirmed at block 937,337 — the activation block. The protocol was live. No prior public announcement was made.
  2. Simultaneous publication. After genesis confirmation, the @cogcoin/genesis package was published: this whitepaper, the signed genesis announcement, the scoring bundle, the genesis transaction data, the canonical constants, the BIP-39 wordlist, and the package verification script. The reference indexer (@cogcoin/indexer), sample client (@cogcoin/client), state transition test vectors (@cogcoin/vectors), and scoring settlement wrapper (@cogcoin/scoring) were published separately. The scoring bundle is verifiable against the hash committed in the genesis parameters. The announcement signature authenticates every artifact in the genesis package against the genesis public key.
  3. Mining begins. MINE submissions are valid in the activation block (after the GENESIS transaction) and in all subsequent blocks. In practice, no miner had access to the scoring bundle until step 2, so the first realistic submissions appeared in blocks after publication. The first rewards were settled at the end of the first block containing MINE submissions.

The genesis-first sequence was deliberate. Publishing before activation would have given squatters time to prepare pre-signed domain registration transactions targeting the activation block. Confirming the GENESIS transaction before publication ensured that all participants discovered the protocol on equal footing. The chain of cryptographic commitments (parameters hash on-chain, scoring bundle hash in parameters, genesis signature over announcement) is fully verifiable after the fact.

The launch is complete. The protocol runs on Bitcoin. No entity has an ongoing protocol function. No one can modify rules, upgrade contracts, freeze assets, or intervene in any state transition. The protocol is self-sustaining: miners mine, domains resolve, data persists, reputation accrues, locks resolve, trades settle — all from Bitcoin block data alone.


7. Indexer State Machine

7.1 State

A conforming Cogcoin indexer requires access to a Bitcoin full node with prevout data, not just OP_RETURN outputs. Sender address extraction (Section 4.1.1) requires the prevout scriptPubKey for input 0 of Cogcoin transactions. This is the only UTXO-dependent operation — the indexer does not need to scan non-Cogcoin transactions and does not need to maintain a running UTXO set.

The indexer maintains the following state, reconstructable from the Bitcoin blockchain:

activation_block:     uint32  (block height where GENESIS confirmed; set during genesis scan)
treasury_scriptpubkey: bytes  (sender of GENESIS transaction per Section 4.1.1; immutable after activation)
cogcoin_balances:     map[scriptpubkey] -> uint64 (cogtoshi)
total_cog_supply:     uint64  (total non-burned COG in existence; used in per-block state hash)
domains:              map[domain_name] -> {domain_id, owner_scriptpubkey, anchored, anchor_height, reg_height, next_field_id, endpoint, delegate_scriptpubkey, miner_scriptpubkey, pq_hash}
domain_by_id:         map[domain_id] -> {name, owner_scriptpubkey, anchored, anchor_height, reg_height, next_field_id, endpoint, delegate_scriptpubkey, miner_scriptpubkey, pq_hash}
domain_listings:      map[domain_id] -> {price_cogtoshi, seller_scriptpubkey}
fields:               map[(domain_id, field_id)] -> {name, permanent}
field_by_name:        map[(domain_id, field_name)] -> field_id
self_stake:           map[domain_id] -> uint64 (cogtoshi, domain must be anchored)
net_support:          map[(source_domain_id, target_domain_id)] -> uint64 (support minus revocations; entry removed when value reaches zero)
supported_stake:      map[domain_id] -> uint64 (sum of all net_support for this domain)
total_supported:      map[domain_id] -> uint64 (cumulative cogtoshi ever supported)
total_revoked:        map[domain_id] -> uint64 (cumulative cogtoshi ever revoked)
domain_data:          map[(domain_id, field_id)] -> {format: uint8, value: bytes}  (field values)
bootstrap_remaining:  uint64 (cogtoshi)
mining_pending:       map[block_height] -> list[{sender_scriptpubkey, mining_domain_id, raw_sentence_bytes, bip39_word_indices, referenced_blockhash, tx_index}]  (consumed at end of same block's settlement)
next_domain_id:       uint32  (sequential counter for domain IDs, starts at 1; ID 0 is reserved/null)
total_field_count:    uint64  (total number of fields registered across all domains; used in per-block state hash)
next_lock_id:         uint32  (sequential counter for lock IDs, starts at 1; ID 0 is reserved/null)
cog_locks:            map[lock_id] -> {locker_scriptpubkey, amount, condition, timeout_height, recipient_domain_id, creation_height}
active_lock_count:    uint32  (number of active/unresolved COG_LOCKs)
total_lock_cog:       uint64  (sum of all active COG_LOCK amounts)
canonical_domain:     map[scriptpubkey] -> domain_id  (set by DOMAIN_ANCHOR on first anchor, updatable via SET_CANONICAL)
canonical_count:      uint32  (number of entries in canonical_domain; used in per-block state hash)
total_listing_count:  uint32  (number of active DOMAIN_SELL listings; used in per-block state hash)
total_burned_cog:     uint64  (cumulative cogtoshi destroyed: field_reg + data_update writes + REP_COMMIT burns (self and third-party) + subdomain_reg burns)
total_self_staked:    uint64  (sum of all domains' self_stake; used in per-block state hash)
total_net_supported:  uint64  (sum of all domains' supported_stake; used in per-block state hash)
anchored_domain_count:  uint32  (number of domains anchored via DOMAIN_ANCHOR; used in per-block state hash)
total_minted_cog:     uint64  (cumulative cogtoshi credited via mining rewards; used in per-block state hash)
balance_xor:          bytes32 (running XOR fingerprint of all non-zero (address, balance) pairs; used in per-block state hash)
domain_xor:           bytes32 (running XOR fingerprint of all (domain_id, name, owner, anchored, reg_height, anchor_height, next_field_id) tuples; used in per-block state hash)
lock_xor:             bytes32 (running XOR fingerprint of all active lock entries; used in per-block state hash)
listing_xor:          bytes32 (running XOR fingerprint of all active (domain_id, price, seller) listing tuples; used in per-block state hash)
field_xor:            bytes32 (running XOR fingerprint of all (domain_id, field_id, permanent, name) field tuples; used in per-block state hash)
support_xor:          bytes32 (running XOR fingerprint of all non-zero (source_domain_id, target_domain_id, net_support) tuples; used in per-block state hash)
reputation_xor:       bytes32 (running XOR fingerprint of all anchored domains whose (self_stake, supported_stake, total_supported, total_revoked) 4-tuple is not all zero; used in per-block state hash)
data_xor:             bytes32 (running XOR fingerprint of all non-null (domain_id, field_id, format, value) entries in domain_data; used in per-block state hash)
endpoint_xor:         bytes32 (running XOR fingerprint of all non-null (domain_id, endpoint_bytes) entries; used in per-block state hash)
canonical_xor:        bytes32 (running XOR fingerprint of all (scriptpubkey, domain_id) entries in canonical_domain; used in per-block state hash)
delegate_xor:         bytes32 (running XOR fingerprint of all non-null (domain_id, delegate_scriptpubkey) entries; used in per-block state hash)
miner_xor:            bytes32 (running XOR fingerprint of all non-null (domain_id, miner_scriptpubkey) entries; used in per-block state hash)
pq_xor:               bytes32 (running XOR fingerprint of all PQ commitments; used in per-block state hash)

Protocol-level stored data (not in state hash). The state fields above are consensus-critical and included in the per-block state hash. The following data is defined by the protocol, permanently recorded on the Bitcoin blockchain, and MUST be decoded and stored by conforming indexers — but it does not appear in the per-block state hash and does not affect transaction validity:

founding_messages:    map[domain_id] -> decoded_text  (set during DOMAIN_ANCHOR via decode_sentence_wasm; null if absent/invalid; not in domain_xor or any state hash)
reviews:              list[{target_domain_id, source_domain_id, type: commit|revoke, amount, review_text, block_height, txid}]  (set during REP_COMMIT/REP_REVOKE via decode_sentence_wasm; null if absent/invalid; not in any state hash)

Founding messages and reviews do not affect validation, state transitions, or state hashes. During reorgs, they are cleaned up alongside the consensus state they accompany (Section 7.3). Their elevation to protocol-level storage ensures that all conforming indexers produce identical decoded text for the lookup_domain (Section 14) and get_reviews queries, eliminating interoperability divergence from independent Coglex reimplementations.

The following data is permanently recorded on the Bitcoin blockchain and MAY be stored by indexers, but is not required:

  • Miner data: Bytes 72–79 of MINE transactions (Section 5.1.1). Not protocol-level.

Implementer note: subdomain status and parent are derived, not stored. The domain record contains no is_subdomain or parent_id field. Whether a domain is a subdomain is determined by the presence of a hyphen in the domain name. The parent prefix, if applicable, is the substring before the last hyphen. Indexers derive these at query time from domain.name. No additional state is needed to support subdomain operations.

7.2 Processing Order


For each Bitcoin block at or after the genesis height, the indexer processes Cogcoin transactions in the following order:

  1. Sort transactions by their position in the block (index 0, 1, 2, ...).
  2. For each transaction, identify the Cogcoin output (if any) using the extraction procedure in Section 3.1.
  3. Parse the operation type and payload. Op 0x00 is ignored after the GENESIS transaction has been processed.
  4. Apply the operation to the state (checking balances, ownership, etc.).
  5. If the operation is invalid (insufficient balance, duplicate domain, etc.), silently skip it.

All Cogcoin transactions before the genesis block height are ignored. The GENESIS transaction confirmed at the genesis height (937,337), so the activation block and the genesis height are the same block — no blocks were skipped.

Mining rewards are settled at the end of each block's processing. After the indexer has processed all Cogcoin transactions in block H (steps 1-5 above), it settles mining rewards for all valid MINE transactions in block H using the canonical WASM scoring entry point (score_sentences_wasm) plus the @cogcoin/scoring settlement logic (ranking, deduplication, tie-breaking, reward distribution), or a byte-identical reimplementation of the settlement logic only — the WASM scoring path itself must not be reimplemented natively (Section 5.1.6). Mining rewards for block H are credited at the end of block H processing — a miner cannot spend block H rewards until block H+1 at the earliest. This ordering is consensus-critical.

7.3 Reorg Handling

If a blockchain reorganization occurs:

  1. Unwind the affected blocks (reverse all state changes).
  2. Reprocess the new chain from the fork point.

The indexer must be able to efficiently undo state changes. This can be implemented with a journal/log of state transitions per block.

Reorg across the activation block (consensus-critical). The GENESIS transaction confirmed at block 937,337. A reorganization deep enough to remove block 937,337 is astronomically unlikely at current chain depth, but the indexer must handle it for correctness. If a reorganization removes the activation block, the indexer must unwind all Cogcoin state and return to the pre-activation scanning state. It then rescans from the genesis height forward on the new chain to find the GENESIS transaction. All state derived from the original activation — domain registrations, mining rewards, balances — is invalidated and rebuilt from the new chain. This is the most expensive reorg case but is handled by the same unwind-and-reprocess logic used for all other reorgs.

Reorg of DOMAIN_ANCHOR. If a reorg removes a block containing a DOMAIN_ANCHOR: unwind the anchor (set domain.anchored = false, clear domain.anchor_height to NULL), decrement anchored_domain_count, remove the entry from founding_messages for this domain (or set to null), and restore any DOMAIN_SELL listing that the anchor had cancelled (incrementing total_listing_count by 1 if a listing is restored).

If the DOMAIN_ANCHOR created a canonical_domain entry for the owner (because this was the owner's first anchor), remove the entry and decrement canonical_count by 1. If a bootstrap award was granted (root-level domain, pool was not exhausted at the time), reverse it: decrement the sender's Cogcoin balance by the awarded amount, increment bootstrap_remaining by the same amount, and decrement total_cog_supply by the same amount. If the award was partial (pool exhausted mid-block), restore only the partial amount.

Any operations in subsequent blocks that depended on the domain being anchored (FIELD_REG, DATA_UPDATE, SET_ENDPOINT, REP_COMMIT, subdomain DOMAIN_REG under this namespace, etc.) are also unwound by the general mechanism and will fail validation on the new chain if the DOMAIN_ANCHOR does not reappear. This is handled by the general unwind-and-reprocess logic — no special-case code is needed.

Reorg of SET_ENDPOINT. If a reorg removes a block containing a SET_ENDPOINT: restore the previous endpoint value (or null if no prior SET_ENDPOINT existed). This is handled by the general unwind-and-reprocess logic.

Reorg of DOMAIN_TRANSFER. If a reorg removes a block containing a DOMAIN_TRANSFER: revert domain ownership to the original owner. If the DOMAIN_TRANSFER had cancelled an active DOMAIN_SELL listing (Section 5.5.3 step 1), restore the listing with its original price and increment total_listing_count by 1. This is handled by the general unwind-and-reprocess logic.

Reorg of DOMAIN_SELL. If a reorg removes a block containing a DOMAIN_SELL with price > 0: if the DOMAIN_SELL created a new listing (no prior listing existed), remove the listing and decrement total_listing_count by 1. If the DOMAIN_SELL updated an existing listing's price, restore the previous price and leave total_listing_count unchanged. If a reorg removes a block containing a DOMAIN_SELL with price = 0 (cancellation): restore the listing that was cancelled and increment total_listing_count by 1. If the original DOMAIN_SELL was a no-op (no listing existed at the time), the reorg is also a no-op — total_listing_count is unchanged. This is handled by the general unwind-and-reprocess logic.

Reorg of DOMAIN_BUY. If a reorg removes a block containing a DOMAIN_BUY: reverse the COG transfer (debit the seller, credit the buyer), restore domain ownership to the original owner, and restore the listing with its original price. Increment total_listing_count by 1. This is handled by the general unwind-and-reprocess logic.

Reorg of root DOMAIN_REG. If a reorg removes a block containing a root domain registration (no hyphen): remove the domain from state, decrement next_domain_id. The BTC payment to treasury reverses naturally on the Bitcoin layer and requires no indexer action. This is handled by the general unwind-and-reprocess logic.

Reorg of subdomain DOMAIN_REG. If a reorg removes a block containing a subdomain DOMAIN_REG: unwind the domain creation (remove the domain from state, decrement next_domain_id), re-credit the sender's Cogcoin balance by 100 cogtoshi (the burned amount), decrement total_burned_cog by 100, and increment total_cog_supply by 100. Any subsequent operations that depended on the subdomain existing (DOMAIN_ANCHOR, DOMAIN_TRANSFER, FIELD_REG, etc.) are also unwound by the general mechanism. This is handled by the same unwind-and-reprocess logic — no special-case code is needed.

Cascading subdomain invalidation. A reorg that removes an intermediate domain's DOMAIN_ANCHOR can cascade to deeper levels. If block N contains the DOMAIN_ANCHOR for "oracle-weather" and block N+5 contains a DOMAIN_REG for "oracle-weather-tokyo" (which requires "oracle-weather" to be anchored), reorging block N invalidates the DOMAIN_REG in block N+5. On reprocessing, "oracle-weather" is no longer anchored at the time "oracle-weather-tokyo" is validated, so the registration fails.

This extends to arbitrary depth — losing an anchor at level K invalidates all registrations at levels K+1 and below that depended on it. The general unwind-and-reprocess mechanism handles this correctly with no special-case code, but implementers should be aware that a single reorged DOMAIN_ANCHOR can invalidate an entire subtree of registrations beneath it.

Reorg of COG_LOCK. If a reorg removes a block containing a COG_LOCK: unwind the lock (return the locked COG to the locker's available balance, remove the lock entry, decrement next_lock_id, decrement active_lock_count, subtract the amount from total_lock_cog). Any COG_CLAIM in subsequent blocks that resolved this lock is also unwound by the general mechanism.

Lock ID stability across reorgs. After a reorg, next_lock_id is decremented and the reprocessed chain may assign the same numeric lock IDs to different locks. External systems (explorers, agent caches, cross-chain bridges) that store lock IDs across reorgs should treat IDs as invalidated at the reorg depth and re-query the indexer. This is consistent with Bitcoin's own treatment of transaction confirmations across reorgs. Domain IDs have the same property: a reorged DOMAIN_REG that reappears in a different transaction order may assign a different ID.

Reorg of COG_CLAIM. If a reorg removes a block containing a COG_CLAIM: unwind the claim (debit the COG from the claimant's balance, restore the lock to active state, increment active_lock_count, add the amount back to total_lock_cog). The lock is once again claimable or reclaimable on the new chain.

Both cases are handled by the general unwind-and-reprocess mechanism — no special-case logic is needed.

Reorg of COG_TRANSFER. If a reorg removes a block containing a COG_TRANSFER: reverse the balance change (debit the recipient, credit the sender by the transferred amount). total_cog_supply is unchanged. This is handled by the general unwind-and-reprocess logic.

Reorg of MINE. If a reorg removes a block whose mining settlement credited rewards: reverse all reward credits (debit each winner's balance by their share), decrement total_minted_cog by the total distributed amount, and decrement total_cog_supply by the same amount. Submissions in mining_pending for the removed block are discarded. On the new chain, any MINE transactions in the replacement block are collected and settled normally. This is handled by the general unwind-and-reprocess logic.

Reorg of FIELD_REG. If a reorg removes a block containing a FIELD_REG: remove the field from state, decrement the parent domain's next_field_id, update domain_xor for the next_field_id change, decrement total_field_count, re-credit the sender's Cogcoin balance by 100 cogtoshi, decrement total_burned_cog by 100, and increment total_cog_supply by 100. Any DATA_UPDATE in subsequent blocks that wrote to this field is also unwound by the general mechanism. This is handled by the general unwind-and-reprocess logic.

Reorg of DATA_UPDATE. If a reorg removes a block containing a DATA_UPDATE: restore the previous field value (or remove the entry if no prior write existed). If the DATA_UPDATE was a write (non-zero format byte), re-credit the sender's Cogcoin balance by 1 cogtoshi, decrement total_burned_cog by 1, and increment total_cog_supply by 1. If the DATA_UPDATE was a clear (format byte 0x00), no balance change is needed (clears are free). For permanent fields, if the reorged DATA_UPDATE was the first write, the field reverts to its empty, unfrozen state — it is once again open for one future write. This is handled by the general unwind-and-reprocess logic.

Reorg of REP_COMMIT. If a reorg removes a block containing a REP_COMMIT: re-credit the sender's Cogcoin balance by the burned amount, decrement total_burned_cog by the burned amount, increment total_cog_supply by the burned amount, and reverse the reputation change. For self-commitments (source == target): decrement the target domain's self_stake and decrement total_self_staked. For third-party endorsements (source != target): decrement net_support[(source_domain_id, target_domain_id)], decrement the target domain's supported_stake, decrement the target domain's total_supported, and decrement total_net_supported. Discard the review (if any) associated with the REP_COMMIT transaction. This is handled by the general unwind-and-reprocess logic.

Reorg of REP_REVOKE. If a reorg removes a block containing a REP_REVOKE: reverse the revocation — increment net_support[(source_domain_id, target_domain_id)] by the revocation amount, increment the target domain's supported_stake, decrement the target domain's total_revoked, and increment total_net_supported. No balance change is needed (revocation does not return COG). Discard the revocation review (if any) associated with the REP_REVOKE transaction. This is handled by the general unwind-and-reprocess logic.

Reorg of SET_CANONICAL. If a reorg removes a block containing a SET_CANONICAL: restore the previous canonical_domain[sender] value (or the value set by the most recent prior DOMAIN_ANCHOR or SET_CANONICAL, if any). canonical_count is unchanged — SET_CANONICAL only updates existing entries, never creates or deletes them. This is handled by the general unwind-and-reprocess logic.

Reorg of SET_DELEGATE. If a reorg removes a block containing a SET_DELEGATE: restore the previous domain.delegate value (or null if no prior SET_DELEGATE existed). This is handled by the general unwind-and-reprocess logic.

Reorg of SET_MINER. If a reorg removes a block containing a SET_MINER: restore the previous domain.miner value (or null if no prior SET_MINER existed). This is handled by the general unwind-and-reprocess logic.

Reorg of PQ_COMMIT. If a reorg removes a block containing a PQ_COMMIT: clear domain.pq_hash to null and XOR the entry back out of pq_xor. This is handled by the general unwind-and-reprocess logic.

7.4 State Transition Test Vectors

Conforming implementations MUST produce identical state snapshots on a published set of synthetic test blocks. The state transition test vectors are published in @cogcoin/vectors (test vectors are not part of @cogcoin/genesis and may be expanded) and cover all 20 operations, including:

Mining settlement vectors MUST include poison-pill disagreement cases that intentionally fail under settle_block_wasm and under naive independent per-rank floor allocation. Passing only happy-path mining vectors is insufficient for conformance.

7.4.1 OP_RETURN Extraction and Parsing

  • V-001: OP_RETURN data of 81 bytes with valid COG magic and valid operation — output skipped (step D); transaction has no Cogcoin effect.
  • V-002: OP_RETURN data of exactly 80 bytes — accepted.
  • V-003: OP_RETURN data of 3 bytes — output skipped (step D).
  • V-004: Valid Cogcoin transaction whose OP_RETURN output carries a non-zero satoshi value — accepted. The satoshi amount is irrelevant; an implementation that rejects non-zero-value OP_RETURN outputs will fork.
  • V-005: Coinbase transaction with valid-looking COG_TRANSFER OP_RETURN — silently ignored (coinbase has no sender).
  • V-006: Coinbase transaction with valid-looking MINE OP_RETURN — ignored.
  • V-007: Coinbase transaction with valid-looking GENESIS 0x00 OP_RETURN and correct parameters hash — ignored, does not activate the protocol.
  • V-008: Two OP_RETURN outputs: first has COG magic but 81 bytes (oversized), second is valid REP_COMMIT — first skipped (fails step D), second processed.
  • V-009: Two OP_RETURN outputs: first is non-COG OP_RETURN (no magic, valid size), second is valid COG_TRANSFER — first skipped (fails step E), second processed.
  • V-010: OP_RETURN output whose push opcode declares 100 bytes but only 40 remain in scriptPubKey, followed by valid COG OP_RETURN — first skipped (fails step C), second processed.
  • V-011: OP_RETURN output whose OP_PUSHDATA2 length field is truncated (1 byte instead of 2), followed by valid COG OP_RETURN — first skipped (fails step C), second processed.
  • V-012: OP_RETURN output containing non-push opcode after 0x6a (e.g., 0x6a 0x61), followed by valid COG OP_RETURN — first skipped (fails step B), second processed.
  • V-013: OP_FALSE + OP_RETURN output containing valid COG data, followed by real OP_RETURN with valid COG data — first skipped (fails step A), second processed.
  • V-014: Two OP_RETURN outputs: first passes extraction (valid magic, 4-80 bytes) but carries unknown op code 0x99, second carries valid known operation — first output selected by step F, unknown op ignored, second never examined, transaction has no Cogcoin effect.
  • V-015: Two OP_RETURN outputs: first passes extraction with known op code but fails operation-specific validation (e.g., truncated COG_TRANSFER), second is fully valid — first output selected by step F, truncated op ignored, second never examined.
  • V-016: OP_RETURN output using OP_PUSHDATA1 (0x4c) to encode a 20-byte COG payload (non-minimal encoding) — accepted.
  • V-017: OP_RETURN output using OP_PUSHDATA2 (0x4d) with 2-byte little-endian length field encoding a 20-byte COG payload (0x1400) — accepted. Verify length is read little-endian (big-endian 0x0014 = 5120 bytes would fail).
  • V-018: OP_RETURN output using OP_PUSHDATA4 (0x4e) with 4-byte little-endian length field encoding a short COG payload — accepted.
  • V-019: Two data pushes in one OP_RETURN: first push is 3 bytes (too short, fails step D), second push is valid COG — only first push read, output skipped, scanning continues to next output.
  • V-020: Two data pushes in one OP_RETURN: first push is valid COG payload — first push extracted and processed, second push never read.
  • V-021: Two data pushes in one OP_RETURN: first push is size-valid (4-80 bytes) but no COG magic, second push is valid COG — first push read, fails step E, output skipped, second push within same output never examined.

7.4.2 Identity and Address Handling

  • V-022: Sender prevout scriptPubKey exceeding 67 bytes — transaction silently ignored.
  • V-023: COG_TRANSFER with recipient length L > 67 — silently ignored.
  • V-024: DOMAIN_TRANSFER with recipient length L > 67 — silently ignored.
  • V-025: COG_TRANSFER with L = 0 — silently ignored.
  • V-026: DOMAIN_TRANSFER with L = 0 — silently ignored (would create unrecoverable domain).
  • V-027: Sender prevout scriptPubKey of zero bytes — silently ignored.
  • V-028: Multi-input transaction: input 0 and input 1 have different prevout scriptPubKeys — sender is input 0 only.
  • V-029: COG_TRANSFER with recipient L = 67 — accepted (maximum).
  • V-030: COG_TRANSFER with recipient L = 68 — rejected.
  • V-031: DOMAIN_TRANSFER with recipient L = 67 — accepted.
  • V-032: DOMAIN_TRANSFER with recipient L = 68 — rejected.
  • V-033: SET_DELEGATE with delegate L = 67 — accepted.
  • V-034: SET_DELEGATE with delegate L = 68 — rejected.
  • V-035: SET_MINER with miner L = 67 — accepted.
  • V-036: SET_MINER with miner L = 68 — rejected.
  • V-037: SET_ENDPOINT with URI length 72 bytes (payload 76 bytes) — accepted (maximum).
  • V-038: SET_ENDPOINT with URI length 73 bytes (payload 77 bytes) — rejected.
  • V-039: Sender prevout scriptPubKey of exactly 67 bytes — accepted.
  • V-040: Sender prevout scriptPubKey of 68 bytes — silently ignored.
  • V-041: COG_TRANSFER with recipient scriptPubKey that is length-valid (1-67 bytes) but not any known address encoding — accepted, stored byte-for-byte.
  • V-042: DOMAIN_TRANSFER with unknown-encoding recipient scriptPubKey — accepted, stored byte-for-byte.
  • V-043: SET_DELEGATE with unknown-encoding delegate scriptPubKey — accepted, stored byte-for-byte.
  • V-044: SET_MINER with unknown-encoding miner scriptPubKey — accepted, stored byte-for-byte.
  • V-045: Sender input 0 prevout scriptPubKey is nonstandard-but-length-valid (e.g., bare OP_TRUE) — successfully performs COG_TRANSFER or any operation.
  • V-046: COG_TRANSFER from P2WPKH sender to same key's P2PKH scriptPubKey — succeeds, creates separate balance entry (different identity).
  • V-047: DOMAIN_TRANSFER from P2WPKH owner to same key's P2TR scriptPubKey — succeeds, domain owner changes to P2TR bytes, subsequent ops require P2TR sender.
  • V-048: SET_DELEGATE from domain owner to same key's P2WPKH scriptPubKey — accepted (not self-delegation, byte strings differ).
  • V-049: Every handler that takes a domain ID rejects domain ID 0: DOMAIN_TRANSFER, DOMAIN_SELL, DOMAIN_BUY, DOMAIN_ANCHOR, SET_ENDPOINT, SET_DELEGATE, SET_MINER, SET_CANONICAL, FIELD_REG, DATA_UPDATE, REP_COMMIT (source), REP_COMMIT (target), REP_REVOKE (source), REP_REVOKE (target), COG_LOCK (recipient), PQ_COMMIT, PQ_MIGRATE.
  • V-050: Every handler that takes a domain ID rejects domain ID >= next_domain_id.
  • V-051: DATA_UPDATE with field_id = 0 — rejected.
  • V-052: DATA_UPDATE with valid domain_id but field_id never registered under that domain — rejected.
  • V-053: DATA_UPDATE targeting field_id not yet assigned (e.g., domain next_field_id = 3, DATA_UPDATE targets field_id 5) — rejected.
  • V-054: COG_CLAIM with lock_id = 0 — rejected.
  • V-055: COG_CLAIM with lock_id >= next_lock_id — rejected.
  • V-056: COG_CLAIM against already-resolved lock — rejected.

7.4.3 Payload Structure

  • V-057: COG_TRANSFER with recipient L = 34 but payload shorter than 9+L bytes — silently ignored.
  • V-058: DOMAIN_TRANSFER with recipient L = 22 but payload shorter than 5+L bytes — silently ignored.
  • V-059: DOMAIN_REG with name length N = 50 but payload shorter than 1+N bytes — silently ignored.
  • V-060: FIELD_REG with name length N = 40 but payload shorter than 6+N bytes — silently ignored.
  • V-061: SET_DELEGATE with delegate L = 67 but payload shorter than 5+L bytes — silently ignored.
  • V-062: SET_MINER with same truncation pattern — silently ignored.
  • V-063: Each variable-length operation with L/N = 1 and exactly enough bytes — accepted.
  • V-064: Padded REP_COMMIT (fixed 20-byte layout) with 4 trailing zero bytes (24-byte payload) — accepted, trailing bytes ignored.
  • V-065: Padded REP_REVOKE (fixed 20-byte layout) with trailing bytes — accepted, trailing bytes ignored.
  • V-066: Padded COG_TRANSFER: recipient L bytes present plus additional trailing bytes — accepted, trailing bytes ignored.
  • V-067: Padded DOMAIN_TRANSFER: recipient L bytes present plus additional trailing bytes — accepted, trailing bytes ignored.
  • V-068: Padded DATA_UPDATE clear: format byte 0x00 followed by 3 trailing bytes — accepted, clear succeeds, trailing bytes ignored. Distinct from SET_ENDPOINT/SET_DELEGATE/SET_MINER where only exact payload length 4 triggers clear.
  • V-069: Padded SET_DELEGATE set: valid L > 0, declared scriptPubKey present, additional trailing bytes — accepted, delegate set, trailing bytes ignored.
  • V-070: Padded SET_MINER set: same pattern — accepted, miner set, trailing bytes ignored. High-risk for over-enforcement due to combined length-prefixed set + exact-length clear encoding.
  • V-071: Padded COG_LOCK: trailing bytes beyond 52-byte parsed layout — accepted.
  • V-072: Padded COG_CLAIM: trailing bytes beyond 40-byte parsed layout — accepted.
  • V-073: Padded DOMAIN_SELL: trailing bytes beyond 16-byte parsed layout — accepted.
  • V-074: Padded DOMAIN_BUY: trailing bytes beyond 16-byte parsed layout — accepted.
  • V-075: Padded SET_CANONICAL: trailing bytes beyond 8-byte parsed layout — accepted.
  • V-076: Padded DOMAIN_ANCHOR: trailing bytes beyond 8-byte parsed layout — accepted. If OP_RETURN >= 68 bytes, the indexer decodes bytes 8–67 as a founding message (Section 5.8.7). See founding message test vectors (V-414 through V-419).
  • V-077: Padded root DOMAIN_REG: name length N, N bytes of name, additional trailing bytes — accepted, trailing bytes ignored.
  • V-078: Padded subdomain DOMAIN_REG: same pattern — accepted.
  • V-079: Padded FIELD_REG: name length N, N bytes of name, additional trailing bytes — accepted, trailing bytes ignored. Extra bytes must not be interpreted as field content or initial value.

7.4.4 Domain Registration and Naming

  • V-080: DOMAIN_REG with name length N = 0 — rejected.
  • V-081: FIELD_REG with name length N = 0 — rejected.
  • V-082: DOMAIN_REG with uppercase characters ("Oracle") — rejected, not silently lowercased.
  • V-083: FIELD_REG with uppercase characters ("Api-Url") — rejected.
  • V-084: DOMAIN_REG with digit-only name ("123") — accepted.
  • V-085: DOMAIN_REG with digit-starting name ("0x") — accepted.
  • V-086: FIELD_REG with digit-only name ("123") — accepted.
  • V-087: FIELD_REG with digit-starting name ("0x") — accepted.
  • V-088: DOMAIN_REG with exactly 63-byte name — accepted (maximum).
  • V-089: DOMAIN_REG with 64-byte name — rejected.
  • V-090: FIELD_REG with exactly 63-byte name — accepted.
  • V-091: FIELD_REG with 64-byte name — rejected.
  • V-092: DOMAIN_REG with non-ASCII bytes in name (e.g., UTF-8 encoded characters) — rejected.
  • V-093: FIELD_REG with non-ASCII bytes — rejected.
  • V-094: DOMAIN_REG with leading hyphen ("-foo") — rejected.
  • V-095: DOMAIN_REG with trailing hyphen ("foo-") — rejected.
  • V-096: DOMAIN_REG with consecutive hyphens ("foo--bar") — rejected.
  • V-097: FIELD_REG with leading hyphen ("-api") — rejected.
  • V-098: FIELD_REG with trailing hyphen ("api-") — rejected.
  • V-099: FIELD_REG with consecutive hyphens ("api--url") — rejected.
  • V-100: Same-block DOMAIN_REG poison pill: earlier transaction underpays treasury for same name, later transaction pays correctly — later succeeds (first valid wins, not first seen).
  • V-101: Same-block subdomain DOMAIN_REG poison pill: earlier from non-owner/non-delegate of parent, later valid from actual owner — later succeeds.
  • V-102: Same-block FIELD_REG poison pill: earlier fails validation (e.g., unanchored domain) for same (domain_id, field_name), later passes — later succeeds.
  • V-103: Subdomain registration: parent validation (last-hyphen rule), COG burn, balance check, no bootstrap.
  • V-104: Subdomain minting across multiple anchored levels.
  • V-105: Subdomain gap-jumping rejected: intermediate parent does not exist or is not anchored.
  • V-106: Subdomain with consecutive hyphens in name — rejected.
  • V-107: Subdomain reorg unwind including cascading invalidation.
  • V-108: Delegate registers subdomain — new domain owned by delegate (sender), not parent owner. COG burn debited from delegate's balance.
  • V-109: Root domain treasury payment: two outputs each paying half — registration ignored (amounts not summed).
  • V-110: Root domain treasury payment: one output pays full price, second also pays treasury — first qualifying output sufficient, second irrelevant.
  • V-111: Root domain treasury payment: overpayment in single output — accepted (excess is donation).
  • V-112: Root domain treasury payment: first treasury output underpays, second pays full amount — registration succeeds. Implementation that stops at first treasury match will fork.
  • V-113: 5-char domain at 5-char price (1,000,000 sat) — accepted.
  • V-114: 6-char domain at 5-char price — accepted (overpays 6+ tier at 100,000 sat).
  • V-115: 5-char domain at 6+ price (100,000 sat) — rejected (underpays).
  • V-116: 4-char domain at 4-char price (10,000,000 sat) — accepted.
  • V-117: 4-char domain at 5-char price (1,000,000 sat) — rejected.
  • V-118: 3-char domain at 3-char price (100,000,000 sat) — accepted.
  • V-119: 3-char domain at 4-char price (10,000,000 sat) — rejected.
  • V-120: 2-char domain at 2-char price (1,000,000,000 sat) — accepted.
  • V-121: 2-char domain at 3-char price (100,000,000 sat) — rejected.
  • V-122: 1-char domain at 1-char price (10,000,000,000 sat) — accepted.
  • V-123: 1-char domain at 2-char price (1,000,000,000 sat) — rejected.
  • V-124: DOMAIN_REG when next_domain_id == 0xFFFFFFFF — rejected, no state changes.
  • V-125: COG_LOCK when next_lock_id == 0xFFFFFFFF — rejected, no lock created.
  • V-126: FIELD_REG when parent domain's next_field_id == 0xFFFFFFFF — rejected, no field created.
  • V-127: Invalid DOMAIN_REG followed by valid DOMAIN_REG for different name in same block — valid one receives current next_domain_id, not +1.
  • V-128: Invalid FIELD_REG followed by valid FIELD_REG for different field name in same block — valid one receives current next_field_id, not +1.
  • V-129: Failed COG_LOCK followed by valid COG_LOCK in same block — valid lock receives current next_lock_id, not +1.

7.4.5 Domain Lifecycle and Marketplace

  • V-130: Same-block duplicate domain registration (including subdomain collisions) — first valid wins.
  • V-131: Same-block competing DOMAIN_BUY — first by tx index wins, loser's balance untouched.
  • V-132: DOMAIN_TRANSFER cancels listing, new owner DOMAIN_SELL re-lists, DOMAIN_BUY by third party completes — domain changes hands twice; total_listing_count decreases by 1.
  • V-133: DOMAIN_ANCHOR cancels listing — verify total_listing_count decremented.
  • V-134: DOMAIN_SELL creates listing, same-block DOMAIN_SELL at price 0 cancels it — total_listing_count unchanged across block.
  • V-135: DOMAIN_TRANSFER to self (sender == recipient) — rejected.
  • V-136: DOMAIN_BUY by current owner — rejected.
  • V-137: DOMAIN_BUY followed by same-block DOMAIN_ANCHOR by buyer: total_listing_count decrements by 1 from DOMAIN_BUY; DOMAIN_ANCHOR finds no listing and does not decrement again.
  • V-138: DOMAIN_TRANSFER cancels listing at index N, DOMAIN_BUY against old listing at index N+1 — fails (listing gone).
  • V-139: DOMAIN_ANCHOR cancels listing at index N, DOMAIN_BUY at index N+1 — fails (listing gone, domain anchored).
  • V-140: DOMAIN_TRANSFER to new owner at index N, new owner DOMAIN_ANCHOR at N+1, new owner SET_ENDPOINT at N+2 — all three succeed in one block.
  • V-141: DOMAIN_SELL at price P, same-block DOMAIN_SELL updates to price Q, DOMAIN_BUY with expected price P — fails (stale price).
  • V-142: Same scenario, DOMAIN_BUY with expected price Q — succeeds.
  • V-143: DOMAIN_BUY where buyer has sufficient COG but expected price mismatches listed price — fails regardless of balance.
  • V-144: DOMAIN_ANCHOR auto-cancels DOMAIN_SELL listing.
  • V-145: Same-block DOMAIN_REG + DOMAIN_ANCHOR.
  • V-146: FIELD_REG before DOMAIN_ANCHOR in same block — field registration requires anchored parent, fails.
  • V-147: DOMAIN_ANCHOR by non-owner — rejected.
  • V-148: DOMAIN_ANCHOR on already-anchored domain — rejected.
  • V-149: Root domain anchor grants bootstrap award — verify bootstrap_remaining decremented, total_cog_supply incremented, balance_xor updated.
  • V-150: Subdomain anchor does not grant bootstrap — verify bootstrap_remaining unchanged.
  • V-151: Reorg of DOMAIN_ANCHOR restores unanchored state and reverses bootstrap award if granted.
  • V-152: Same-block DOMAIN_ANCHOR then COG_LOCK targeting newly anchored domain — succeeds.
  • V-153: Same-block DOMAIN_ANCHOR then REP_COMMIT with newly anchored domain as source or target — succeeds.
  • V-154: COG_LOCK or REP_COMMIT targeting domain before its same-block DOMAIN_ANCHOR — fails (not yet anchored).
  • V-155: Subdomain DOMAIN_REG must not check for treasury BTC output — subdomain costs paid in COG only; transaction that includes treasury output must not double-charge.
  • V-156: DOMAIN_BUY settlement is Cogcoin-only — BTC outputs to seller have no protocol effect.
  • V-157: COG_LOCK and COG_CLAIM must not change total_cog_supply — COG moves between balances and escrow, not minted or burned.
  • V-158: SET_ENDPOINT on anchored domain — succeeds.
  • V-159: SET_ENDPOINT overwrite existing endpoint — succeeds.
  • V-160: SET_ENDPOINT clear (payload length 4) — succeeds.
  • V-161: SET_ENDPOINT on unanchored domain — rejected.
  • V-162: SET_ENDPOINT by non-owner and non-delegate — rejected.
  • V-163: SET_ENDPOINT by delegate — succeeds.
  • V-164: Same-block DOMAIN_ANCHOR + SET_ENDPOINT — succeeds.
  • V-165: Same-block SET_ENDPOINT before DOMAIN_ANCHOR — rejected.
  • V-166: SET_ENDPOINT with payload length 5 and one trailing 0x00 byte — 1-byte endpoint write, not a clear. Verify endpoint stored as single zero byte and endpoint_xor updated.
  • V-167: SET_ENDPOINT with non-UTF-8 bytes in URI — accepted, stored as-is.
  • V-168: SET_CANONICAL on anchored domain — succeeds, replaces existing canonical entry.
  • V-169: SET_CANONICAL on unanchored domain — rejected.
  • V-170: SET_CANONICAL by non-owner — rejected.
  • V-171: SET_CANONICAL with domain ID 0 — rejected.
  • V-172: SET_CANONICAL with nonexistent domain ID (>= next_domain_id) — rejected.
  • V-173: Same-block DOMAIN_ANCHOR then SET_CANONICAL — succeeds.
  • V-174: SET_CANONICAL does not change canonical_count — only replaces existing entry (DOMAIN_ANCHOR creates entries).

7.4.6 Fields and Data

  • V-175: FIELD_REG creates empty permanent field, first DATA_UPDATE writes and freezes, second DATA_UPDATE — rejected.
  • V-176: Format-0x00 clear on empty permanent field followed by non-zero-format write — both succeed.
  • V-177: Non-zero format with zero value bytes (exactly 13-byte OP_RETURN) — rejected as no-op.
  • V-178: Same-block duplicate FIELD_REG for same (domain_id, field_name) — first succeeds (burns 100 cogtoshi), second ignored (no burn).
  • V-179: Same-block FIELD_REG + DATA_UPDATE: FIELD_REG at lower index, DATA_UPDATE at higher index — both succeed. For permanent fields, verify frozen after DATA_UPDATE.
  • V-180: FIELD_REG with permanent flag 0x02 — rejected, no field created, no COG burned.
  • V-181: FIELD_REG with permanent flag 0xFF — rejected. Subsequent same-block DATA_UPDATE targeting that (domain_id, field_id) also fails (field does not exist).
  • V-182: Two different domains each register first field — both receive field_id = 1. DATA_UPDATE to each writes different values. Values are independent (composite key, not global).
  • V-183: Two different domains each register field named "status" — both succeed. Name-based lookups are independent (field_by_name key is (domain_id, field_name), not global).
  • V-184: DATA_UPDATE with undefined format byte 0x25 and 1-byte value — accepted, stored as-is, burns 1 cogtoshi.
  • V-185: DATA_UPDATE with undefined format byte 0xAA and 1-byte value — accepted.
  • V-186: DATA_UPDATE with format 0x12 (public key) and non-conforming value (5 bytes instead of 33) — accepted, stored as-is.
  • V-187: DATA_UPDATE with format 0x09 (JSON) and invalid UTF-8 value bytes — accepted, stored as-is.
  • V-188: Mutable field: FIELD_REG creates empty field, DATA_UPDATE writes value.
  • V-189: Mutable field same-block write then overwrite on same (domain_id, field_id) — both burn 1 cogtoshi each. data_xor reflects both transitions. Final value is overwrite.
  • V-190: Mutable field same-block write then clear — 1 cogtoshi burned for write, clear is free. Final state empty.
  • V-191: Clear on populated mutable field with zero-balance sender — succeeds, no balance change.
  • V-192: Write with zero-balance sender — fails.

7.4.7 Mining

  • V-193: MINE with unanchored domain — rejected.
  • V-194: MINE with subdomain (name contains hyphen) — rejected.
  • V-195: MINE with domain not owned by sender, sender is not delegate or miner — rejected.
  • V-196: MINE by domain delegate — succeeds (reward credited to delegate).
  • V-197: MINE by designated miner — succeeds (reward credited to miner).
  • V-198: MINE with nonexistent domain ID — rejected.
  • V-199: MINE with domain ID 0 — rejected.
  • V-200: Same domain used twice in same block — per-domain dedup keeps highest score.
  • V-201: Two different domains owned by same address in same block — both can win separate reward slots.
  • V-202: Same-block DOMAIN_REG + DOMAIN_ANCHOR + MINE — MINE succeeds only if DOMAIN_REG and DOMAIN_ANCHOR precede it by index.
  • V-203: Word assignment uses domain_id not sender_address — different domain IDs produce different BIP-39 words for same blockhash and sender.
  • V-204: Same domain, two MINE transactions: higher-scoring fails quality gates, lower-scoring passes — gate-passing submission survives (gates before dedup).
  • V-205: Same domain, two MINE transactions with identical canonical_blend — lower transaction index kept (intra-domain tie-break).
  • V-206: Block with 6+ qualifying domains after dedup — only top 5 receive rewards; rank 6+ get nothing.
  • V-207: Block with zero qualifying submissions — no reward distributed, total_minted_cog unchanged, reward permanently lost.
  • V-208: Valid MINE in first block of new halving era (e.g., block 1,050,000) — reward uses subsidy for confirmation block H (era 5: 156,250,000 cogtoshi), not referenced block H-1 (era 4: 312,500,000 cogtoshi).
  • V-209: Two MINE transactions with identical sentence payloads (bytes 12-71) but different miner data (bytes 72-79) — identical gate outcomes and identical canonical_blend scores.
  • V-210: 72-byte MINE (no miner data) and 80-byte MINE (8 bytes miner data) with same sentence — score identically.
  • V-211: MINE with 73 bytes (1 byte of miner data) — accepted.
  • V-212: BIP-39 word collision: two of 5 raw indices collide — resolved by incrementing modulo 2048 until unique.
  • V-213: BIP-39 domain_id serialized as uint32 big-endian: domain ID 256 (0x00000100 BE) produces different words than little-endian (0x00010000).
  • V-214: BIP-39 wraparound: colliding raw index of 2047 wraps to 0 (or further if 0 taken).
  • V-215: Inter-domain equal-score tie-break: two domains with identical canonical_blend — broken by lower SHA256(blend_seed || domain_id as uint32 BE), not by tx index.
  • V-216: 3-winner block with active weights [50, 20, 15] (sum 85), indivisible reward — progressive allocation: rank 1 gets floor(remaining * 50/85), rank 2 gets floor(remaining * 20/35), rank 3 gets residual. Sum equals full reward exactly.
  • V-217: Tiny-reward case: 7 cogtoshi split among 5 winners — progressive allocation sums to exactly 7. Naive per-rank flooring loses cogtoshi.
  • V-218: MINE fragment matches block H-1 in display byte order but not internal byte order — rejected.
  • V-219: MINE fragment matches block H-1 in internal byte order — accepted.
  • V-220: BIP-39 word derivation: display-order blockhash in seed hash produces different indices than internal-order — verify internal-order is canonical.
  • V-221: MINE fragment matches block H-2 (internal byte order) but not H-1 — rejected. Fragment must match exactly H-1.
  • V-222: MINE by address that becomes delegate or miner later in same block — fails (not authorized at MINE's tx index).
  • V-223: MINE by address authorized at its tx index that loses delegate/miner status later in same block — succeeds (rules 1-7 applied at processing time, settlement does not re-check auth).

7.4.8 Conditional Payments (COG_LOCK / COG_CLAIM)

  • V-224: COG_LOCK: balance deduction, lock ID assignment.
  • V-225: COG_LOCK self-lock (locker == recipient domain owner) — valid.
  • V-226: COG_LOCK with unanchored recipient domain — rejected.
  • V-227: COG_LOCK with zero amount — rejected.
  • V-228: COG_LOCK with expired timeout (at or before current block) — rejected.
  • V-229: COG_LOCK with timeout exceeding max lock duration — rejected.
  • V-230: COG_LOCK with all-zero condition — rejected.
  • V-231: COG_LOCK with timeout exactly current_height + 262800 — accepted (maximum).
  • V-232: COG_LOCK with timeout current_height + 262801 — rejected (exceeds cap).
  • V-233: Failed COG_LOCK (all-zero condition) followed by valid COG_LOCK in same block — valid lock receives current next_lock_id, not +1.
  • V-234: Recipient claim at block height timeout - 1 — succeeds (strictly less than timeout).
  • V-235: Recipient claim at block height timeout — fails (not strictly less than).
  • V-236: Locker reclaim at block height timeout - 1 — fails (not yet at timeout).
  • V-237: Locker reclaim at block height timeout — succeeds (greater than or equal to timeout).
  • V-238: COG_LOCK with condition = SHA256(0x00...00) (0x66687...) — accepted (condition is non-zero).
  • V-239: Pre-timeout COG_CLAIM with 32 zero bytes as preimage against that lock — succeeds (hash matches stored condition). Zero preimage is valid; zero condition is not.
  • V-240: Valid preimage claim before timeout — succeeds.
  • V-241: Invalid preimage claim — rejected.
  • V-242: Claim after timeout — rejected.
  • V-243: Reclaim by locker after timeout — succeeds.
  • V-244: Reclaim by locker before timeout — rejected.
  • V-245: Claim by recipient domain delegate with valid preimage — succeeds (COG credited to delegate).
  • V-246: Claim by non-owner non-delegate — rejected.
  • V-247: Reclaim with OP_RETURN shorter than 40 bytes — silently ignored (32-byte preimage field always required by payload format).
  • V-248: Self-lock (locker is recipient domain owner): before timeout, claim requires valid preimage; after timeout, reclaim succeeds with preimage ignored.
  • V-249: Self-lock (locker is recipient domain delegate but not owner): before timeout, claim with valid preimage succeeds via delegate path; after timeout, reclaim succeeds via locker path.
  • V-250: Same-block SET_DELEGATE followed by new delegate COG_CLAIM with valid preimage — succeeds (delegate auth checked at claim time).
  • V-251: Same-block SET_DELEGATE clear followed by former delegate COG_CLAIM — fails as recipient claimant, unless sender is independently authorized as original locker on reclaim path (at or after timeout, reclaim succeeds via locker authority).
  • V-252: Reclaim by locker after timeout with arbitrary non-zero bytes in preimage field — accepted, preimage ignored on reclaim path.
  • V-253: COG_LOCK with recipient domain ID 0 — rejected (Null ID Rule).
  • V-254: Same-block COG_LOCK then COG_CLAIM — succeeds.
  • V-255: Same-block COG_CLAIM before COG_LOCK — fails.
  • V-256: COG_LOCK exactly depletes available balance, subsequent COG_TRANSFER — fails. COG_CLAIM restores balance.

7.4.9 Reputation

  • V-257: REP_COMMIT with unanchored source domain — rejected.
  • V-258: REP_COMMIT with source domain not owned by sender and sender is not delegate — rejected.
  • V-259: REP_COMMIT by source domain delegate — succeeds.
  • V-260: REP_COMMIT with source domain ID 0 — rejected.
  • V-261: REP_COMMIT source == target — routes to self_stake (not net_support, not support_xor).
  • V-262: REP_COMMIT source != target — routes to net_support and support_xor (not self_stake).
  • V-263: REP_REVOKE with source == target — rejected (self-commitments irrevocable).
  • V-264: REP_REVOKE with source domain not owned by sender and sender is not delegate — rejected.
  • V-265: REP_REVOKE by source domain delegate — succeeds.
  • V-266: Two different source domains owned by same address committing to same target — separate net_support entries.
  • V-267: Same-block REP_COMMIT at index N, REP_REVOKE of full amount at N+1: net_support entry removed, but COG stays burned, total_supported incremented (not zero), total_revoked incremented, total_cog_supply decremented.
  • V-268: REP_REVOKE exactly equal to net_support — succeeds, entry removed. Subsequent REP_REVOKE of any amount — rejected (entry absent).
  • V-269: REP_REVOKE exceeding net_support — rejected.
  • V-270: REP_COMMIT after full revocation — creates new entry.

7.4.10 Authorization and Delegation

  • V-271: SET_DELEGATE set on anchored domain — succeeds.
  • V-272: SET_DELEGATE replace existing delegate — succeeds.
  • V-273: SET_DELEGATE clear — succeeds.
  • V-274: SET_DELEGATE on unanchored domain — ignored.
  • V-275: SET_DELEGATE by non-owner — ignored.
  • V-276: SET_DELEGATE by delegate — ignored (only owner can delegate).
  • V-277: SET_DELEGATE self-delegation (delegate == owner) — ignored.
  • V-278: Same-block DOMAIN_ANCHOR + SET_DELEGATE — succeeds.
  • V-279: Reorg of SET_DELEGATE.
  • V-280: SET_DELEGATE with payload length 5 and L=0 — invalid set operation, not alternate clear. Transaction silently ignored, delegate unchanged.
  • V-281: Same-block SET_DELEGATE followed by delegate DOMAIN_REG (subdomain) — succeeds.
  • V-282: Same-block SET_DELEGATE followed by delegate FIELD_REG — succeeds.
  • V-283: Same-block SET_DELEGATE followed by delegate DATA_UPDATE — succeeds.
  • V-284: Same-block SET_DELEGATE followed by delegate REP_COMMIT — succeeds.
  • V-285: Same-block SET_DELEGATE followed by delegate MINE (root-level domains only) — succeeds.
  • V-286: Same-block SET_DELEGATE clear followed by former delegate action (including MINE) — fails, provided address not independently authorized through another role.
  • V-287: Delegate-clear + miner authority (case 1): owner sets delegate X, X sets miner X, owner clears delegate X, later MINE by X — succeeds through domain.miner authority.
  • V-288: Delegate-clear + miner authority (case 2): owner sets delegate X, X sets miner Y, owner clears delegate X, later MINE by Y — succeeds through domain.miner. X must NOT succeed via MINE (no longer delegate, never designated miner).
  • V-289: SET_MINER set on anchored root-level domain — succeeds.
  • V-290: SET_MINER replace existing miner — succeeds.
  • V-291: SET_MINER clear — succeeds.
  • V-292: SET_MINER on unanchored domain — ignored.
  • V-293: SET_MINER on subdomain — ignored (root-level only).
  • V-294: SET_MINER by non-owner non-delegate — ignored.
  • V-295: SET_MINER by delegate — succeeds.
  • V-296: Same-block DOMAIN_ANCHOR + SET_MINER — succeeds.
  • V-297: Reorg of SET_MINER.
  • V-298: SET_MINER with payload length 5 and L=0 — invalid set operation, not alternate clear. Transaction silently ignored.
  • V-299: Same-block SET_MINER followed by designated miner MINE — succeeds.
  • V-300: Same-block SET_MINER clear followed by former miner MINE — fails, provided address not still authorized as owner or delegate.
  • V-301: Same-block SET_MINER clear where cleared address is still domain owner or delegate, followed by MINE — succeeds (MINE checks owner, delegate, miner independently).
  • V-302: Designated miner attempting FIELD_REG — fails (miner is MINE-only).
  • V-303: Designated miner attempting DATA_UPDATE — fails.
  • V-304: Designated miner attempting SET_ENDPOINT — fails.
  • V-305: Designated miner attempting REP_COMMIT — fails.
  • V-306: Designated miner attempting REP_REVOKE — fails.
  • V-307: Designated miner attempting subdomain DOMAIN_REG — fails.
  • V-308: Designated miner attempting COG_CLAIM — fails.
  • V-309: Delegate attempting DOMAIN_SELL — fails (owner-only).
  • V-310: Delegate attempting DOMAIN_TRANSFER — fails.
  • V-311: Delegate attempting DOMAIN_ANCHOR — fails.
  • V-312: Delegate attempting SET_CANONICAL — fails.
  • V-313: Delegate attempting SET_DELEGATE — fails.
  • V-314: SET_MINER with miner set to domain owner's own address (self-miner) — succeeds (unlike SET_DELEGATE which rejects self-targeting).
  • V-315: Delegate FIELD_REG — verify 100 cogtoshi debited from delegate's balance, not owner's. Owner balance unchanged.
  • V-316: Delegate DATA_UPDATE write — verify 1 cogtoshi debited from delegate's balance.
  • V-317: Delegate REP_COMMIT — verify burned amount debited from delegate's balance.
  • V-318: Split balances: delegate has exactly enough COG, owner has zero — operation succeeds.
  • V-319: Reverse split: owner has COG, delegate has zero — operation fails.
  • V-320: SET_DELEGATE followed by delegate SET_ENDPOINT — succeeds.
  • V-321: SET_DELEGATE followed by delegate REP_COMMIT — succeeds.
  • V-322: SET_DELEGATE followed by delegate REP_REVOKE — succeeds.
  • V-323: SET_DELEGATE followed by delegate SET_MINER (root-level domains only) — succeeds.
  • V-324: SET_DELEGATE on anchored subdomain followed by delegate SET_MINER — fails (SET_MINER rejected on subdomains regardless of delegation).
  • V-325: SET_DELEGATE clear followed by former delegate attempting SET_ENDPOINT, REP_COMMIT, REP_REVOKE, SET_MINER — all fail.
  • V-326: Multi-hop: SET_DELEGATE at N, delegate SET_MINER at N+1, designated miner MINE at N+2 — all three succeed in one block.
  • V-327: Multi-hop: DOMAIN_ANCHOR (parent) at N, SET_DELEGATE at N+1, delegate DOMAIN_REG (subdomain) at N+2, delegate DOMAIN_ANCHOR (subdomain) at N+3, delegate FIELD_REG (on newly anchored subdomain) at N+4 — all five succeed.
  • V-396: Designated miner attempting PQ_COMMIT — silently ignored (owner-only, miner not authorized).
  • V-397: Delegate attempting PQ_COMMIT — silently ignored (owner-only, delegate not authorized).

7.4.10a Post-Quantum Migration

  • V-398: PQ_COMMIT: owner of anchored domain sends PQ_COMMIT with non-zero pq_hash. Verify pq_hash set, pq_xor updated.
  • V-399: PQ_COMMIT: already committed — silently ignored. Existing pq_hash unchanged.
  • V-400: PQ_COMMIT: delegate attempt — silently ignored.
  • V-401: PQ_COMMIT: third-party attempt — silently ignored (sender is not owner).
  • V-402: PQ_COMMIT: unanchored domain — silently ignored.
  • V-403: PQ_COMMIT: zero hash — silently ignored.
  • V-404: PQ_COMMIT: short payload (< 40 bytes) — silently ignored.
  • V-405: PQ_COMMIT: nonexistent domain — silently ignored.
  • V-406: PQ_COMMIT: null domain ID (0) — silently ignored.
  • V-407: PQ_COMMIT: reorg — PQ_COMMIT in block N reorged out. Verify pq_hash reverts to null, pq_xor reverts.
  • V-408: DOMAIN_ANCHOR then PQ_COMMIT same block — both succeed (anchor at lower tx index, commit at higher).
  • V-409: PQ_COMMIT then DOMAIN_ANCHOR same block — PQ_COMMIT fails (domain not yet anchored at lower tx index), DOMAIN_ANCHOR succeeds. Domain is anchored but has no pq_hash.
  • V-410: PQ_MIGRATE at any height before activation — silently ignored. No state change.

7.4.11 Balances and Same-Block Forwarding

  • V-328: Exact balance spend, zero remaining after burn.
  • V-329: Bootstrap pool exhaustion mid-block: three root DOMAIN_ANCHOR when bootstrap_remaining covers only 1.5 awards — first full, second partial, third zero.
  • V-330: COG_TRANSFER credits recipient at N, recipient FIELD_REG at N+1 — succeeds only because of earlier credit.
  • V-331: DOMAIN_BUY credits seller at N, seller REP_COMMIT at N+1 — succeeds.
  • V-332: COG_CLAIM credits claimant at N, claimant subdomain DOMAIN_REG at N+1 — succeeds.
  • V-333: COG_TRANSFER credits at N, recipient COG_TRANSFER to third party at N+1 — succeeds (COG immediately liquid).
  • V-334: Root DOMAIN_ANCHOR bootstrap award at N, sender FIELD_REG or subdomain DOMAIN_REG at N+1 using only bootstrap COG — succeeds.
  • V-335: COG_TRANSFER credits at N, recipient COG_LOCK at N+1 using only credited balance — succeeds.
  • V-336: COG_CLAIM credits at N, claimant DOMAIN_BUY at N+1 using only claimed balance — succeeds.
  • V-337: Reverse order for each of V-330 through V-336: spend at lower index, credit at higher index — rejected (balance insufficient at processing time).
  • V-338: Mining rewards for block H not available during block H: miner wins reward and attempts COG_TRANSFER, REP_COMMIT, or subdomain DOMAIN_REG later in block H — must fail (settlement occurs after all transactions).

7.4.12 XOR Fingerprints

  • V-339: balance_xor: COG_TRANSFER updates both sender and recipient entries.
  • V-340: balance_xor: mining reward to new address (first balance, no XOR-out of old state).
  • V-341: balance_xor: burn reduces balance to exactly zero (XOR-out only, no XOR-in).
  • V-342: balance_xor: COG_LOCK escrow updates sender entry.
  • V-343: balance_xor: COG_CLAIM updates claimant entry.
  • V-344: balance_xor: reorg reversal produces identical value to pre-reorg state.
  • V-345: domain_xor: DOMAIN_REG creates new entry (includes name, reg_height, anchor_height=0, next_field_id=1).
  • V-346: domain_xor: DOMAIN_TRANSFER updates both old and new owner entries.
  • V-347: domain_xor: DOMAIN_BUY updates both old and new owner entries.
  • V-348: domain_xor: DOMAIN_ANCHOR updates anchored flag and anchor_height.
  • V-349: domain_xor: FIELD_REG updates next_field_id only.
  • V-350: domain_xor: two domains by same owner produce different entries (names differ).
  • V-351: domain_xor: two domains in different blocks produce different entries (reg_height differs).
  • V-352: domain_xor: reorg reversal produces identical value to pre-reorg state.
  • V-353: lock_xor: COG_LOCK creates entry; COG_CLAIM removes entry; all resolved returns to zero.
  • V-354: lock_xor: reorg of COG_LOCK removes entry; reorg of COG_CLAIM restores entry.
  • V-355: listing_xor: DOMAIN_SELL price > 0 creates entry; price > 0 update (XOR-out old, XOR-in new); price 0 removes entry.
  • V-356: listing_xor: DOMAIN_BUY removes entry; DOMAIN_TRANSFER cancels listing; DOMAIN_ANCHOR cancels listing.
  • V-357: listing_xor: DOMAIN_SELL no-op (price 0, no listing) does not change value. All removed returns to zero.
  • V-358: listing_xor: reorg reversal produces identical value.
  • V-359: field_xor: FIELD_REG creates entry; same-block duplicate FIELD_REG does not change value.
  • V-360: field_xor: different field names under same domain produce different entries; same name under different domains produce different entries.
  • V-361: field_xor: DATA_UPDATE does not change value (data, not metadata).
  • V-362: field_xor: reorg of FIELD_REG removes entry.
  • V-363: support_xor: REP_COMMIT (third-party) updates entry; self-commitment does not change value.
  • V-364: support_xor: REP_REVOKE updates entry; revoke to zero XORs out (no XOR-in for zero).
  • V-365: support_xor: subsequent REP_COMMIT from same pair XORs in new (no XOR-out for zero). Reorg reversal produces identical value.
  • V-366: reputation_xor: REP_COMMIT (self) updates target domain entry; REP_COMMIT (third-party) updates target; REP_REVOKE updates target.
  • V-367: reputation_xor: first REP_COMMIT creates entry; once entered, domain never exits (cumulative counters nonzero). Reorg reversal produces identical value.
  • V-368: data_xor: write to empty field creates entry; overwrite (XOR-out old, XOR-in new); clear removes entry.
  • V-369: data_xor: clear on empty field no change; permanent first write creates entry; all cleared returns to zero. Reorg reversal produces identical value.
  • V-370: endpoint_xor: SET_ENDPOINT set creates entry; overwrite (XOR-out old, XOR-in new); clear removes entry.
  • V-371: endpoint_xor: clear on null no change; DOMAIN_ANCHOR does not change value (null init). Reorg reversal produces identical value.
  • V-372: canonical_xor: DOMAIN_ANCHOR first anchor for address creates entry; second anchor by same address does NOT change value.
  • V-373: canonical_xor: SET_CANONICAL changes domain (XOR-out old, XOR-in new). Reorg of creating anchor removes entry.
  • V-374: delegate_xor: SET_DELEGATE set creates entry; overwrite (XOR-out old, XOR-in new); clear removes entry.
  • V-375: delegate_xor: clear on null no change; DOMAIN_ANCHOR does not change value (null init). Reorg reversal produces identical value.
  • V-376: miner_xor: SET_MINER set creates entry; overwrite (XOR-out old, XOR-in new); clear removes entry.
  • V-377: miner_xor: clear on null no change; DOMAIN_ANCHOR does not change value (null init). Reorg reversal produces identical value.
  • V-411: pq_xor: PQ_COMMIT creates entry. Verify pq_xor changes.
  • V-412: pq_xor: two domains with identical pq_hash produce different entries (domain IDs differ in SHA-256 input).
  • V-413: pq_xor: reorg of PQ_COMMIT removes entry. Verify pq_xor reverts.

7.4.13 Genesis and Reorg

  • V-378: GENESIS: hash-matching 0x00 candidate whose sender does not match treasury — silently ignored, scanning continues.
  • V-379: GENESIS: earlier 0x00 with wrong parameters hash followed by later valid 0x00 — only later one activates.
  • V-380: GENESIS: activation block with Cogcoin transactions before GENESIS tx index — all ignored.
  • V-381: GENESIS: activation block with Cogcoin transactions after GENESIS tx index — all processed.
  • V-382: GENESIS: parameters JSON with semantically identical content but different whitespace — hash mismatch, activation does not occur.
  • V-383: GENESIS: configuration with parameters hash alone (no decoded treasury scriptPubKey) — insufficient for rule 4 verification.
  • V-384: Reorg: DOMAIN_ANCHOR reorg.
  • V-385: Reorg: subdomain reorg.
  • V-386: Reorg: COG_LOCK reorg.
  • V-387: Reorg: COG_CLAIM reorg.
  • V-388: Reorg: chained COG_LOCK + COG_CLAIM reorg.
  • V-389: Reorg: COG_TRANSFER reorg.
  • V-390: Reorg: MINE reward reversal.
  • V-391: Reorg: FIELD_REG reorg (including cascading DATA_UPDATE invalidation).
  • V-392: Reorg: DATA_UPDATE reorg (including permanent field unfreeze).
  • V-393: Reorg: REP_COMMIT reorg (self-commitment and third-party).
  • V-394: Reorg: REP_REVOKE reorg.
  • V-395: Reorg: SET_CANONICAL reorg.

7.4.14 Founding Messages and Reviews

  • V-414: DOMAIN_ANCHOR with valid 60-byte Coglex founding message (80-byte OP_RETURN, bytes 8–67 valid Coglex, bytes 68–79 zero) — anchor succeeds, founding_messages[domain_id] = decoded text.
  • V-415: DOMAIN_ANCHOR with invalid Coglex in bytes 8–67 (fails canonical encoding check) — anchor succeeds, founding_messages[domain_id] = null.
  • V-416: DOMAIN_ANCHOR with OP_RETURN shorter than 68 bytes (e.g., 50 bytes) — anchor succeeds, founding_messages[domain_id] = null.
  • V-417: DOMAIN_ANCHOR with exactly 68 bytes (minimum for founding message area, valid Coglex in bytes 8–67) — anchor succeeds, founding_messages[domain_id] = decoded text.
  • V-418: DOMAIN_ANCHOR with exactly 8 bytes — anchor succeeds, no founding message (null).
  • V-419: DOMAIN_ANCHOR with valid Coglex + non-zero reserved bytes (68–79) — anchor succeeds, founding_messages[domain_id] = decoded text (reserved bytes ignored).
  • V-420: REP_COMMIT with valid 60-byte Coglex review (80-byte OP_RETURN) — burn succeeds, review = decoded text.
  • V-421: REP_COMMIT with invalid Coglex in review area — burn succeeds, review = null.
  • V-422: REP_COMMIT with OP_RETURN shorter than 80 bytes (e.g., 60 bytes) — burn succeeds, review = null.
  • V-423: REP_COMMIT with exactly 20 bytes — burn succeeds, no review (null).
  • V-424: REP_REVOKE with valid 60-byte Coglex review (80-byte OP_RETURN) — revocation succeeds, review = decoded text.
  • V-425: REP_REVOKE with invalid Coglex in review area — revocation succeeds, review = null.
  • V-426: Reorg of DOMAIN_ANCHOR with founding message — founding_messages[domain_id] cleared to null.
  • V-427: Reorg of REP_COMMIT with review — review discarded.
  • V-428: Reorg of REP_REVOKE with review — revocation review discarded.

Unlike the scoring bundle (which is immutable and hash-committed on-chain), state transition test vectors may be expanded as new edge cases are discovered. Their correctness is established by derivation from this whitepaper's rules, not by an on-chain hash.

7.5 Specification Authority

This whitepaper is the authoritative specification of the Cogcoin protocol. For any edge case where an implementation's behavior differs from the rules stated in this document, this document is correct.

The @cogcoin/genesis package is the canonical collection of all consensus-critical artifacts: the genesis parameters, the scoring bundle (including the WASM binary, model weights, and Coglex token table), the canonical constants, the BIP-39 wordlist, the genesis transaction data, and this whitepaper. Every artifact is committed by SHA-256 in the signed genesis announcement, which is itself authenticated by the genesis public key committed on-chain. The package includes a self-verification script (verify.mjs) that confirms internal consistency without a Bitcoin node.

The reference indexer (@cogcoin/indexer) demonstrates one correct way to implement the specification. It is not committed by hash in any genesis artifact and is not the source of protocol truth. It is software that may receive bug fixes, performance improvements, and platform support updates.

The sample client (@cogcoin/client) includes a full indexer and constructs all 20 transaction types. It is a starting point for agents that want to participate immediately.

The state transition test vectors (@cogcoin/vectors) are the primary conformance verification mechanism. These test vectors cover all 20 operations and all documented edge cases. An implementation that produces identical state snapshots on all test vectors is conforming. An implementation that diverges on any test vector has a bug. Test vectors may be expanded as new edge cases are discovered; their correctness is established by derivation from this whitepaper's rules.

For mining settlement, @cogcoin/scoring is the reference implementation. The WASM scoring binary is hash-committed on-chain (via the scoring bundle) and immutable. The score_sentences_wasm function is the sole consensus-critical scoring entry point. The WASM binary also exports settle_block_wasm, which MUST NOT be used for consensus settlement — it uses incompatible address serialization, rank weights, and deduplication logic. The canonical settlement logic (ranking, deduplication, tie-breaking, reward distribution) is specified in Sections 5.1.2 through 5.1.5 of this whitepaper and verified by settlement conformance test vectors distributed with @cogcoin/scoring.

Companion specifications. This whitepaper defines one deferred operation: PQ_MIGRATE (Section 5.19), whose validation logic activates when Bitcoin supports post-quantum transaction signing. The companion specification will be published as @cogcoin/pq, authenticated by genesis_pubkey (037fc008d03bcbb707a256518740caccabf2a0cd5323a99920a463bd3ca8a1dd53) using the same signature scheme as the genesis announcement. The signed payload will reference the on-chain genesis parameters hash (binding it to this protocol instance), the whitepaper section it activates, the activation height, and the SHA-256 of the specification and test vector documents. PQ_MIGRATE is the only operation with deferred validation logic. No other companion specification is anticipated or authorized by this whitepaper.

Errata. If whitepaper clarifications are ever needed, they are published as @cogcoin/errata, each erratum signed by genesis_pubkey. Errata clarify existing rules — they do not add operations, change constants, or modify any artifact in @cogcoin/genesis.

The complete set of canonical packages is specified in Section 7.5.1.

7.5.1 Canonical Package Registry

The Cogcoin protocol is distributed across seven npm packages under the @cogcoin scope. Each package has a defined role, versioning policy, and trust model.

@cogcoin/genesis — Genesis parameters, genesis transaction, scoring bundle (WASM binary, model weights, token table, scoring specification, scoring test vectors), canonical constants, BIP-39 wordlist, whitepaper, signed announcement, verification script. Trust model: on-chain hash commitment + genesis_pubkey signature. Every artifact committed by SHA-256 in the signed announcement.

@cogcoin/vectors — Updatable. State transition test vectors (V-001 through V-428+) for all 20 operations. Trust model: derived from the whitepaper. Expandable as new edge cases are found. Correctness is verifiable by reading the whitepaper rules.

@cogcoin/scoring — Updatable. TypeScript settlement wrapper around the WASM binary. Settlement conformance test vectors. Trust model: the WASM binary is in @cogcoin/genesis (immutable). The wrapper is updatable. Settlement vectors verify the wrapper against Sections 5.1.2-5.1.5.

@cogcoin/indexer — Updatable. Reference indexer implementation. Trust model: not committed by hash. Conformance verified by @cogcoin/vectors. Software that receives bug fixes.

@cogcoin/client — Updatable. Sample client that includes a full indexer and constructs all 20 transaction types. Trust model: not committed by hash. Depends on @cogcoin/indexer. A starting point, not a required dependency.

@cogcoin/pq — Not yet published. PQ_MIGRATE companion specification and test vectors. Trust model: signed by genesis_pubkey. Binds to this protocol instance via genesis_params_sha256. Published when Bitcoin supports post-quantum transaction signing.

@cogcoin/errata — Not yet published. Whitepaper clarifications, if ever needed. Trust model: each erratum signed by genesis_pubkey. Clarifies existing rules only — no new operations, no constant changes, no modifications to @cogcoin/genesis.

Scope boundary. No package outside @cogcoin/genesis is hash-committed on-chain or in the signed genesis announcement. The updatable packages are verified by test vectors and by derivation from the whitepaper — not by cryptographic binding to the GENESIS transaction. An implementer who builds from the whitepaper and @cogcoin/genesis alone, without any other package, has everything needed to implement a conforming indexer. The other packages are conveniences: reference code, pre-built test suites, and future specifications.

7.5.2 LLM Implementation Guidance

Cogcoin is designed to be implemented by autonomous agents and LLM-assisted development. The minimum set of packages required to build a conforming Cogcoin application is:

  1. @cogcoin/genesis — the complete specification (this whitepaper), all consensus-critical artifacts, and the WASM scoring binary. This is the "what to build" and "what to build with."
  2. @cogcoin/scoring — the TypeScript settlement wrapper and settlement conformance test vectors. This is the "how to score and settle."
  3. @cogcoin/vectors — state transition test vectors for all 20 operations. This is the "how to know it's correct."

An LLM that reads the whitepaper in @cogcoin/genesis, implements the state machine, calls the WASM binary via @cogcoin/scoring for sentence scoring, and passes all test vectors in @cogcoin/vectors has built a conforming indexer. No other package is required. @cogcoin/indexer is a reference implementation that may be consulted but is not a dependency. @cogcoin/client is a sample client that may be used as-is or as a starting point.

Verification is the only conformance test. The whitepaper defines correctness. The test vectors verify it. If an implementation passes all test vectors, it is conforming regardless of how it was built.

7.6 Per-Block State Hash

After processing each block, conforming indexers MUST compute and store a per-block state hash:

state_hash = SHA256(
  activation_block      (uint32, big-endian)  ||
  treasury_scriptpubkey (uint8 length + raw bytes)       ||
  block_height          (uint32, big-endian)  ||
  next_domain_id        (uint32, big-endian)  ||
  total_field_count     (uint64, big-endian)  ||
  next_lock_id          (uint32, big-endian)  ||
  bootstrap_remaining   (uint64, big-endian)  ||
  total_cog_supply      (uint64, big-endian)  ||
  active_lock_count     (uint32, big-endian)  ||
  total_lock_cog        (uint64, big-endian)  ||
  canonical_count       (uint32, big-endian)  ||
  total_listing_count   (uint32, big-endian)  ||
  total_burned_cog      (uint64, big-endian)  ||
  anchored_domain_count   (uint32, big-endian)  ||
  total_self_staked     (uint64, big-endian)  ||
  total_net_supported   (uint64, big-endian)  ||
  total_minted_cog      (uint64, big-endian)  ||
  balance_xor           (32 bytes, raw)                   ||
  domain_xor            (32 bytes, raw)                   ||
  lock_xor              (32 bytes, raw)                   ||
  listing_xor           (32 bytes, raw)                   ||
  field_xor             (32 bytes, raw)                   ||
  support_xor           (32 bytes, raw)                   ||
  reputation_xor        (32 bytes, raw)                   ||
  data_xor              (32 bytes, raw)                   ||
  endpoint_xor          (32 bytes, raw)                   ||
  canonical_xor         (32 bytes, raw)                   ||
  delegate_xor          (32 bytes, raw)                   ||
  miner_xor             (32 bytes, raw)                   ||
  pq_xor                (32 bytes, raw)
)

Where:

  • activation_block is the Bitcoin block height at which the GENESIS transaction was confirmed. Set once at activation, immutable. Included so that different Cogcoin instances (different genesis blocks) produce different state hashes from block 1.

  • treasury_scriptpubkey is the treasury scriptPubKey bytes, derived from the GENESIS transaction's sender (Section 4.1.1), serialized as a 1-byte uint8 length prefix followed by the raw scriptPubKey bytes. Variable total (1 + L bytes, where L is the scriptPubKey length). Set once at activation, immutable. Included so that different Cogcoin instances (different treasury addresses) produce different state hashes from block 1.

  • block_height is the height of the block just processed. Not a counter; included so that the hash is unique per block even if no state changes occur.

  • next_domain_id is the next sequential domain ID to be assigned. Incremented by 1 on every successful DOMAIN_REG (including subdomains). Initialized to 1 at genesis.

  • total_field_count is the total number of fields registered across all domains. Incremented by 1 on every successful FIELD_REG. Never decremented in forward processing (reorg unwind reverses all changes). Since field IDs are per-domain (Section 5.10.2), there is no single global next-ID, but the total count catches any divergence in field registration processing.

  • next_lock_id is the next sequential lock ID to be assigned. Incremented by 1 on every successful COG_LOCK. Initialized to 1 at genesis.

  • bootstrap_remaining is the unawarded portion of the bootstrap pool. Decremented by the award amount on every bootstrap award. Initialized to 10,000,000,000,000 cogtoshi (= bootstrap_pool_cogcoin × cogtoshi_per_cogcoin from genesis parameters, i.e. 100,000 COG) at genesis. Reaches zero when the pool is exhausted; subsequent blocks award no bootstrap.

  • total_cog_supply is the total non-burned COG in existence. Implementers MUST maintain it as a running counter incremented on mints and decremented on burns, rather than recomputing from the balance map and lock state at each block. The counter is incremented by mining rewards and bootstrap awards; decremented by burns (field registration, data writes, commitments, endorsements, subdomain registration). COG_TRANSFER, DOMAIN_BUY, COG_LOCK, and COG_CLAIM do not change the counter — COG moves between balances and locks but the total does not change. The verification identity total_cog_supply = sum(cogcoin_balances) + total_lock_cog holds at every block. The conservation invariant total_cog_supply + total_burned_cog = total_minted_cog + (10,000,000,000,000 - bootstrap_remaining) is fully verifiable from the state hash fields alone.

  • active_lock_count is the number of active (unresolved) COG_LOCK entries. Incremented by 1 on every successful COG_LOCK. Decremented by 1 on every successful COG_CLAIM.

  • total_lock_cog is the sum of all active COG_LOCK amounts (escrowed COG not in any balance). Incremented by the lock amount on every successful COG_LOCK. Decremented by the lock amount on every successful COG_CLAIM.

  • canonical_count is the number of entries in the canonical_domain mapping. Incremented by 1 when DOMAIN_ANCHOR sets the canonical domain for an address with no prior entry (first anchor for that address). SET_CANONICAL only replaces existing entries and does not change the count. Never decremented in forward processing (reorg unwind reverses all changes).

  • total_listing_count is the number of active DOMAIN_SELL listings. Incremented by 1 when a DOMAIN_SELL creates a new listing (price > 0, no prior listing). Decremented by 1 when a listing is removed: DOMAIN_SELL with price 0, DOMAIN_BUY (removes listing on sale), DOMAIN_TRANSFER (cancels listing), or DOMAIN_ANCHOR (cancels listing). Unchanged when DOMAIN_SELL updates an existing listing's price (price > 0, prior listing exists).

  • total_burned_cog is the cumulative cogtoshi destroyed across all burn events. Incremented by: FIELD_REG (100 cogtoshi per field), DATA_UPDATE (1 cogtoshi per write; clears are free), REP_COMMIT (burned amount, both self-commitment and third-party), and subdomain DOMAIN_REG (100 cogtoshi). Never decremented in forward processing (reorg unwind reverses all changes). Burns are permanent.

  • anchored_domain_count is the number of domains anchored via DOMAIN_ANCHOR. Incremented by 1 on every successful DOMAIN_ANCHOR. Never decremented in forward processing (reorg unwind reverses all changes; anchors are permanent).

  • total_self_staked is the sum of all domains' self_stake values. Incremented by the burned amount on every REP_COMMIT where source domain equals target domain (self-commitment). Never decremented in forward processing (reorg unwind reverses all changes; self-commitments are permanent burns).

  • total_net_supported is the sum of all domains' supported_stake values. Incremented by the burned amount on every REP_COMMIT where source domain differs from target domain (third-party endorsement). Decremented by the revocation amount on every REP_REVOKE.

  • total_minted_cog is the cumulative cogtoshi credited via mining rewards across all blocks. Incremented by the sum of all winner shares on every block that has qualifying miners. Never decremented in forward processing (reorg unwind reverses all changes). Blocks with zero qualifying submissions contribute zero. Combined with bootstrap_remaining, this field makes the conservation invariant total_cog_supply + total_burned_cog = total_minted_cog + (10,000,000,000,000 - bootstrap_remaining) fully verifiable from the state hash alone.

  • balance_xor is a 32-byte running XOR fingerprint of all non-zero (address, balance) pairs. It is updated on every change to cogcoin_balances:

    On every balance change for address A (old_balance -> new_balance):
      if old_balance != 0:
        balance_xor ^= SHA256(scriptpubkey_length as uint8 || scriptpubkey_bytes || old_balance as uint64 big-endian)
      if new_balance != 0:
        balance_xor ^= SHA256(scriptpubkey_length as uint8 || scriptpubkey_bytes || new_balance as uint64 big-endian)
    

    The address is length-prefixed: a uint8 byte count followed by the raw prevout scriptPubKey bytes (Section 4.1.1). The SHA-256 input is scriptpubkey_length_uint8 || scriptpubkey_bytes || balance_uint64_be. P2PKH and P2WPKH from the same private key produce different scriptPubKey bytes, so they naturally produce different XOR contributions. The old_balance and new_balance values are the address's balance immediately before and after each individual modification — not at the start or end of the block. An address that changes balance multiple times within a block (e.g., a COG_TRANSFER followed by a mining reward) produces multiple XOR update pairs, one per modification. The maximum SHA-256 input is 76 bytes. Initialized to 32 zero bytes at genesis.

    The XOR fingerprint is a probabilistic commitment to the entire balance map. Two indexers with the same balance_xor have the same set of (address, balance) pairs with overwhelming probability. XOR is commutative and associative, so the fingerprint depends only on the final balance state, not on the order of intermediate updates within a block. XOR is self-inverse, so reorg reversal is natural: undoing a balance change applies the same two XOR operations with old and new swapped. Supply-neutral operations (COG_TRANSFER, DOMAIN_BUY, COG_LOCK, COG_CLAIM) do not change total_cog_supply but still require balance_xor updates — COG_TRANSFER and DOMAIN_BUY update two entries (sender and recipient); COG_LOCK and COG_CLAIM update one entry each (the debited or credited address) — because individual balances change even though total supply does not.

    The conservation invariant (total_cog_supply) catches bugs that alter the total supply. The balance_xor fingerprint catches bugs that preserve the total but distribute it incorrectly — crediting the wrong address, swapping sender and recipient, or splitting a single credit across multiple addresses. Distribution bugs are detected at the block where they occur.

  • domain_xor is a 32-byte running XOR fingerprint of all registered (domain_id, name, owner, anchored, reg_height, anchor_height, next_field_id) tuples. It is updated on every domain creation, ownership change, anchor, or field registration:

    On DOMAIN_REG (new domain with id, name, owner, anchored=false, reg_height=H, anchor_height=0, next_field_id=1):
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || owner_length as uint8 || owner_scriptpubkey_bytes || 0x00 || reg_height as uint32 BE || 0x00000000 || next_field_id as uint32 BE)
    
    On DOMAIN_TRANSFER or DOMAIN_BUY (owner changes; name, reg_height, anchor_height=0, next_field_id unchanged):
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || old_owner_length as uint8 || old_owner_scriptpubkey_bytes || 0x00 || reg_height as uint32 BE || 0x00000000 || next_field_id as uint32 BE)
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || new_owner_length as uint8 || new_owner_scriptpubkey_bytes || 0x00 || reg_height as uint32 BE || 0x00000000 || next_field_id as uint32 BE)
    
    On DOMAIN_ANCHOR (anchored 0→1, anchor_height 0→H; name, owner, reg_height, next_field_id unchanged):
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || owner_length as uint8 || owner_scriptpubkey_bytes || 0x00 || reg_height as uint32 BE || 0x00000000 || next_field_id as uint32 BE)
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || owner_length as uint8 || owner_scriptpubkey_bytes || 0x01 || reg_height as uint32 BE || anchor_height as uint32 BE || next_field_id as uint32 BE)
    
    On FIELD_REG (next_field_id increments from N to N+1; name, owner, anchored, reg_height, anchor_height unchanged):
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || owner_length as uint8 || owner_scriptpubkey_bytes || anchored as uint8 || reg_height as uint32 BE || anchor_height as uint32 BE || N as uint32 BE)
      domain_xor ^= SHA256(domain_id as uint32 BE || name_length as uint8 || name_bytes || owner_length as uint8 || owner_scriptpubkey_bytes || anchored as uint8 || reg_height as uint32 BE || anchor_height as uint32 BE || (N+1) as uint32 BE)
    

    The domain ID is serialized as uint32 big-endian (4 bytes). The name is length-prefixed: a uint8 byte count (1-63) followed by the raw ASCII name bytes. The owner is length-prefixed: a uint8 byte count followed by the raw prevout scriptPubKey bytes (Section 4.1.1), variable-length (up to 67 bytes per Section 4.1.1). Both variable-length fields (name and owner) are length-prefixed so that the concatenation is unambiguous. The anchored flag is a single byte (0x00 unanchored, 0x01 anchored). The reg_height and anchor_height are serialized as uint32 big-endian (4 bytes each). Before anchoring, anchor_height is 0x00000000. The next_field_id is serialized as uint32 big-endian (4 bytes). The maximum SHA-256 input is 149 bytes. Initialized to 32 zero bytes at genesis.

    Domain names are immutable after registration. DOMAIN_TRANSFER, DOMAIN_BUY, and DOMAIN_ANCHOR include the name in every hash input — the name is already stored in domain_by_id[id].name. DOMAIN_TRANSFER and DOMAIN_BUY always operate on unanchored domains (validation rules enforce this), so the anchored byte is always 0x00 in both the XOR-out and XOR-in entries. DOMAIN_ANCHOR does not change the owner, name, reg_height, or next_field_id, so only the anchored byte and anchor_height differ between the XOR-out and XOR-in entries. DOMAIN_TRANSFER and DOMAIN_BUY do not change reg_height, anchor_height, or next_field_id (all unchanged for ownership transfers). FIELD_REG does not change the owner, name, anchored status, reg_height, or anchor_height — only next_field_id increments by 1.

    XOR is self-inverse, so reorg reversal is natural: undoing a DOMAIN_REG XORs out the entry; undoing a DOMAIN_TRANSFER or DOMAIN_BUY applies the same two XOR operations with old and new owner swapped; undoing a DOMAIN_ANCHOR XORs the anchored-status change back. The fingerprint depends only on the final domain state, not on the order of intermediate updates within a block.

    The domain_xor fingerprint catches domain mapping corruptions that the aggregate counters (next_domain_id, anchored_domain_count) cannot detect: wrong name assigned to a specific domain ID, wrong owner assigned to a specific domain, swapped ownership between two domains, incorrect anchored status, wrong registration height, wrong anchor height, or wrong next_field_id on a specific domain. Name corruption is consensus-affecting — subdomain registration resolves the parent domain by name (last-hyphen rule), so a wrong name-to-ID mapping silently breaks all downstream subdomain registrations.

  • lock_xor is a 32-byte running XOR fingerprint of all active (unresolved) lock entries. It is updated on COG_LOCK creation and COG_CLAIM resolution:

    On COG_LOCK (new lock created):
      lock_xor ^= SHA256(lock_id as uint32 BE || locker_scriptpubkey_length as uint8 || locker_scriptpubkey_bytes || amount as uint64 BE || condition (32 bytes) || timeout_height as uint32 BE || recipient_domain_id as uint32 BE || creation_height as uint32 BE)
    
    On COG_CLAIM (lock resolved — claimed or reclaimed):
      lock_xor ^= SHA256(lock_id as uint32 BE || locker_scriptpubkey_length as uint8 || locker_scriptpubkey_bytes || amount as uint64 BE || condition (32 bytes) || timeout_height as uint32 BE || recipient_domain_id as uint32 BE || creation_height as uint32 BE)
    

    The lock ID is serialized as uint32 big-endian (4 bytes). The locker is length-prefixed: a uint8 byte count followed by the raw prevout scriptPubKey bytes of the COG_LOCK sender (Section 4.1.1). Amount, condition, timeout, and recipient domain ID are the values stored in the lock entry at creation time. The creation_height is serialized as uint32 big-endian (4 bytes) — the block height where the COG_LOCK transaction was processed. It is immutable; both COG_LOCK and COG_CLAIM entries use the same value. The maximum SHA-256 input is 124 bytes. Initialized to 32 zero bytes at genesis.

    The XOR operation is self-inverse: XOR-in at creation and XOR-out at resolution use the same hash. When all locks are resolved, lock_xor returns to all zeros.

    The lock_xor fingerprint catches lock content corruptions that the aggregate counters (active_lock_count, total_lock_cog) cannot detect: wrong locker address, wrong condition hash, wrong timeout height, wrong recipient domain, wrong locked amount, or wrong creation height on a specific lock entry. Lock corruptions are detected at the block where they occur.

  • listing_xor is a 32-byte running XOR fingerprint of all active domain listings. It is updated on every listing creation, price update, and removal:

    On DOMAIN_SELL price > 0, new listing (no prior listing for this domain):
      listing_xor ^= SHA256(domain_id as uint32 BE || price as uint64 BE || seller_scriptpubkey_length as uint8 || seller_scriptpubkey_bytes)
    
    On DOMAIN_SELL price > 0, update (prior listing exists):
      listing_xor ^= SHA256(domain_id as uint32 BE || old_price as uint64 BE || seller_scriptpubkey_length as uint8 || seller_scriptpubkey_bytes)
      listing_xor ^= SHA256(domain_id as uint32 BE || new_price as uint64 BE || seller_scriptpubkey_length as uint8 || seller_scriptpubkey_bytes)
    
    On listing removal (DOMAIN_SELL price 0, DOMAIN_BUY, DOMAIN_TRANSFER cancel, DOMAIN_ANCHOR cancel):
      listing_xor ^= SHA256(domain_id as uint32 BE || price as uint64 BE || seller_scriptpubkey_length as uint8 || seller_scriptpubkey_bytes)
    

    The domain ID is serialized as uint32 big-endian (4 bytes). The price is the listed price in cogtoshi as uint64 big-endian (8 bytes). The seller is length-prefixed: a uint8 byte count followed by the raw prevout scriptPubKey bytes of the listing creator (Section 4.1.1), variable-length (up to 67 bytes). The maximum SHA-256 input is 80 bytes. Initialized to 32 zero bytes at genesis.

    XOR is self-inverse, so reorg reversal is natural: undoing a DOMAIN_SELL XORs out the created entry; undoing a price update swaps old and new prices; undoing a removal XORs the listing back in. The fingerprint depends only on the final listing state, not on the order of intermediate updates within a block.

    The listing_xor fingerprint catches listing content corruptions that the total_listing_count counter cannot detect: wrong price on a specific listing, wrong seller address, or a listing assigned to the wrong domain. Listing corruption is consensus-affecting — DOMAIN_BUY validates the listed price and checks that the seller matches the domain's current owner.

  • field_xor is a 32-byte running XOR fingerprint of all registered field metadata entries. It is updated on FIELD_REG only:

    On FIELD_REG (new field created under domain):
      field_xor ^= SHA256(domain_id as uint32 BE || field_id as uint32 BE || permanent as uint8 || name_bytes)
    

    The domain ID and field ID are serialized as uint32 big-endian (4 bytes each). The permanent flag is a single byte (0x00 mutable, 0x01 permanent). The name is the raw ASCII field name bytes (1–63 bytes, same character rules as domain names). The maximum SHA-256 input is 72 bytes. Initialized to 32 zero bytes at genesis.

    Field metadata is immutable after creation — no operation modifies a field's name or permanent flag. DATA_UPDATE modifies field data (the {format, value} entry in domain_data), not field metadata (the {name, permanent} entry in fields). Reorg reversal of FIELD_REG XORs the entry back out.

    The field_xor fingerprint catches field metadata corruptions that the total_field_count counter cannot detect: wrong name assigned to a specific field ID, wrong permanent flag, wrong parent domain, or wrong field ID assignment. Name corruption affects FIELD_REG duplicate checking (5.10.3 rule 5). Permanent flag corruption affects DATA_UPDATE freeze logic (5.11.3 rule 7). Both are consensus-affecting — they change which operations succeed and which are silently ignored.

  • support_xor is a 32-byte running XOR fingerprint of all non-zero (source_domain_id, target_domain_id, net_support) entries. It is updated on every change to net_support:

    On every net_support change for pair (source_domain_id, target_domain_id) (old_value -> new_value):
      if old_value != 0:
        support_xor ^= SHA256(source_domain_id as uint32 BE || target_domain_id as uint32 BE || old_value as uint64 BE)
      if new_value != 0:
        support_xor ^= SHA256(source_domain_id as uint32 BE || target_domain_id as uint32 BE || new_value as uint64 BE)
    

    Both domain IDs are serialized as uint32 big-endian (4 bytes each). The net_support value is uint64 big-endian (8 bytes). The SHA-256 input is exactly 16 bytes (fixed length). Initialized to 32 zero bytes at genesis.

    Two operations change net_support: REP_COMMIT (third-party endorsement, increments) and REP_REVOKE (decrements). Self-commitments (REP_COMMIT where source == target) do not touch net_support. XOR is self-inverse, so reorg reversal is natural: undoing a REP_COMMIT or REP_REVOKE applies the same XOR operations with old and new values swapped. The fingerprint depends only on the final support state, not on the order of intermediate updates within a block.

    The support_xor fingerprint catches per-pair support corruptions that total_net_supported cannot detect: wrong amount for a specific (source, target) pair, support credited to the wrong target domain, or support attributed to the wrong source domain. Per-pair corruption is consensus-affecting — REP_REVOKE validates net_support[(source_domain_id, target_domain_id)] >= revocation_amount.

  • reputation_xor is a 32-byte running XOR fingerprint of all anchored domains whose (self_stake, supported_stake, total_supported, total_revoked) 4-tuple is not all zero. It is updated on every REP_COMMIT and REP_REVOKE that changes any of these four fields for the target domain:

On REP_COMMIT (self or third-party) or REP_REVOKE -- target domain entry update:

if old 4-tuple was not all zero:
  reputation_xor ^= SHA256(domain_id as uint32 BE || old_self_stake as uint64 BE || old_supported_stake as uint64 BE || old_total_supported as uint64 BE || old_total_revoked as uint64 BE)

reputation_xor ^= SHA256(domain_id as uint32 BE || new_self_stake as uint64 BE || new_supported_stake as uint64 BE || new_total_supported as uint64 BE || new_total_revoked as uint64 BE)

Once any field in the 4-tuple becomes nonzero, at least one cumulative counter (self_stake for self-commitments, total_supported or total_revoked for third-party) remains nonzero permanently. No domain exits the fingerprint once entered.

XOR is self-inverse, so reorg reversal is natural: undoing a REP_COMMIT or REP_REVOKE applies the same XOR operations with old and new values swapped. The fingerprint depends only on the final per-domain reputation state, not on the order of intermediate updates within a block. Initialized to 32 zero bytes at genesis.

The reputation_xor fingerprint catches per-domain reputation corruptions that the aggregate counters (total_self_staked, total_net_supported) cannot detect: wrong self_stake for a specific domain, wrong supported_stake, wrong total_supported, wrong total_revoked, or swapped values between domains all change the fingerprint.

  • data_xor is a 32-byte running XOR fingerprint of all non-null entries in the domain_data map. It is updated on every DATA_UPDATE that creates, overwrites, or clears an entry:

On DATA_UPDATE write (non-zero format with value bytes):

if domain_data[(domain_id, field_id)] already has an entry:
  data_xor ^= SHA256(domain_id as uint32 BE || field_id as uint32 BE || old_format as uint8 || old_value_bytes)

data_xor ^= SHA256(domain_id as uint32 BE || field_id as uint32 BE || new_format as uint8 || new_value_bytes)

On DATA_UPDATE clear (format byte 0x00):

if domain_data[(domain_id, field_id)] already has an entry:
  data_xor ^= SHA256(domain_id as uint32 BE || field_id as uint32 BE || old_format as uint8 || old_value_bytes)

Clearing an already-empty field does not change data_xor.

The domain ID and field ID are serialized as uint32 big-endian (4 bytes each). The format byte is a single byte. The value bytes are variable-length (1-67 bytes for writes). The SHA-256 input length varies from 10 to 76 bytes. Initialized to 32 zero bytes at genesis.

Entries can exit the fingerprint: a DATA_UPDATE clear removes the entry. When all field data entries across all domains are cleared, data_xor returns to zero. XOR is self-inverse, so reorg reversal is natural: undoing a DATA_UPDATE write or clear applies the same XOR operations with old and new swapped.

The data_xor fingerprint verifies per-entry correctness for field data: wrong format byte, wrong value bytes, phantom entries (data stored for a nonexistent field), or missing entries (data lost for a populated field). The field_xor fingerprint covers field metadata (names and permanent flags); data_xor covers field data (format and value). These are orthogonal.

  • endpoint_xor is a 32-byte running XOR fingerprint of all domains whose endpoint is not null. It is updated on every SET_ENDPOINT that sets or clears an endpoint:

On SET_ENDPOINT set (URI present):

if domain.endpoint was not null:
  endpoint_xor ^= SHA256(domain_id as uint32 BE || old_endpoint_bytes)

endpoint_xor ^= SHA256(domain_id as uint32 BE || new_endpoint_bytes)

On SET_ENDPOINT clear:

if domain.endpoint was not null:
  endpoint_xor ^= SHA256(domain_id as uint32 BE || old_endpoint_bytes)

Clearing an already-null endpoint does not change endpoint_xor.

The domain ID is serialized as uint32 big-endian (4 bytes). The endpoint bytes are variable-length (1-72 bytes). The SHA-256 input length varies from 5 to 76 bytes. Initialized to 32 zero bytes at genesis.

Like data_xor, entries can exit the fingerprint: a SET_ENDPOINT clear removes the entry. When all endpoints across all domains are cleared, endpoint_xor returns to zero. XOR is self-inverse, so reorg reversal is natural: undoing a SET_ENDPOINT applies the same XOR operations with old and new swapped.

The endpoint_xor fingerprint verifies per-domain endpoint correctness: wrong URI bytes, phantom endpoints, or missing endpoints.

  • canonical_xor is a 32-byte running XOR fingerprint of all entries in the canonical_domain mapping. It is updated on DOMAIN_ANCHOR (when a new entry is created) and SET_CANONICAL (when an existing entry is updated):

On DOMAIN_ANCHOR creating a new canonical_domain entry:

canonical_xor ^= SHA256(owner_scriptpubkey_length as uint8 || owner_scriptpubkey_bytes || domain_id as uint32 BE)

On SET_CANONICAL updating an existing entry (old_domain_id -> new_domain_id):

canonical_xor ^= SHA256(sender_scriptpubkey_length as uint8 || sender_scriptpubkey_bytes || old_domain_id as uint32 BE)
canonical_xor ^= SHA256(sender_scriptpubkey_length as uint8 || sender_scriptpubkey_bytes || new_domain_id as uint32 BE)

The scriptpubkey is length-prefixed: a uint8 byte count followed by the raw prevout scriptPubKey bytes (variable length, up to 67 bytes per Section 4.1.1). The domain ID is uint32 big-endian (4 bytes). The SHA-256 input length varies from 27 to 72 bytes. Initialized to 32 zero bytes at genesis.

Entries are created by DOMAIN_ANCHOR and updated by SET_CANONICAL. In forward processing, entries never exit the fingerprint — once an address has a canonical domain, it always has one. Only reorg of the creating DOMAIN_ANCHOR can remove an entry (XOR-out). XOR is self-inverse, so reorg reversal is natural.

The canonical_xor fingerprint catches canonical mapping corruptions that canonical_count cannot detect: wrong domain ID for an address, phantom entries, or missing entries.

  • delegate_xor is a 32-byte running XOR fingerprint of all domains whose delegate is not null. It is updated on every SET_DELEGATE that sets or clears a delegate:

On SET_DELEGATE set (delegate address present):

if domain.delegate was not null:
  delegate_xor ^= SHA256(domain_id as uint32 BE || old_delegate_scriptpubkey_length as uint8 || old_delegate_scriptpubkey_bytes)

delegate_xor ^= SHA256(domain_id as uint32 BE || new_delegate_scriptpubkey_length as uint8 || new_delegate_scriptpubkey_bytes)

On SET_DELEGATE clear:

if domain.delegate was not null:
  delegate_xor ^= SHA256(domain_id as uint32 BE || old_delegate_scriptpubkey_length as uint8 || old_delegate_scriptpubkey_bytes)

Clearing an already-null delegate does not change delegate_xor.

The domain ID is serialized as uint32 big-endian (4 bytes). The delegate scriptPubKey is length-prefixed: a uint8 byte count followed by the raw bytes, variable-length (up to 67 bytes per Section 4.1.1). The SHA-256 input length varies from 27 to 72 bytes. Initialized to 32 zero bytes at genesis.

Entries can exit the fingerprint: a SET_DELEGATE clear removes the entry. XOR is self-inverse, so reorg reversal is natural.

The delegate_xor fingerprint verifies per-domain delegate correctness: wrong delegate address, phantom delegates, or missing delegates all change the fingerprint.

  • miner_xor is a 32-byte running XOR fingerprint of all domains whose miner is not null. It is updated on every SET_MINER that sets or clears a miner:

On SET_MINER set (miner address present):

if domain.miner was not null:
  miner_xor ^= SHA256(domain_id as uint32 BE || old_miner_scriptpubkey_length as uint8 || old_miner_scriptpubkey_bytes)

miner_xor ^= SHA256(domain_id as uint32 BE || new_miner_scriptpubkey_length as uint8 || new_miner_scriptpubkey_bytes)

On SET_MINER clear:

if domain.miner was not null:
  miner_xor ^= SHA256(domain_id as uint32 BE || old_miner_scriptpubkey_length as uint8 || old_miner_scriptpubkey_bytes)

Clearing an already-null miner does not change miner_xor.

The domain ID is serialized as uint32 big-endian (4 bytes). The miner scriptPubKey is length-prefixed: a uint8 byte count followed by the raw bytes, variable-length (up to 67 bytes per Section 4.1.1). The SHA-256 input length varies from 27 to 72 bytes. Initialized to 32 zero bytes at genesis.

Entries can exit the fingerprint: a SET_MINER clear removes the entry. XOR is self-inverse, so reorg reversal is natural.

The miner_xor fingerprint verifies per-domain miner correctness: wrong miner address, phantom miners, or missing miners all change the fingerprint.

  • pq_xor is a 32-byte running XOR fingerprint of all PQ commitments. Each entry is computed as:
pq_xor ^= SHA256(domain_id as uint32 BE || pq_hash as 32 raw bytes)

One-time per domain. Entries never exit the fingerprint in forward processing. Reorg of PQ_COMMIT XORs the entry back out. Initialized to 32 zero bytes at genesis.

pq_hash is not part of the domain_xor serialization. The existing domain_xor tuple and formulas are unchanged. pq_hash is tracked exclusively by pq_xor.

Total input: 513 + L bytes, where L is the treasury scriptPubKey length. For the actual genesis treasury: 535 bytes.

Reputation divergence detection. The total_self_staked and total_net_supported aggregate fields verify totals. The reputation_xor fingerprint verifies per-domain correctness: wrong self_stake, supported_stake, total_supported, or total_revoked for any specific domain, as well as swaps between domains that leave aggregates unchanged, all change the fingerprint.

Support distribution divergence detection. The total_net_supported counter verifies the total amount of support. The support_xor fingerprint verifies per-pair correctness: wrong amount for a specific (source, target) domain pair, support credited to the wrong pair, or swapped support between pairs all change the fingerprint. Divergence is detected at the block where the incorrect REP_COMMIT or REP_REVOKE is processed.

Lock divergence detection. The active_lock_count and total_lock_cog fields catch structural divergence in lock state — wrong number of locks or wrong total escrowed amount. The lock_xor fingerprint catches content-level divergence — wrong locker, wrong condition, wrong timeout, wrong recipient, wrong amount, or wrong creation height on a specific lock. Together, they ensure that any bug in COG_LOCK creation, COG_CLAIM resolution, or timeout evaluation is immediately detectable.

Listing divergence detection. The total_listing_count counter verifies the number of active listings. The listing_xor fingerprint verifies per-listing correctness: wrong price, wrong seller address, or a listing associated with the wrong domain all change the fingerprint. Divergence is detected at the block where the incorrect listing is created or modified.

Field metadata divergence detection. The total_field_count counter verifies the number of registered fields. The field_xor fingerprint verifies per-field correctness: wrong name, wrong permanent flag, or a field associated with the wrong parent domain all change the fingerprint. Divergence is detected at the block where the incorrect FIELD_REG is processed.

Data divergence detection. The field_xor fingerprint verifies field metadata (names, permanent flags). The data_xor fingerprint verifies field data (format bytes, value bytes). Wrong value for a (domain_id, field_id) pair, wrong format byte, or a failed clear all change the fingerprint.

Endpoint divergence detection. The domain_xor fingerprint verifies domain identity (name, owner, anchored status, registration height, anchor height, next_field_id). The endpoint_xor fingerprint verifies the endpoint URI stored for each domain. Wrong URI bytes, phantom endpoints, or missing endpoints all change the fingerprint.

Canonical mapping divergence detection. The canonical_count counter verifies the number of canonical entries. The canonical_xor fingerprint verifies per-entry correctness: wrong domain ID for an address, phantom entries, or missing entries all change the fingerprint.

Delegate divergence detection. The delegate_xor fingerprint verifies delegate assignment correctness. Wrong delegate address for a domain, phantom delegates, or missing delegates all change the fingerprint.

Miner divergence detection. The miner_xor fingerprint verifies miner designation correctness. Wrong miner address for a domain, phantom miners, or missing miners all change the fingerprint.

PQ commitment divergence detection. The pq_xor fingerprint verifies PQ commitment correctness: wrong pq_hash for a domain, phantom commitments (pq_hash set on a domain that never received PQ_COMMIT), or missing commitments (PQ_COMMIT processed but pq_hash not stored). Divergence is detected at the block where the incorrect assignment occurs.

Domain mapping divergence detection. The next_domain_id counter verifies the number of registered domains, and anchored_domain_count verifies anchor processing. The domain_xor fingerprint verifies per-domain correctness: wrong name, wrong owner address, swapped owners, wrong anchored status, wrong registration height, wrong anchor height, or wrong next_field_id all change the fingerprint. Divergence is detected at the block where the incorrect assignment occurs.

Balance distribution divergence detection. The total_cog_supply counter verifies the total amount of COG in existence. The balance_xor fingerprint verifies per-address correctness: wrong balance for a specific address, credits to the wrong address, or split credits all change the fingerprint. Divergence is detected at the block where the incorrect credit occurs. The XOR fingerprint adds one to two SHA-256 calls per balance change, negligible overhead at Cogcoin's transaction volume.

This hash is NOT on-chain — it is not used in any validation rule and does not appear in OP_RETURN transactions. However, it IS mandatory for conforming indexers. An indexer that does not compute and store the per-block state hash is non-conforming. The hash serves as the primary divergence detection mechanism: two indexers that have processed the same blocks can compare state hashes at any height. If hashes differ, they know the exact block where divergence began. This is vastly faster than comparing full state trees or replaying from genesis. Peers, explorers, and agents SHOULD compare state hashes during sync to detect non-conformant indexers.

The state hash uses aggregate values and XOR fingerprints. The computation is trivial while catching any divergence that affects balance distribution, mining settlement, domain ownership, field metadata and counts, bootstrap depletion, canonical domain entry count, burn accounting, lock state and contents, listing state and contents, or reputation distribution and per-pair support — which covers every consensus-relevant code path.

State hash completeness. Every relational mapping in indexer state is covered by an XOR fingerprint: domain identity by domain_xor, lock contents by lock_xor, listing contents by listing_xor, field metadata by field_xor, per-pair support by support_xor, per-domain reputation by reputation_xor, field data by data_xor, endpoint URIs by endpoint_xor, and canonical domain mappings by canonical_xor; delegate assignments by delegate_xor; miner designations by miner_xor; PQ commitments by pq_xor.

The state hash commits the canonical forward maps (domain_by_id, fields, domain_data, net_support, etc.). Reverse indexes — domains (name → record, derived from domain_by_id), field_by_name (derived from fields) — are implementation conveniences for efficient lookup and are not independently committed. Their correctness is a consequence of the forward maps being correct. Per-domain next_field_id is deterministic given correct field assignments.

The activation_block and treasury_scriptpubkey fields pin the state hash to a specific protocol instance — different genesis parameters produce different hashes from block 1. Two conforming indexers that agree on the state hash have identical canonical state and are operating on the same protocol instance.


8. Transaction Construction Guide

8.1 General Pattern

Every Cogcoin operation is a standard Bitcoin transaction with:

  • At least one input (establishes the sender address).
  • An OP_RETURN output containing the Cogcoin payload (at most 80 bytes).
  • Optional BTC payment output to the treasury for root-level DOMAIN_REG only.
  • Optional change output back to the sender.

Unless an operation explicitly requires a BTC payment output, no other Bitcoin-value outputs have protocol meaning to the indexer. In particular, DOMAIN_BUY is settled entirely in indexer-tracked COG: the buyer's Cogcoin balance is debited, the seller's Cogcoin balance is credited, the domain ownership changes, and the listing is removed. No BTC payment output to the seller is required or recognized by the protocol. Subdomain registrations likewise require no treasury payment output — only the standard Bitcoin transaction fee.

8.2 OP_RETURN Output Script

OP_RETURN <data>

Where <data> is the Cogcoin payload (4–80 bytes). The OP_RETURN output value SHOULD be 0 satoshi. Any satoshi attached to an OP_RETURN output are permanently destroyed — they cannot be recovered. The indexer does not check the output value.

Other outputs in the same transaction carry real BTC value as needed:

OperationAdditional Outputs Required
DOMAIN_REGPayment to treasury address (domains); no additional output (subdomains)
DOMAIN_ANCHORNo additional outputs required (only Bitcoin tx fee)
All othersNo additional outputs required (only Bitcoin tx fee)

8.3 Byte Order Convention for Transaction IDs and Blockhashes

No current Cogcoin operation embeds Bitcoin transaction IDs in its payload. The byte order conventions in this section apply to the blockhash fragment in MINE transactions and to any future operations that may embed txids.

Display byte order (also called "RPC order") is the form shown by block explorers, Bitcoin Core's getrawtransaction, and most user-facing tools. This is the standard representation that developers copy and paste when working with Bitcoin transactions.

Internal byte order is the raw SHA-256d hash as it appears in serialized Bitcoin transactions on the wire. Internal order is the display bytes reversed end-to-end.

Blockhash fragment uses internal byte order (consensus-critical). The 4-byte blockhash fragment in MINE transactions (Section 5.1.1) uses internal byte order — bytes 0–3 of the raw SHA-256d hash, NOT the display-order hash shown by block explorers. This is the opposite convention from display order, and for good reason: display-order blockhashes begin with leading zeros (due to proof-of-work difficulty), so bytes 0–3 in display order would be 0x00000000 for nearly all recent blocks, making the fragment useless for identification. Internal-order bytes 0–3 are effectively random, providing strong identification of the referenced block.

Miners constructing MINE transactions must use the internal-order blockhash. Bitcoin Core's getblockhash returns display order; miners must reverse the bytes before extracting the fragment.

8.4 Multi-Operation Transactions

A Bitcoin transaction SHOULD contain at most one Cogcoin OP_RETURN. If multiple OP_RETURN outputs are present, the indexer uses the first output that passes extraction (Section 3.1 steps A–F). Outputs that fail any step — including size validation — are skipped and do not prevent later outputs from being examined.


9. Protocol Fee Schedule

Domain registration fees are paid in BTC to the treasury address. Subdomain registration burns 100 cogtoshi (see Section 5.4.6). All other fees are paid in Cogcoin (cogtoshi) and burned.

OperationFeeUnitDestinationNotes
Domain reg0.001–100 BTCBTC (satoshi)Treasury addressOne-time; varies by name length
Subdomain reg100 cogtoshiCOGBurnedRequires anchored parent; no bootstrap
Domain anchor0 cogtoshiOnly Bitcoin transaction fee; permanently locks domain
Set endpoint0 cogtoshiOnly Bitcoin transaction fee; mutable, overwritable
Set delegate0 cogtoshiOnly Bitcoin transaction fee; revocable
Set miner0 cogtoshiOnly Bitcoin transaction fee; revocable
Field registration100 cogtoshiCOGBurnedPer field; domain must already be anchored via DOMAIN_ANCHOR
Data write1 cogtoshiCOGBurnedFlat fee; real deterrent is Bitcoin tx fee
Data clear0Free; incentivizes reducing indexer storage
Commitmentamount chosenCOGBurned (reputation)Self-commitment: irrevocable. Third-party: revocable endorsement
COG_LOCK0 cogtoshiEscrowedCOG held in lock; not burned
COG_CLAIM0 cogtoshiOnly Bitcoin transaction fee
PQ_COMMIT0 cogtoshiOnly Bitcoin transaction fee
PQ_MIGRATE0 cogtoshiOnly Bitcoin transaction fee
All other operations0 cogtoshiOnly Bitcoin transaction fees apply

9.1 Cogcoin Denomination Table

UnitCogtoshiNotation
1 cogtoshi1The atomic unit
1 millicog100,0000.001 COG
1 cogcoin (COG)100,000,0001 COG

Cogtoshi pricing. Operational fees — data writes (1 cogtoshi), field registration (100 cogtoshi), subdomain registration (100 cogtoshi) — are priced so the protocol remains functional even at extreme COG valuations. If COG reached Bitcoin parity, a data write would cost 1 satoshi and a subdomain registration 100 satoshi. The protocol does not become unusable as its native token appreciates.


10. Full OP_RETURN Layout Reference

Minimum parsed sizes. The size values in this section are minimum parsed sizes, not exact length requirements. Unless an operation explicitly defines an exact-length special case (SET_ENDPOINT / SET_DELEGATE / SET_MINER clear at exactly 4 payload bytes), bytes beyond the parsed fields are ignored per the global trailing-byte rule (Section 3.2). A padded COG_LOCK, COG_CLAIM, DOMAIN_SELL, DOMAIN_BUY, DOMAIN_ANCHOR, REP_COMMIT, REP_REVOKE, SET_CANONICAL, PQ_COMMIT, PQ_MIGRATE, or any length-prefixed operation with trailing bytes after the declared fields is valid. Implementations MUST NOT reject transactions for exceeding the sizes listed here.

10.0 GENESIS (0x00)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x00)
4       32    SHA-256 of genesis parameters JSON
------
36 bytes (trailing bytes ignored).
Treasury = sender (input 0 prevout scriptPubKey).
Activated at block 937,337. Ignored before genesis height
and after the first valid GENESIS has been processed.

10.1 MINE (0x01)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x01)
4       4     Mining root domain ID (uint32 BE, anchored root-level domain)
8       4     Blockhash fragment (bytes 0–3 of referenced blockhash, internal byte order — not display order)
12      60    Sentence payload (40 × 12-bit token IDs, big-endian)
72      0–8   Miner data (optional, any content, ignored by indexer)
─────────────
Minimum: 72 bytes.  Maximum: 80 bytes.

10.2 COG_TRANSFER (0x02)

Offset  Size     Field
0       3        Magic "COG"
3       1        Op type (0x02)
4       8        Amount (uint64 cogtoshi, BE)
12      1        Recipient scriptPubKey length L
13      L        Recipient scriptPubKey (raw bytes)
─────────────
13 + L bytes (L = scriptPubKey length, max 67).

10.3 COG_LOCK (0x03)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x03)
4       8     Amount (uint64 cogtoshi, BE)
12      4     Timeout block height (uint32, BE)
16      4     Recipient domain ID (uint32, BE)
20      32    Condition: SHA-256 of 32-byte preimage
---------
Total: 52 bytes

10.4 COG_CLAIM (0x04)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x04)
4       4     Lock ID (uint32, BE)
8       32    Preimage (32 bytes, fixed). Claim: SHA256(preimage) must match condition.
              Reclaim (locker reclaiming after timeout): ignored by indexers; constructors SHOULD use 0x00.
---------
Total: 40 bytes

10.5 DOMAIN_REG (0x05)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x05)
4       1     Domain name length N (1–63)
5       N     Domain name (ASCII)
5+N     ...   Trailing bytes (ignored)
─────────────
Minimum parsed size: 5 + N bytes. Trailing bytes ignored. Maximum OP_RETURN size: 80 bytes.
No hyphen: BTC payment to treasury in a separate output.
Hyphen present: no treasury output; 100 cogtoshi burned from sender balance.

10.6 DOMAIN_TRANSFER (0x06)

Offset  Size     Field
0       3        Magic "COG"
3       1        Op type (0x06)
4       4        Domain ID (uint32 BE)
8       1        Recipient scriptPubKey length L
9       L        Recipient scriptPubKey (raw bytes)
─────────────
9 + L bytes (L = scriptPubKey length, max 67).

10.7 DOMAIN_SELL (0x07)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x07)
4       4     Domain ID (uint32 BE)
8       8     Listed price (uint64 cogtoshi, BE) — 0 to cancel
─────────────
Total: 16 bytes ✓

10.8 DOMAIN_BUY (0x08)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x08)
4       4     Domain ID (uint32 BE)
8       8     Expected price (uint64 cogtoshi, BE) — must match listed price
─────────────
Total: 16 bytes ✓

10.9 FIELD_REG (0x09)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x09)
4       4     Parent domain ID (uint32 BE)
8       1     Permanent flag (0x00 = mutable, 0x01 = permanent)
9       1     Field name length N (1–63)
10      N     Field name (ASCII)
10+N    ...   Trailing bytes ignored
---------
Fixed overhead: 10 + N bytes.
Field is always created empty. Write via DATA_UPDATE.

10.10 DATA_UPDATE (0x0A)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0A)
4       4     Domain ID (uint32 BE)
8       4     Field ID (uint32 BE)
12      1     Format byte (0x00 = clear, 0x01 = raw, 0x02+ = typed format)
13      ...   Value (remaining bytes)
---------
Fixed overhead: 13 bytes. Max value: 80 - 13 = 67 bytes.

10.11 SET_ENDPOINT (0x0B)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0B)
4       4     Domain ID (uint32 BE)
8       0–72  Endpoint URI (conventionally UTF-8). Absent = clear.
─────────────
Total: 8–80 bytes

10.12 REP_COMMIT (0x0C)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0C)
4       4     Source domain ID (uint32 BE, anchored, owned by sender or delegate)
8       4     Target domain ID (uint32 BE, anchored)
12      8     Amount (uint64 cogtoshi, BE)
20      0–60  Review (optional, 40 Coglex tokens; Section 5.13.4)
─────────────
Minimum: 20 bytes.  Maximum: 80 bytes.

10.13 REP_REVOKE (0x0D)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0D)
4       4     Source domain ID (uint32 BE, anchored, owned by sender or delegate)
8       4     Target domain ID (uint32 BE, anchored)
12      8     Revocation amount (uint64 cogtoshi, BE)
20      0–60  Review (optional, 40 Coglex tokens; Section 5.14.5)
─────────────
Minimum: 20 bytes.  Maximum: 80 bytes.

10.14 SET_CANONICAL (0x0E)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0E)
4       4     Domain ID (uint32 BE)
─────────────
Total: 8 bytes

10.15 DOMAIN_ANCHOR (0x0F)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x0F)
4       4     Domain ID (uint32 BE)
8       60    Founding message (optional, 40 Coglex tokens; Section 5.8.7)
68      12    Reserved (SHOULD be 0x00)
─────────────
Minimum: 8 bytes.  Maximum: 80 bytes.

10.16 SET_DELEGATE (0x10)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x10)
4       4     Domain ID (uint32 BE)
8       1     Delegate scriptPubKey length L (uint8)
9       L     Delegate scriptPubKey (raw bytes)
─────────────
Set total: 9 + L bytes (L = scriptPubKey length, max 67)
Clear total: 8 bytes (no length byte or scriptPubKey)

10.17 SET_MINER (0x11)

Offset  Size  Field
0       3     Magic "COG"
3       1     Op type (0x11)
4       4     Domain ID (uint32 BE)
8       1     Miner scriptPubKey length L (uint8)
9       L     Miner scriptPubKey (raw bytes)
─────────────
Set total: 9 + L bytes (L = scriptPubKey length, max 67)
Clear total: 8 bytes (no length byte or scriptPubKey)

10.18 PQ_COMMIT (0x12)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x12)
4       4     Domain ID (uint32, big-endian)
8       32    pq_hash (32-byte commitment)
---------
Total: 40 bytes. Any trailing bytes (up to 80) are ignored.

10.19 PQ_MIGRATE (0x13)

Offset  Size  Field
0       3     Magic "COG" (0x43 0x4F 0x47)
3       1     Op type (0x13)
4       4     Domain ID (uint32, big-endian)
8       32    Migration secret (32 bytes)
---------
Total: 40 bytes. Any trailing bytes (up to 80) are ignored.

11. Protocol Constants Summary

ConstantValueRationale
Magic bytes0x434F47 ("COG")Protocol identification
GENESIS op code0x00Activated at block 937,337; encodes treasury address on-chain
Max OP_RETURN80 bytesEnforced at Section 3.1 step D; oversized outputs skipped during extraction
Sentence payload60 bytes40 × 12 bits
Max tokens per sentence40Coglex
Token ID bits124096 token vocabulary
BIP-39 words per sentence5Mandatory, deterministic
Mining block window1 block (H-1 only)All miners in block H reference H-1
Top miners rewarded per block5Fixed rank-weights: 50,20,15,10,5
Scorers256 total (three tiers: gates, statistical, neural)Blend from referenced blockhash; tier details in scoring module
Scoring bundleSHA-256 committed in genesis parametersImmutable, verified by hash
Cross-platform test vectorsIncluded in bundleGates + scorers + preprocessor + blend + quantization boundary. Settlement vectors in @cogcoin/scoring.
Scoring executionMandatory WASM via @cogcoin/scoringNative scoring reimplementations non-conforming. Settlement logic may be reimplemented if all conformance vectors pass.
Cogtoshi per Cogcoin100,000,000Same as satoshi per BTC
Bootstrap pool100,000 COGFirst-come-first-served
Bootstrap award0.1 COG per root domain anchor (flat)Root-level DOMAIN_ANCHOR only; subdomains receive no bootstrap
Data write fee1 cogtoshi (flat)Clears are free; BTC tx fee deters spam
Max domain name length63 charactersASCII a-z, 0-9, hyphens (no leading/trailing/consecutive); last hyphen determines parent
Subdomain fee100 cogtoshiBurned; requires anchored parent
Domain identifieruint32 domain IDStarts at 1; ID 0 is null
Field identifieruint32 field ID (per-domain)Starts at 1 per domain; ID 0 is null; unique key is (domain_id, field_id)
Field name max length63 charactersSame rules as domain names
Field registration fee100 cogtoshiBurned from sender
Field modes2 (mutable, permanent)Binary permanent flag (0x00 or 0x01)
Max value (DATA_UPDATE)67 bytes1 byte used for format byte
Address encodingRaw scriptPubKey bytesLength-prefixed in payloads; raw prevout bytes for sender identity
Max scriptPubKey size67 bytesMatches max recipient size in COG_TRANSFER; all standard types ≤ 42 bytes
Domain resaleCogcoin-only, on-chain listingsIndexer-atomic, no race conditions
Domain anchor fee0 cogtoshiOnly Bitcoin tx fee; permanence is the cost
Domain anchor total8–80 bytesDomain ID + optional 40-token founding message + 12 reserved bytes (Section 5.8.7)
Set endpoint fee0 cogtoshiOnly Bitcoin tx fee; mutable, overwritable
Max endpoint URI72 bytes80 - 8 (header + op + domain ID)
Set delegate fee0 cogtoshiOnly Bitcoin tx fee; revocable
Set miner fee0 cogtoshiOnly Bitcoin tx fee; revocable
Operation count20 (0x00-0x13)GENESIS through PQ_MIGRATE
Lock typeHashlock onlySHA-256 preimage condition
Lock identifieruint32 lock IDStarts at 1; ID 0 is null
Preimage length32 bytes (fixed)Matches SHA-256 output width
Lock fee0 cogtoshiOnly Bitcoin tx fee; COG is escrowed, not burned
Max lock duration262,800 blocks (~5 years)Bounds indexer state growth; covers all practical financial instruments

Counter capacity. Domain IDs and lock IDs use uint32 counters (max ~4.3 billion). Field IDs are uint32 per domain. At projected usage rates constrained by Bitcoin block space, these capacities are sufficient for decades. In the unlikely event of exhaustion, new registrations or locks of the affected type would cease; all existing state would be unaffected.

Complete constant set. The genesis parameters JSON contains economic values tunable at design time. Structural protocol constants (subdomain fee, rank weights, size limits, name length limits, null ID rules, overflow guards) are published in canonical_constants.json within the @cogcoin/genesis package. The union of both files covers every consensus-critical constant. Both files are committed by SHA-256 in the signed genesis announcement. This table is a summary — the authoritative values are in the files and in this whitepaper.


12. Appendix A: Worked Examples

A.1 Mining Transaction

Alice wants to mine Cogcoin. She has previously registered and anchored the root-level domain "alice" (domain ID 7). The current Bitcoin block height is 937,400. She references block 937,400 (the current tip). Blockhash of 937,400 starts with 0xABCD1234....

Her domain ID (7) combined with the blockhash yields 5 BIP-39 words: "ocean", "puzzle", "bright", "anchor", "flame".

She uses an LLM to generate: "The bright flame of an ocean sun rise can anchor every puzzle in meaning."

She encodes this with the Coglex, gets 22 token IDs, packed into 60 bytes. She constructs:

43 4F 47  01  00 00 00 07  AB CD 12 34  [60 bytes of sentence payload...]  [0–8 bytes miner data]
[magic  ] [op] [domain ID ] [blockhash ]

The trailing bytes are optional miner data — Alice uses them to embed her vanity tag. She broadcasts this in a Bitcoin transaction. Her transaction confirms in block 937,401. The indexer checks block 937,400 (H-1 = 937,401 - 1), confirms its blockhash starts with 0xABCD1234, and accepts the submission. At the end of block 937,401 processing, all valid MINE transactions in block 937,401 are scored using blend_seed = SHA256(blockhash_937400). If her sentence scores in the top 5, she earns a share of block 937,401's reward.

A.2 Domain Registration

Bob registers the domain "mybot" (5 characters, costs 0.01 BTC).

43 4F 47  05  05  6D 79 62 6F 74  00 ...
[magic ] [op] [L] [m  y  b  o  t] [trailing]

His Bitcoin transaction includes an output of 0.01 BTC to the treasury address (separate from the OP_RETURN). The indexer assigns domain ID 42 (the 42nd domain registered, since IDs start at 1). "mybot" now points to Bob's address.

A.2b Subdomain Registration

Carol owns "oracle" (domain ID 7, anchored). She registers "oracle-weather" (14 characters) as a subdomain. Her available COG balance is 0.5 COG.

43 4F 47  05  0E  6F 72 61 63 6C 65 2D 77 65 61 74 68 65 72  00 ...
[magic ] [op] [L] [o  r  a  c  l  e  -  w  e  a  t  h  e  r] [pad]

Carol's Bitcoin transaction does NOT include a payment to the treasury. The indexer:

  1. Parses name "oracle-weather". Contains hyphen → subdomain.
  2. Extracts parent prefix "oracle" (before last hyphen).
  3. Looks up "oracle" → domain ID 7, owner = Carol, anchored = true. OK.
  4. Verifies sender (Carol) == owner. OK.
  5. Checks Carol's available balance: 50,000,000 >= 100. OK.
  6. Assigns domain ID (next sequential). Owner = Carol.
  7. Debits 100 cogtoshi from Carol's balance.
  8. No bootstrap award.

Carol's final balance: 49,999,900 cogtoshi. She can now DOMAIN_TRANSFER "oracle-weather" to a child agent's address, or DOMAIN_ANCHOR it for her own use, or DOMAIN_SELL it.

A.2c Hierarchical Subdomain Minting

Carol transferred "oracle-weather" to Dave, who anchored it (domain ID 15, anchored, owner = Dave). Dave wants to create specialized subdomains under his namespace. His available COG balance is 0.3 COG.

Dave registers "oracle-weather-tokyo" (20 characters):

43 4F 47  05  14  6F 72 61 63 6C 65 2D 77 65 61 74 68 65 72 2D 74 6F 6B 79 6F  00 ...
[magic ] [op] [L] [o  r  a  c  l  e  -  w  e  a  t  h  e  r  -  t  o  k  y  o] [pad]

The indexer:

  1. Parses name "oracle-weather-tokyo". Contains hyphen → subdomain.
  2. Extracts parent prefix "oracle-weather" (before last hyphen).
  3. Looks up "oracle-weather" → domain ID 15, owner = Dave, anchored = true. OK.
  4. Verifies sender (Dave) == owner. OK.
  5. Checks Dave's available balance: 30,000,000 >= 100. OK.
  6. Assigns domain ID (next sequential). Owner = Dave.
  7. Debits 100 cogtoshi from Dave's balance.
  8. No bootstrap award.

Dave's final balance: 29,999,900 cogtoshi. Dave can DOMAIN_TRANSFER "oracle-weather-tokyo" to a specialized agent, DOMAIN_ANCHOR it, or DOMAIN_SELL it. Carol (owner of "oracle") was not involved — Dave's namespace authority over "oracle-weather-*" is a consequence of anchoring "oracle-weather."

Gap prevention example. Suppose Carol (owner of anchored "oracle") attempts to directly register "oracle-weather-tokyo" before Dave has registered "oracle-weather":

  1. Parses name "oracle-weather-tokyo". Contains hyphen → subdomain.
  2. Extracts parent prefix "oracle-weather" (before last hyphen).
  3. Looks up "oracle-weather" → not registered. Fails.

The registration is silently ignored. Intermediate levels cannot be skipped. "oracle-weather" must exist and be anchored before any "oracle-weather-*" names can be created.

Cost of depth. Reaching "oracle-weather-tokyo" required three registrations, three anchors, and two COG burns:

"oracle"                 0.001 BTC to treasury  (root domain)
"oracle-weather"         100 cogtoshi burned  (level 1 subdomain)
"oracle-weather-tokyo"   100 cogtoshi burned  (level 2 subdomain)

Total COG burned: 200 cogtoshi across two subdomain registrations
Total Bitcoin transactions: 6 (3 registrations + 3 anchors)
Total anchored domains: 3 (one per level)

Each level of depth adds economic cost and an independently committed identity to the namespace.

A.3 Field Registration and Data Write


Bob has already anchored domain 42 ("mybot") via DOMAIN_ANCHOR (Section 5.8). He now registers a permanent field "endpoint" under domain 42:

43 4F 47  09  00 00 00 2A  01  08  65 6E 64 70 6F 69 6E 74
[magic ] [op] [domain=42 ] [pf] [L] [e  n  d  p  o  i  n  t]

Permanent flag = 0x01 (permanent), name length = 8 ("endpoint"). The field is created empty. The domain must already be anchored via DOMAIN_ANCHOR — if it is not, the FIELD_REG is silently ignored. Bob's balance is debited 100 cogtoshi (the flat field registration fee).

Bob then writes the endpoint value via a separate DATA_UPDATE transaction. The field was assigned field ID 1 (the first field under domain 42):

43 4F 47  0A  00 00 00 2A  00 00 00 01  11  [value bytes: e.g., "https://mybot.example.com/api"]
[magic ] [op] [domain=42 ] [field=1   ] [fmt] [value                                            ]

Format byte = 0x11 (service endpoint, see Appendix D). The indexer writes {format=0x11, value} to domain_data and immediately freezes the field (permanent). Bob's balance is debited 1 cogtoshi for the data write. No subsequent DATA_UPDATE to this field is accepted.

Both transactions can appear in the same block if FIELD_REG has a lower transaction index than DATA_UPDATE. The field exists when the DATA_UPDATE is processed.

For agents that want a mutable endpoint, SET_ENDPOINT (Section 5.12) provides a simpler alternative: a single transaction with no field registration fee, and the URI is updatable without registering a mutable field.

A.4 Data Update

Domain-scoped write (mutable field): Charlie owns domain "oracle" (domain ID 12). He previously registered mutable field "btc-usd" (field ID 3 under domain 12). He writes a price:

43 4F 47  0A  00 00 00 0C  00 00 00 03  10  [value bytes, up to 67 bytes]
[magic ] [op] [domain=12 ] [field=3   ] [fmt] [value                      ]

Format byte = 0x10 (price feed, see Appendix D). This creates the entry: 12.3 = {format=0x10, value}. The indexer looks up field 3 under domain 12, verifies the field exists, reads the format byte and remaining bytes as value data, and stores {format, value} in domain_data. Charlie's Cogcoin balance is debited 1 cogtoshi.

Field clearing: To clear field 3, Charlie sends a DATA_UPDATE with format byte 0x00:

43 4F 47  0A  00 00 00 0C  00 00 00 03  00
[magic ] [op] [domain=12 ] [field=3   ] [fmt=clear]

The indexer deletes the entry from domain_data. Reads now return null. No Cogcoin is debited — clears are free (only the Bitcoin transaction fee applies).

Domain-scoped write (mutable field): Charlie also registers a mutable field "status" (field name length 6) under domain 12:

43 4F 47  09  00 00 00 0C  00  06  73 74 61 74 75 73
[magic ] [op] [domain=12 ] [pf] [L] [s  t  a  t  u  s]

Permanent flag = 0x00 (mutable), name length = 6 ("status"). The field is created empty. Charlie's balance is debited 100 cogtoshi for the registration. He then writes the initial status via a separate DATA_UPDATE using the assigned field ID.

A.5 Reputation Commitment

Charlie owns domain "oracle" (domain ID 12), which is anchored. He commits 10 COG to his own domain's reputation (self-commitment: source and target are both domain 12):

10 COG = 10 × 100,000,000 = 1,000,000,000 cogtoshi = 0x3B9ACA00 as uint64 big-endian: 00 00 00 00 3B 9A CA 00.

43 4F 47  0C  00 00 00 0C  00 00 00 0C  00 00 00 00 3B 9A CA 00
[magic ] [op] [source=12 ] [target=12 ] [10 COG in cogtoshi       ]

Charlie's Cogcoin balance decreases by 1,000,000,000 cogtoshi. Domain 12's self_stake increases by the same amount. Because source == target, this is a permanent self-commitment with no revocation path.

A.6 Mining Reward Settlement

Block 937,392 (in the 4th halving era) contains 4 valid MINE transactions from miners A, B, C, D, mining under root domains with IDs 3, 8, 14, and 21 respectively. Each submission passed the indexer-side checks (header, op, size, domain validation, fragment resolution) and has been stored in mining_pending with its mining domain ID, raw sentence bytes, BIP-39 word indices, referenced blockhash, and transaction index. In this example, all four submissions reference block 937,391.

At the end of block 937,392 processing (after all Cogcoin transactions in 937,392 have been applied), the indexer settles mining rewards using @cogcoin/scoring:

1. Determines referenced block. All submissions in block 937,392 reference block 937,391 (H-1).

2. Computes blend weights.

blend_seed = SHA256(blockhash_937391)
256 bytes = SHA256(blend_seed || 0x00) || SHA256(blend_seed || 0x01) || ... || SHA256(blend_seed || 0x07)

The scoring module maps these 256 bytes to scorer activations and weights. In this example, 85 scorers are active.

3. Calls score_sentences_wasm with the 4 submissions and the blend_seed. The WASM binary scores each submission using the 85 active scorers (uint16 outputs), then computes the integer blend. Results (in input order):

MinerDomain IDAddresscanonical_blend (uint64)Display Score
A31A2B...3C868,744,215~0.741
B85D6E...7F818,361,270~0.698
C148A9B...0D818,361,270~0.698
D212E3F...4A717,520,692~0.612

4. Deduplicates per domain. All four domains are distinct, so no dedup needed.

5. Breaks tie between B and C (identical canonical_blend 818,361,270):

tie_B = SHA256(blend_seed || domain_id_B)  = 0x2f91...
tie_C = SHA256(blend_seed || domain_id_C)  = 0x8a03...

B's hash (0x2f91...) < C's hash (0x8a03...), so B ranks higher.

6. Final ranking: A (1st), B (2nd), C (3rd), D (4th).

7. Distributes reward. Block reward at height 937,392 (4th halving era):

halving_era = 937392 / 210000 = 4 (integer division)
block_reward = 5000000000 >> 4 = 312,500,000 cogtoshi (3.125 COG)

Active rank-weights for 4 winners: [50, 20, 15, 10], sum = 95.

remaining = 312,500,000; remaining_weight = 95

Rank 1 (A): floor(312,500,000 × 50 / 95) = 164,473,684
  remaining = 148,026,316; remaining_weight = 45

Rank 2 (B): floor(148,026,316 × 20 / 45) = 65,789,473
  remaining = 82,236,843; remaining_weight = 25

Rank 3 (C): floor(82,236,843 × 15 / 25) = 49,342,105
  remaining = 32,894,738; remaining_weight = 10

Rank 4 (D): floor(32,894,738 × 10 / 10) = 32,894,738
  remaining = 0
RankMinerReward (cogtoshi)Reward (COG)
1stA164,473,684~1.645
2ndB65,789,473~0.658
3rdC49,342,105~0.493
4thD32,894,738~0.329
Total312,500,0003.125

Note: rank 4 absorbs the rounding remainder (2 extra cogtoshi compared to a naive floor(312500000 × 10/95) = 32,894,736). These rewards are credited at the end of block 937,392 processing. The miners can spend these rewards starting at block 937,393.


A.7 Hash-Locked Escrow

Agent "atlas" wants to pay agent "oracle-weather" 2 COG for a data feed, conditional on oracle-weather producing a specific computation result. Atlas generates a 32-byte secret and shares the hash with oracle-weather off-chain.

Step 1: Atlas creates the lock.

Atlas knows oracle-weather's domain ID is 47. Atlas generates a random 32-byte preimage and computes hash = SHA256(preimage). Atlas broadcasts:

43 4F 47  03  00 00 00 00 0B EB C2 00  00 0E 4D B8  00 00 00 2F  [32 bytes: hash]
[magic  ] [op][   200,000,000 cogtoshi ][ block 937400][ domain 47] [condition     ]

The indexer debits 200,000,000 cogtoshi (2 COG) from atlas's available balance and creates lock ID 1. The COG is now in escrow.

Step 2: Atlas shares the preimage off-chain.

When oracle-weather delivers the data feed, atlas sends the preimage via an off-chain channel (Nostr, HTTP, direct message).

Step 3: Oracle-weather claims.

Oracle-weather's owner broadcasts a COG_CLAIM:

43 4F 47  04  00 00 00 01  [32 bytes: preimage]
[magic  ] [op][ lock ID 1 ] [preimage           ]

The indexer verifies: lock 1 is active, sender is domain 47's owner, current block < 937,400, and SHA256(preimage) matches the stored hash. All checks pass. 200,000,000 cogtoshi is credited to oracle-weather's owner.

Alternative: timeout reclaim. If oracle-weather never claims (they never delivered the data, or lost their key), atlas waits until block 937,400 and broadcasts a COG_CLAIM. The indexer verifies: sender is the original locker, block >= timeout. The 2 COG returns to atlas.


13. Appendix B: Indexer Pseudocode

This appendix is illustrative, not normative. The handler sketches below are simplified to show control flow and are not a complete implementation guide. They omit payload length validation, state hash counter maintenance, reverse-map updates (e.g., domains name index, field_by_name), full domain-record initialization on registration, listing cancellation side effects, and other state work required by the normative sections. The authoritative specification for each operation is its handler section (Sections 5.1–5.19) and the state hash rules (Section 7.6). Do not port this pseudocode literally.

Counter maintenance. The state hash includes two genesis constants (activation_block and treasury_scriptpubkey) that are set once at activation and never updated. The simplified pseudocode below omits updates to several state hash counters, including total_cog_supply, total_minted_cog, total_field_count, total_self_staked, total_net_supported, total_listing_count, balance_xor, domain_xor, lock_xor, listing_xor, field_xor, support_xor, reputation_xor, data_xor, endpoint_xor, canonical_xor, delegate_xor, miner_xor, and pq_xor. Section 7.6 specifies the complete set of 30 state hash fields and their update triggers. Conforming implementations MUST maintain all 30 fields as described in Section 7.6; the pseudocode is not sufficient on its own.

total_cog_supply must be incremented on every mint (mining rewards, bootstrap awards) and decremented on every burn (field registration, data writes, commitments, endorsements, subdomain registration). COG_LOCK, COG_CLAIM, COG_TRANSFER, and DOMAIN_BUY do not change it.

balance_xor must be updated on every change to cogcoin_balances. domain_xor must be updated on every domain creation, ownership change, anchor, and field registration. lock_xor must be updated on every COG_LOCK creation and COG_CLAIM resolution. listing_xor must be updated on every listing creation, price update, and removal. field_xor must be updated on every FIELD_REG.

support_xor must be updated on every REP_COMMIT (third-party endorsement) and REP_REVOKE. reputation_xor must be updated on every REP_COMMIT and REP_REVOKE (all types). data_xor must be updated on every DATA_UPDATE (writes and clears).

endpoint_xor must be updated on every SET_ENDPOINT (sets and clears). canonical_xor must be updated on every DOMAIN_ANCHOR (when creating a new canonical entry) and SET_CANONICAL. delegate_xor must be updated on every SET_DELEGATE (sets and clears). miner_xor must be updated on every SET_MINER (sets and clears). pq_xor must be updated on every PQ_COMMIT.

These updates do not appear in the pseudocode functions below.

Payload length checks. Most pseudocode functions below omit payload length validation for brevity. Every operation MUST validate that the OP_RETURN data contains enough bytes for all fixed and variable-length fields before reading any field (Section 3.2). The omission is for readability — production implementations must check lengths first.

def scan_for_genesis(block, state, expected_params_hash, expected_treasury_scriptpubkey):
    """Scan a block for the GENESIS transaction. Returns True if found."""
    for tx in block.transactions:
        if tx.index == 0:
            continue  # Skip coinbase — Section 4.1.1 applies to ALL ops including GENESIS
        op_return = find_cogcoin_op_return(tx)
        if op_return and op_return[3] == 0x00:  # GENESIS
            params_hash = op_return[4:36]
            if params_hash != expected_params_hash:
                continue  # Wrong hash — skip this 0x00 op, keep scanning
            # Treasury = sender of GENESIS tx (Section 4.1.1)
            sender = get_sender_address(tx)  # input 0 prevout scriptPubKey
            if not sender:
                continue  # No valid sender
            # Rule 4: verify sender matches genesis params treasury_address
            if sender != expected_treasury_scriptpubkey:
                continue  # Sender doesn't match JSON treasury_address
            state.treasury_scriptpubkey = sender
            state.activated = True
            state.activation_block = block.height
            state.genesis_tx_index = tx.index
            return True
    return False  # No GENESIS in this block; skip entirely

# Main loop: scan from genesis_height until activation, then process normally
for block in blocks_from(genesis_height):
    if not state.activated:
        if scan_for_genesis(block, state, expected_params_hash, expected_treasury_scriptpubkey):
            # Process only transactions AFTER the GENESIS transaction in this block.
            # Transactions at a lower index than GENESIS are ignored.
            process_block(block, state)
        # else: no GENESIS found, skip this block entirely
    else:
        process_block(block, state)

def process_block(block, state):
    for tx in block.transactions:
        # Skip coinbase transaction (Section 4.1.1).
        if tx.index == 0:
            continue

        # In the activation block, skip transactions at or before the GENESIS index.
        if block.height == state.activation_block and tx.index <= state.genesis_tx_index:
            continue

        # Extract the Cogcoin output (if any) per Section 3.1 steps A--F.
        # find_cogcoin_op_return scans outputs in index order, skipping
        # non-OP_RETURN outputs, malformed pushdata, data outside 4--80 bytes,
        # and data not starting with COG magic. Returns None or the extracted data.

        op_return = find_cogcoin_op_return(tx)
        if op_return is not None:
            sender = get_sender_address(tx)
            if sender is not None:  # Empty/oversized scriptPubKey or coinbase → skip (Section 4.1.1)
                op_type = op_return[3]
                payload = op_return[4:]

                if op_type == 0x00:  # GENESIS — handled by scan_for_genesis
                    pass
                elif op_type == 0x01:  # MINE
                    process_mine(sender, payload, tx, block, state)
                elif op_type == 0x02:  # COG_TRANSFER
                    process_cog_transfer(sender, payload, state)
                elif op_type == 0x03:  # COG_LOCK
                    process_cog_lock(sender, payload, block, state)
                elif op_type == 0x04:  # COG_CLAIM
                    process_cog_claim(sender, payload, block, state)
                elif op_type == 0x05:  # DOMAIN_REG (domain or subdomain)
                    process_domain_reg(sender, payload, tx, state)
                elif op_type == 0x06:  # DOMAIN_TRANSFER
                    process_domain_transfer(sender, payload, state)
                elif op_type == 0x07:  # DOMAIN_SELL
                    process_domain_sell(sender, payload, state)
                elif op_type == 0x08:  # DOMAIN_BUY
                    process_domain_buy(sender, payload, state)
                elif op_type == 0x09:  # FIELD_REG
                    process_field_reg(sender, payload, state)
                elif op_type == 0x0A:  # DATA_UPDATE
                    process_data_update(sender, payload, state)
                elif op_type == 0x0B:  # SET_ENDPOINT
                    process_set_endpoint(sender, payload, state)
                elif op_type == 0x0C:  # REP_COMMIT
                    process_rep_commit(sender, payload, state)
                elif op_type == 0x0D:  # REP_REVOKE
                    process_rep_revoke(sender, payload, state)
                elif op_type == 0x0E:  # SET_CANONICAL
                    process_set_canonical(sender, payload, state)
                elif op_type == 0x0F:  # DOMAIN_ANCHOR
                    process_domain_anchor(sender, payload, state)
                elif op_type == 0x10:  # SET_DELEGATE
                    process_set_delegate(sender, payload, state)
                elif op_type == 0x11:  # SET_MINER
                    process_set_miner(sender, payload, state)
                elif op_type == 0x12:  # PQ_COMMIT
                    process_pq_commit(sender, payload, state)
                elif op_type == 0x13:  # PQ_MIGRATE
                    pass  # No-op before activation height
                # Unknown op types are silently ignored

    # After all transactions, settle mining rewards for THIS block.
    # Settlement uses @cogcoin/scoring.
    # settle_block_wasm MUST NOT be used for consensus (incompatible address format and weights).
    if block.height >= state.activation_block:
        halving_era = block.height // 210000
        block_reward = 5000000000 >> halving_era
        if block_reward > 0 and block.height in state.mining_pending:
            settle_mining_rewards(block.height, block_reward, state)
        elif block_reward > 0:
            pass  # No submissions. Reward is never minted.
        else:
            state.mining_pending.pop(block.height, None)
# Domain registration (simplified; see Section 5.4 for full rules)
def process_domain_reg(sender, payload, tx, state):
    name = parse_domain_name(payload)
    if not valid_domain_name(name): return
    if name in state.domains: return  # already registered

    if '-' in name:
        # Subdomain registration
        parent_prefix = name[:name.rindex('-')]  # substring before last hyphen
        if parent_prefix not in state.domains: return
        parent = state.domains[parent_prefix]
        if not parent.anchored: return
        if parent.owner != sender and parent.delegate != sender: return
        if available_balance(sender, state) < 100: return

        # Register
        domain_id = state.next_domain_id
        state.next_domain_id += 1
        state.domains[name] = Domain(id=domain_id, owner=sender, anchored=False)
        state.cogcoin_balances[sender] -= 100  # burned
        state.total_burned_cog += 100
        # No bootstrap award

    else:
        # BTC payment to treasury
        if not check_treasury_payment(tx, required_btc(len(name)), state):
            return

        # Register
        domain_id = state.next_domain_id
        state.next_domain_id += 1
        state.domains[name] = Domain(id=domain_id, owner=sender, anchored=False)

        # Bootstrap award is granted at DOMAIN_ANCHOR (see Section 5.8.3 step 7)

# Conditional lock (simplified; see Section 5.3 for full rules)
def process_cog_lock(sender, payload, block, state):
    if len(payload) < 48: return  # 8 + 4 + 4 + 32

    amount = int.from_bytes(payload[0:8], 'big')
    if amount == 0: return

    timeout_height = int.from_bytes(payload[8:12], 'big')
    if timeout_height <= block.height: return
    if timeout_height > block.height + 262800: return  # max ~5 years

    recipient_domain_id = int.from_bytes(payload[12:16], 'big')
    condition = payload[16:48]

    # Validate recipient
    if recipient_domain_id == 0: return
    if recipient_domain_id not in state.domain_by_id: return
    domain = state.domain_by_id[recipient_domain_id]
    if not domain.anchored: return

    # Condition must not be all zeros
    if condition == bytes(32): return

    # Balance check
    if available_balance(sender, state) < amount: return

    # Create lock
    lock_id = state.next_lock_id
    state.next_lock_id += 1
    state.cog_locks[lock_id] = {
        'locker': sender,
        'amount': amount,
        'condition': condition,
        'timeout_height': timeout_height,
        'recipient_domain_id': recipient_domain_id,
        'creation_height': block.height,
    }
    state.cogcoin_balances[sender] -= amount
    state.active_lock_count += 1
    state.total_lock_cog += amount

# Claim or reclaim a conditional lock (simplified; see Section 5.3 for full rules)
def process_cog_claim(sender, payload, block, state):
    if len(payload) < 36: return  # 4 + 32

    lock_id = int.from_bytes(payload[0:4], 'big')
    if lock_id == 0: return
    if lock_id not in state.cog_locks: return

    preimage = payload[4:36]
    lock = state.cog_locks[lock_id]

    # Claim: recipient claims with preimage before timeout
    if block.height < lock['timeout_height']:
        # Verify sender is authorized recipient
        if lock['recipient_domain_id'] not in state.domain_by_id: return
        domain = state.domain_by_id[lock['recipient_domain_id']]
        if domain.owner != sender and domain.delegate != sender: return

        # Verify preimage
        if sha256(preimage) != lock['condition']: return

        # Claim succeeds
        state.cogcoin_balances[sender] += lock['amount']

    # Reclaim: locker reclaims after timeout
    elif block.height >= lock['timeout_height']:
        if sender != lock['locker']: return
        state.cogcoin_balances[sender] += lock['amount']

    else:
        return

    # Remove resolved lock
    del state.cog_locks[lock_id]
    state.active_lock_count -= 1
    state.total_lock_cog -= lock['amount']

# Handlers not shown above:
#
# process_mine:            Section 5.1.2 rules 1–7 (collect into mining_pending; scoring/settlement in process_block above)
# process_cog_transfer:    Section 5.2.3
# process_domain_anchor:   Section 5.8.3 (8 steps including founding message decode via decode_sentence_wasm)
# process_rep_commit:      Section 5.13.3 (self-commitment vs third-party routing, plus review decode)
# process_rep_revoke:      Section 5.14.3 (4 steps plus review decode)
# process_domain_transfer: Section 5.5.3
# process_domain_sell:     Section 5.6.3
# process_domain_buy:      Section 5.7.3
# process_field_reg:       Section 5.10.5
# process_data_update:     Section 5.11.3
# process_set_endpoint:    Section 5.12.3
# process_set_canonical:   Section 5.15.3
# process_set_delegate:    Section 5.16.3
# process_set_miner:       Section 5.17.3
# process_pq_commit:       Section 5.18.3
#
# These handlers follow the same pattern: validate inputs, check authorization,
# mutate state, update XOR fingerprints. The normative sections above are
# authoritative. This pseudocode is illustrative, not a complete implementation.

14. Appendix C: Recommended Query Interface

The indexer state machine (Section 7) specifies what state an indexer holds. This appendix specifies how applications and agents should query that state. Implementations MAY extend this interface but MUST support these core queries for ecosystem interoperability.

Historical query support. The minimal consensus state defined in Section 7 is sufficient to determine current protocol state. Some convenience queries, however, require additional retained history or deterministic replay of past blocks and transactions. In particular, resolved-lock status and historical mining results are not guaranteed by the minimal consensus state alone. Implementations MAY support such queries either by retaining supplemental historical metadata as blocks are processed, or by replaying the relevant historical blocks on demand. If an implementation does not support one of these methods, it SHOULD return null / unsupported rather than fabricate partial history.

Identity parameters. Several queries below take identity input parameters — labeled address (e.g., get_balance(address), list_domains_by_owner(address), resolve_canonical(address)) or named for a specific role (e.g., locker in list_active_locks). Implementations MUST accept both forms of identity input: lowercase hex-encoded scriptPubKey bytes (the protocol's canonical identity per Section 4.1.1) and rendered Bitcoin address strings (bech32, base58check, or the appropriate encoding for the script type). When a rendered address is provided, the implementation resolves it to scriptPubKey bytes before processing. For nonstandard scriptPubKeys that have no canonical rendered form (V-041 through V-045), hex is the only valid input. Hex input is always unambiguous; rendered address input is a convenience for standard script types.

Domain queries:

  • lookup_domain(name) -- Resolve a human-readable name to its full record: domain_id, owner_scriptpubkey, anchored, anchor_height, reg_height, endpoint_hex, delegate_scriptpubkey, miner_scriptpubkey, pq_hash, founding_message, self_stake, supported_stake, total_supported, total_revoked.

    The endpoint_hex field is the raw URI bytes published via SET_ENDPOINT as lowercase hex, or null if no endpoint has been set. Implementations SHOULD additionally include endpoint_decoded as a UTF-8 JSON string when the bytes are valid UTF-8 (Section 14.2). Not every domain serves an endpoint -- endpoint_hex may be null even for anchored domains.

    The anchor_height is the block height at which the domain's DOMAIN_ANCHOR was processed; reg_height is the block height at which the DOMAIN_REG was processed. The pq_hash field is null when no PQ_COMMIT has been issued for the domain.

    The founding_message field contains the decoded text from the DOMAIN_ANCHOR transaction, or null if the founding message was absent, the OP_RETURN was too short, canonical decoding failed, or the domain is unanchored (Section 5.8.7).

  • lookup_domain_by_id(domain_id) — Reverse lookup by numeric ID.

  • list_domains_by_owner(address) — All domains owned by an address.

  • resolve_canonical(address) — The canonical domain for an address. Returns the domain_id from the canonical_domain map, or null if no entry exists.

  • list_children(domain_name) — All subdomains whose immediate parent is the given domain name (i.e., domains where the substring before the last hyphen equals the given name). Returns: list of (domain_id, domain_name, owner_scriptpubkey, anchored). Enables namespace browsing and fleet discovery. Returns only direct children, not all descendants.

  • list_descendants(domain_name) — All domains at any depth whose namespace traces back to the given domain (i.e., domain names that start with {domain_name}-). Returns: list of (domain_id, domain_name, owner_scriptpubkey, anchored, depth). OPTIONAL — can be derived from recursive list_children calls.

  • get_parent(domain_name) — If the domain name contains a hyphen, returns the immediate parent prefix (substring before the last hyphen) and the full record of the domain it resolves to. For domains without a hyphen, returns null.

  • list_domains_by_data_format(format_string) — All domains whose data-format field matches the given identifier. Domains that register a mutable field named data-format and write a descriptive string (e.g., "price-oracle", "identity", "attestation") enable format-based discovery. This is an application-layer convention, not enforced by the protocol. OPTIONAL — requires a secondary index on the data-format field value.

Field and data queries:

  • list_fields(domain_id) — All fields registered under a domain: field_id, name, permanent.
  • read_domain_data(domain_id, field_id) — Read a field entry: returns {format, value_hex, value_decoded} or null if no value is stored. format is the two-character hex format byte. value_hex is the raw stored bytes as a lowercase hex string (always present, always authoritative). value_decoded is a format-aware interpretation (see Section 14.2, "Field data encoding") or null if the implementation does not decode this format.
  • read_domain_data_by_name(domain_id, field_name) — Read a field entry by name: returns the same {format, value_hex, value_decoded} triple as read_domain_data (convenience: combines field name lookup with data read).
  • lookup_field_by_name(domain_id, field_name) — Resolve a field name to its field_id.

Reputation queries:

  • get_reputation(domain_id) — Full reputation summary: self_stake, supported_stake, supporter_count, total_supported, total_revoked, revocation_ratio, domain_age_blocks.
    • supporter_count: the number of distinct source domains with non-zero net_support entries targeting this domain — current active supporters, not all-time unique supporters.
    • revocation_ratio: total_revoked / total_supported (JSON number per Section 14.2). 0 if total_supported is 0.
    • domain_age_blocks: current_height - anchor_height — the number of blocks since the domain became reputation-eligible. Null if the domain is not anchored.
  • list_supporters(domain_id) — All domains actively supporting this domain, with net_support amounts.
  • list_supported_by(domain_id) — All domains supported by a given domain.
  • get_reviews(domain_id) — All decoded Coglex reviews attached to REP_COMMIT and REP_REVOKE transactions targeting this domain. Returns: list of (source_domain_id, type [commit|revoke], amount, review_text, block_height, txid). Reviews that failed canonical decoding are stored as null and excluded from results. Conforming indexers MUST store review data (Section 5.13.4).

Balance queries:

  • get_balance(address) — Cogcoin balance.

Listing queries:

  • get_listing(domain_id) — If the domain has an active DOMAIN_SELL listing, returns the listed price and seller_scriptpubkey. Returns null if no listing exists.
  • list_listings() — All active DOMAIN_SELL listings: domain_id, domain_name, price_cogtoshi, seller_scriptpubkey. Agents scanning for domains to buy need this query.

Conditional lock queries:

  • get_lock(lock_id) — Lock details for an active lock: locker_scriptpubkey, amount, condition, timeout_height, recipient_domain_id, creation_height, status=active. For resolved locks, implementations MAY additionally return claimed or reclaimed status and any retained resolution metadata, but this requires either resolved-lock history retention or replay. Minimal consensus state does not require permanent storage of resolved lock metadata.
  • list_active_locks(locker?, recipient_domain_id?) — Active locks, optionally filtered by locker scriptPubKey (hex or rendered address per Identity parameters) and/or recipient domain ID. Both parameters are optional and may be combined.
  • list_active_locks_by_domain(domain_id) — All active locks where this domain is the recipient.
  • list_resolved_locks_by_domain(domain_id) — OPTIONAL historical query. All resolved locks where this domain was the recipient, with resolution metadata (claimed or reclaimed, resolution block height). Implementations MAY answer this query from retained lock history or by replaying historical blocks. Minimal consensus state does not require permanent storage of resolved lock metadata.

Mining queries:

  • get_block_winners(height) — OPTIONAL historical query. Returns mining results for a specific block: rank, domain_id, credited_scriptpubkey, score, sentence_text, reward_cogtoshi. The score field is the canonical_blend value (uint64) encoded as a decimal string, same convention as cogtoshi amounts. Implementations MAY answer this query from retained settlement history or by replaying the block's MINE submissions and re-running canonical settlement. Minimal consensus state does not require permanent storage of winner history, scores, or decoded sentence text after settlement.

Historical data queries (OPTIONAL):

The indexer tracks only the latest value for each data key. Historical values are permanently recorded on the Bitcoin blockchain and can be recovered by scanning earlier blocks. Implementations MAY provide the following convenience queries, but they are not required for interoperability:

  • read_data_history(domain_id, field_id) — All historical values for a field, with block height and txid for each write.
  • get_domain_event_log(domain_id) — Chronological log of all operations affecting a domain (registrations, field adds, commitments, transfers).

Implementations that do not support historical queries SHOULD document this limitation and advise users that full history is always available by re-scanning the blockchain from genesis.

Protocol status queries:

  • get_protocol_stats() — Current protocol-wide counters: total_cog_supply, total_burned_cog, total_minted_cog, bootstrap_remaining, next_domain_id, anchored_domain_count, total_field_count, next_lock_id, active_lock_count, total_lock_cog, total_listing_count, total_self_staked, total_net_supported, canonical_count. These are the scalar state hash fields from Section 7.6, excluding the fixed genesis constants (activation_block and treasury_scriptpubkey) and block_height (which is returned by get_current_height).

Sync queries:

  • get_state_hash(height) — The per-block state hash (Section 7.6) at the given block height. Returns the 32-byte SHA-256 hash, or null if the height has not been processed. This is the primary mechanism for peers to detect indexer divergence.
  • get_current_height() — The most recently processed block height. Peers must know where the indexer is before comparing state hashes.

14.1 Programmatic API

The query interface above defines what to expose, not how. For programmatic access by autonomous agents, implementations SHOULD expose these queries via one or more of the following:

  • JSON-RPC server (recommended) — a local TCP or Unix socket endpoint, analogous to Bitcoin Core's RPC interface. This allows agents running as separate processes to query the indexer without parsing CLI output.
  • REST/HTTP server — a lightweight HTTP API for browser-based or remote access. Appropriate for query-only access; state-changing operations should go through the Bitcoin transaction layer.
  • CLI with --json flag — a minimum viable interface. Every query command MUST support --json output producing structured JSON that can be parsed by calling processes. This is sufficient for single-machine agent deployments.

Implementations MUST support at least the CLI --json interface. JSON-RPC is RECOMMENDED for production agent deployments. The choice of transport is an implementation detail — the query semantics above are normative.

14.2 JSON Encoding Conventions

When producing JSON output (via CLI --json, JSON-RPC, or REST), conforming implementations MUST use the following encoding rules:

Byte strings (SHA-256 hashes, conditions, Coglex payloads, pq_hash): lowercase hex string, no 0x prefix.

Identity fields — all query fields with a _scriptpubkey suffix: owner_scriptpubkey, seller_scriptpubkey, delegate_scriptpubkey, miner_scriptpubkey, locker_scriptpubkey, credited_scriptpubkey, and any other field whose underlying value is a scriptPubKey. These MUST be returned as lowercase hex of the raw scriptPubKey bytes, no 0x prefix (the protocol's canonical identity per Section 4.1.1). Implementations SHOULD additionally include a rendered companion field with an _address suffix (e.g., owner_address, delegate_address) containing the human-readable address (bech32, base58check) for standard script types. For nonstandard scriptPubKeys that have no canonical rendered form, the rendered companion is null.

Transaction IDs in query results (e.g., txid in get_reviews, read_data_history): lowercase hex string in display byte order (reversed from internal SHA-256d order). This matches Bitcoin Core's RPC convention and format 0x17 (Section 15).

State hashes (get_state_hash): lowercase hex string of the raw SHA-256 output, not reversed. State hashes are not Bitcoin transaction IDs and have no display-order convention.

Cogtoshi amounts (uint64 values representing COG balances, prices, burn totals, lock amounts, reputation amounts, and all uint64 state hash fields including total_cog_supply, total_burned_cog, total_minted_cog, bootstrap_remaining, total_field_count, total_lock_cog, total_self_staked, total_net_supported): JSON string containing the decimal integer. Example: "amount": "1000000000". This avoids precision loss in JavaScript and other environments where JSON numbers are IEEE 754 doubles (safe integer limit 2^53). The rule is type-based: if the underlying state field is uint64, the JSON encoding is a decimal string.

Small integers (domain IDs, field IDs, lock IDs, block heights, and uint32 state hash fields including next_domain_id, next_lock_id, active_lock_count, canonical_count, total_listing_count, anchored_domain_count): JSON number. These are uint32 and always fit within the 53-bit safe integer range.

Ratios (revocation_ratio and any other derived fractional values): JSON number (IEEE 754 double precision). These are query-layer computations, not consensus state. revocation_ratio is computed as total_revoked / total_supported; 0 when total_supported is 0.

Format bytes: two-character lowercase hex string, no prefix. Example: "format": "0f".

Text (domain names, field names, decoded founding messages, decoded reviews, decoded sentence text): JSON string. Null if absent or decoding failed.

Endpoint: returned as twin fields. endpoint_hex (MUST) is the raw stored bytes as lowercase hex, or null if no endpoint is set. endpoint_decoded (SHOULD) is a JSON string when the stored bytes are valid UTF-8, or null if absent or not valid UTF-8. The protocol stores endpoint bytes as-is with no encoding validation (Section 5.12.2). Agents that need deterministic results use endpoint_hex.

Field data (read_domain_data, read_domain_data_by_name): the value_hex field is MUST — lowercase hex of the raw stored bytes, identical across all conforming indexers. The value_decoded field is MAY — a format-aware interpretation that implementations provide as a convenience. When present, value_decoded follows these rules by format byte:

  • 0x01 (raw bytes): null. Raw bytes have no declared encoding; value_hex is the only representation.
  • 0x02 (UTF-8 text): JSON string. Null if bytes are not valid UTF-8.
  • 0x03 (unsigned integer): decimal string.
  • 0x04 (signed integer): decimal string (signed).
  • 0x05 (fixed-point decimal): JSON string of the decimal representation. The output MUST preserve exactly scale fractional digits (e.g., scale=2, value=4523100 → "45231.00"). Trailing fractional zeros are not stripped. If the integer value is zero, the output is "0." followed by scale zeros. Negative zero is not permitted. If scale is 0, the output is the plain integer as a decimal string with no decimal point.
  • 0x07 (timestamp): JSON number (Unix epoch seconds).
  • 0x09 (JSON): parsed JSON value (object, array, string, number, boolean, or null). Null if bytes are not valid JSON.
  • 0x0A (Cogcoin address): {"scriptpubkey": "hex", "address": "rendered_or_null"}. The scriptpubkey field is the raw bytes as lowercase hex. The address field is the rendered human-readable address for standard script types, or null for nonstandard scriptPubKeys.
  • 0x0B (Cogcoin amount): decimal string (cogtoshi).
  • 0x0C (Bitcoin amount): decimal string (satoshi).
  • 0x0D (domain reference): JSON number (domain ID).
  • 0x0E (field reference): {"domain_id": N, "field_id": M}.
  • 0x0F (Coglex text): JSON string of decoded text via decode_sentence_wasm. Null if canonical decoding fails (the round-trip check: the stored value is normalized to 60 bytes per Appendix D — right-padded if short, truncated if long — then re-encoding the decoded token IDs must produce byte-identical output to that normalized 60-byte input; see Section 5.1.6).
  • 0x1D (boolean): JSON boolean.
  • 0x1F (semver): JSON string "major.minor.patch".
  • 0x06 (SHA-256 hash pointer): lowercase hex string (32 bytes → 64 hex chars).
  • 0x08 (timestamp + value): {"timestamp": N, "nested_format": "hex", "nested_value_hex": "hex", "nested_value_decoded": ...}. timestamp is a JSON number (Unix epoch seconds). nested_format is the two-character hex format byte. nested_value_hex is the nested value as hex. nested_value_decoded follows the same decoding rules recursively, or null if the nested format is not decoded.
  • 0x10 (price feed): {"timestamp": N, "scale": N, "price": "decimal_string"}. timestamp is a JSON number (Unix epoch seconds). scale is a JSON number (uint8). price is the int64 value as a decimal string. The actual price is price / 10^scale. Only the first 17 bytes (8 + 1 + 8) are decoded; trailing bytes are application-defined metadata and not included in value_decoded.
  • 0x11 (service endpoint): JSON string (UTF-8 URI). Null if bytes are not valid UTF-8.
  • 0x12 (public key): lowercase hex string (33 bytes → 66 hex chars).
  • 0x13 (signature): {"algorithm": "schnorr"|"ecdsa_der"|"unknown", "signature_hex": "hex"}. Algorithm derived from the tag byte (0x01 = "schnorr", 0x02 = "ecdsa_der", other = "unknown"). signature_hex is the bytes after the tag byte (not including it). Null if fewer than 2 bytes stored, or if tag is 0x01 and exactly 64 bytes do not follow.
  • 0x14 (URL): JSON string (UTF-8). Null if bytes are not valid UTF-8.
  • 0x15 (DNS hostname): JSON string (ASCII hostname).
  • 0x16 (email address): JSON string (ASCII email).
  • 0x17 (Bitcoin txid): lowercase hex string in display byte order (64 hex chars).
  • 0x18 (Ethereum address): lowercase hex string (20 bytes → 40 hex chars, no 0x prefix).
  • 0x19 (Ethereum TX hash): lowercase hex string (32 bytes → 64 hex chars, no 0x prefix).
  • 0x1A (IPFS CID): lowercase hex string of raw CIDv1 bytes. Implementations MAY additionally return a base32 or base58btc multibase-encoded CID string.
  • 0x1B (Arweave TX ID): lowercase hex string (32 bytes → 64 hex chars).
  • 0x1C (Nostr event ID): lowercase hex string (32 bytes → 64 hex chars).
  • 0x1E (alternative public key): {"algorithm": "ed25519"|"x25519"|"secp256r1"|"unknown", "key_hex": "hex"}. Algorithm derived from the tag byte (0x01 = "ed25519", 0x02 = "x25519", 0x03 = "secp256r1", other = "unknown"). key_hex is the bytes after the tag byte (not including it). Null if fewer than 2 bytes stored, or if the byte count after the tag does not match the expected key size for known algorithms (32 for ed25519/x25519, 33 for secp256r1).
  • 0x20 (geographic coordinates): {"latitude": N, "longitude": N}. Both JSON numbers, decoded as int32 / 10^7.
  • 0x21 (duration / TTL): JSON number (uint32 seconds).
  • 0x22 (EVM chain address): {"chain_id": N, "address_hex": "hex"}. chain_id is a JSON number (uint32). address_hex is the 20-byte address as lowercase hex.
  • 0x23 (EVM chain TX hash): {"chain_id": N, "tx_hash_hex": "hex"}. chain_id is a JSON number (uint32). tx_hash_hex is the 32-byte hash as lowercase hex.
  • 0x24 (signed attestation): {"attester_pubkey_hex": "hex", "value_hex": "hex"}. attester_pubkey_hex is the 33-byte compressed secp256k1 public key. value_hex is the remaining bytes.
  • All other formats (including 0x01, 0x250xFE, 0xFF): null.

Malformed value handling. For all value_decoded rules above, if the stored bytes do not meet the format's structural requirements, value_decoded is null. The value_hex field is always returned regardless. Specific null conditions by category:

  • Fixed-width formats (0x06, 0x12, 0x17, 0x18, 0x19, 0x1B, 0x1C, 0x1F): return null if the byte count does not match exactly (32, 33, 32, 20, 32, 32, 32, 3 respectively).
  • Composite formats (0x05, 0x08, 0x0E, 0x10, 0x20, 0x22, 0x23, 0x24): return null if insufficient bytes are present to parse all fields. For 0x05, exactly 9 bytes are required (1 scale + 8 int64).
  • Tagged formats (0x13, 0x1E): have per-format null conditions specified in their individual rules above.
  • Text formats (0x02, 0x09, 0x11, 0x14, 0x15, 0x16): return null if the bytes are not valid for the declared encoding (UTF-8, JSON, URI, ASCII hostname, ASCII email respectively).
  • Integer formats (0x03, 0x04, 0x07, 0x0B, 0x0C, 0x0D, 0x21): decode whatever bytes are present (1-8 bytes for int64/uint64 targets, 1-4 bytes for uint32 targets, zero-extended or sign-extended to the target width). Zero stored bytes return null.
  • Boolean (0x1D): return null if the stored value is not exactly 1 byte, or if the byte is not 0x00 or 0x01.
  • Address and variable-length byte formats (0x0A, 0x1A): return null if zero bytes are stored.
  • Coglex (0x0F): has its own normalization and WASM decode rules specified separately; returns null if canonical decoding fails.

This rule ensures that two conforming indexers that both implement value_decoded for a given format produce identical results — either the same decoded value or both null.

The value_hex field eliminates encoding ambiguity: two conforming indexers always agree on value_hex. They may differ on value_decoded (one implements it, one returns null for a given format), but the authoritative raw bytes are identical. Agents that need deterministic cross-indexer results use value_hex and decode locally. Implementations MAY extend decoding to additional format bytes beyond those listed above.

Booleans (anchored, permanent): JSON boolean.

Null: JSON null for absent optional fields (no endpoint_hex, no delegate_scriptpubkey, no miner_scriptpubkey, no pq_hash, no founding message, null decoded review, unresolved canonical).


15. Appendix D: Format Byte Definitions

Every DATA_UPDATE includes a format byte (Section 5.11.1) that is stored as a first-class field in domain_data alongside the value. The format byte tells applications how to interpret the value bytes without parsing the value itself. The indexer stores any format value (0x010xFF) without validation — it does not check that the value bytes conform to the declared format. Applications interpret the format; the protocol preserves it.

General principles:

  • Format 0x00 is reserved for "clear" at the protocol level and never appears in stored data.
  • Multi-byte integers use big-endian byte order (matching the rest of the Cogcoin protocol).
  • Timestamps are Unix epoch seconds as int64 (8 bytes, valid for approximately 292 billion years). A protocol designed for permanence should not have a timestamp that overflows.
  • Hash pointers are raw 32-byte SHA-256 digests with no prefix (the format byte on the entry indicates that the content is a hash pointer).
  • Cogcoin address values are raw scriptPubKey bytes (variable length, matching the address identity model in Section 4.1.1).

Defined formats:

The following format assignments are canonical. Applications that encounter these format bytes MUST interpret the value bytes according to these definitions. Using a defined format byte with non-conforming value bytes is a protocol violation at the application layer — the indexer will store the entry, but consumers will misinterpret it.

Format bytes are organized into semantic groups. Within each group, related types are adjacent to simplify range-based filtering.

Data primitives (0x000x09):

FormatNameValue bytes
0x00Clear (protocol)N/A — deletes the field entry
0x01Raw bytesUninterpreted bytes (no declared encoding)
0x02UTF-8 textRaw UTF-8 string (no null terminator)
0x03Unsigned integerBig-endian uint, 1–8 bytes
0x04Signed integerBig-endian int, 1–8 bytes (two's complement)
0x05Fixed-point decimal1 byte scale + big-endian int64 (value = int / 10^scale)
0x06SHA-256 hash pointer32 bytes raw hash
0x07Timestampint64 Unix epoch seconds
0x08Timestamp + valueint64 timestamp (8 bytes) + uint8 nested format byte + remaining bytes as value interpreted per that format byte
0x09JSON (compact)UTF-8 JSON with no whitespace

Cogcoin protocol types (0x0A0x0F):

FormatNameValue bytes
0x0ACogcoin addressRaw scriptPubKey bytes (variable length)
0x0BCogcoin amount1–8 bytes uint64 big-endian cogtoshi
0x0CBitcoin amount1–8 bytes uint64 big-endian satoshi
0x0DDomain reference4 bytes (uint32 big-endian domain ID)
0x0EField reference8 bytes (uint32 big-endian domain ID + uint32 big-endian field ID)
0x0FCoglex textExactly 60 bytes: 40 Coglex token IDs at 12 bits each, big-endian, produced by encode_sentence_wasm; trailing value bytes beyond 60 reserved, SHOULD be 0x00

Compound application types (0x100x11):

FormatNameValue bytes
0x10Price feedint64 timestamp + uint8 scale + int64 price (value = int / 10^scale); trailing bytes are application-defined metadata
0x11Service endpointUTF-8 URI

Cryptographic types (0x120x13):

FormatNameValue bytes
0x12Public key33-byte compressed secp256k1 public key
0x13Signature1-byte algorithm tag (0x01 = Schnorr, 0x02 = DER ECDSA) + signature bytes. Tag 0x01: exactly 64 bytes follow (32-byte R + 32-byte S). Tag 0x02: DER-encoded ECDSA signature (variable length, no sighash byte).

Web (0x140x16):

FormatNameValue bytes
0x14URLUTF-8 URL (general-purpose web link)
0x15DNS hostnameASCII hostname (no scheme, no path)
0x16Email addressASCII email address

Blockchain references (0x170x19, 0x220x23):

FormatNameValue bytes
0x17Bitcoin txid32 bytes, display byte order
0x18Ethereum address20 bytes raw (Keccak-derived, no checksum encoding)
0x19Ethereum TX hash32 bytes
0x22EVM chain address4 bytes chain ID (uint32 big-endian) + 20 bytes address
0x23EVM chain TX hash4 bytes chain ID (uint32 big-endian) + 32 bytes transaction hash

Formats 0x22 and 0x23 extend the Ethereum-specific formats (0x18, 0x19) with an explicit EIP-155 chain ID prefix. As agents operate across multiple EVM-compatible chains (Ethereum mainnet, Base, Arbitrum, Optimism, Polygon), consumers cannot determine which chain a 0x18 address refers to without out-of-band context. The chain-prefixed formats resolve this: one field, one format byte, unambiguous chain + address.

Format 0x18/0x19 are not deprecated — they remain appropriate when the chain context is unambiguously Ethereum mainnet. Applications encountering 0x18 SHOULD assume Ethereum mainnet (chain ID 1) unless the field name provides explicit chain context. The uint32 range covers all currently assigned EIP-155 chain IDs. Chain ID 0 is reserved and MUST NOT be used.

Common chain IDs: Ethereum mainnet (1), Base (8453), Arbitrum One (42161), Optimism (10), Polygon (137).

Attestation types (0x24):

FormatNameValue bytes
0x24Signed attestation33 bytes compressed secp256k1 public key + remaining bytes as value

Format 0x24 standardizes cross-domain attestations. The domain's owner or delegate publishes a value that includes a third-party's compressed secp256k1 public key, signaling: "the entity identified by this pubkey attests to this value." Maximum attested value: 67 - 33 = 34 bytes. The format byte declares structure, not validity — the indexer stores the entry without verifying any relationship between the attester pubkey and the value bytes.

Verification is an application-layer concern: consumers resolve the attester pubkey to a domain through application-level identity services, check the attester's reputation, and verify against application-specific criteria.

The cryptographic signature proving the attestation is served off-chain — a Schnorr signature (64 bytes) plus the attester pubkey (33 bytes) totals 97 bytes, exceeding the 67-byte DATA_UPDATE maximum before a single byte of attested value. The on-chain pubkey makes the attestation discoverable and attributable; the off-chain signature makes it verifiable.

A domain accumulating attestations from multiple parties registers separate fields per attester (e.g., audit-by-alpha, audit-by-beta) to preserve history, or uses a single mutable field for the latest attestation.

Decentralized storage and messaging (0x1A0x1C):

FormatNameValue bytes
0x1AIPFS CIDRaw CIDv1 bytes (self-describing via multicodec/multihash, variable)
0x1BArweave TX ID32 bytes
0x1CNostr event ID32 bytes (hex-decoded event ID)

Application utilities (0x1D0x21):

FormatNameValue bytes
0x1DBoolean1 byte (0x00 = false, 0x01 = true)
0x1EAlternative public key1-byte algorithm tag + key bytes. Tags: 0x01 = Ed25519 (32 bytes), 0x02 = X25519 (32 bytes), 0x03 = secp256r1 (33 bytes compressed). Tags 0x04–0xFE undefined.
0x1FSemver3 bytes (major, minor, patch as uint8)
0x20Geographic coordinates8 bytes (latitude x 10^7 + longitude x 10^7, two int32 big-endian)
0x21Duration / TTL4 bytes (uint32 seconds)

Reserved and application-specific:

FormatNameValue bytes
0x250xFEUndefinedNo assigned meaning
0xFFApplication-specificInterpretation defined by the field name or domain

Formats 0x250xFE have no assigned meaning. Applications needing a novel format should use 0xFF (application-specific, interpreted by field name or domain convention). If community conventions emerge around undefined format bytes, they may be documented in future editions of the format table — but the protocol does not enforce format byte semantics, so no assignment carries consensus weight.

Design notes:

The Cogcoin protocol types (0x0A0x0F) let the protocol reference itself: addresses, amounts, domains, fields, and natural language. These are the building blocks for cross-domain linking, delegation, and on-chain data graphs.

Cogcoin amount (0x0B) and Bitcoin amount (0x0C) are semantically distinct from unsigned integer (0x03) — the format byte carries the denomination, so consumers scanning fields across thousands of domains can identify every price, fee, and bounty without parsing field names.

Coglex text (0x0F) uses the same 12-bit token encoding as MINE sentence payloads (Section 5.1) and REP_COMMIT/REP_REVOKE reviews (Section 5.13.4). Transaction constructors SHOULD produce 0x0F values by calling encode_sentence_wasm, which always produces exactly 60 bytes (40 token slots at 12 bits each, with unused slots zero-padded) — the same fixed-width encoding used for MINE sentences, founding messages, and reviews. At the DATA_UPDATE maximum of 67 value bytes, the first 60 bytes are the Coglex payload and the remaining 7 bytes are reserved and SHOULD be 0x00.

Conforming indexers serving decoded text for 0x0F fields MUST use decode_sentence_wasm. If the stored value is shorter than 60 bytes, the indexer MUST right-pad with 0x00 to 60 bytes before calling decode_sentence_wasm. If the stored value exceeds 60 bytes, only the first 60 bytes are decoded; trailing bytes are ignored. If decoding fails the canonical check, the decoded text is null. Trailing zero token IDs are stripped by the Coglex decoder to recover the original token count.

The Coglex vocabulary's BIP-39 base, morphological suffixes, and prefix composition provide expressive English with no profanity and universal machine readability — every agent with the scoring module's WASM binary can decode any 0x0F field deterministically.

Other chains (Solana, Sui, NEAR) use Ed25519; their addresses are public keys stored via the alternative public key format (0x1E) with algorithm tag 0x01, from which consumers derive chain-specific addresses. The EVM cross-chain formats (0x220x23) use an explicit EIP-155 chain ID prefix so consumers can identify the target chain without out-of-band context. The chain-prefixed formats make cross-chain pointers explicit and machine-readable, replacing field-name-based disambiguation that is fragile and non-standard.

Worked examples:

Price feed in 67 bytes: Format 0x10, value: timestamp (8 bytes), scale 0x08 (8 decimal places), price as int64 (8 bytes). Total value: 17 bytes, leaving 50 bytes for additional metadata (source identifier, confidence, sequence number).

Service endpoint in 67 bytes: Format 0x11 (service endpoint), value: UTF-8 URI such as https://api.example.com/v2/oracle. Total value: up to 67 bytes of URI. Applications read the format byte from the domain_data entry to determine how to interpret the value bytes.

Cross-domain delegation: An agent's domain publishes a field reference (0x0E) pointing to another domain's "terms-of-service" field: 4-byte domain ID + 4-byte field ID = 8 bytes. Any consumer can follow the pointer with a single indexer query. Combined with domain reference (0x0D), agents can build on-chain data graphs linking identities, services, and claims.

IPFS content pointer: An agent stores a document on IPFS and publishes the CID (0x1A) as a mutable field. CIDv1 bytes are self-describing — the multicodec and multihash prefixes tell consumers the encoding and hash algorithm. The field can be updated as the agent publishes new versions, while the IPFS network guarantees content integrity.

EVM chain address (cross-chain contract pointer): Agent "atlas" deploys a ZK verifier contract on Base (chain ID 8453 = 0x00002105) at address 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18. The domain owner registers a mutable field base-verifier with format 0x22, value:

00 00 21 05  74 2d 35 cc 66 34 c0 53 29 25 a3 b8 44 bc 9e 75 95 f2 bd 18
[chain=8453] [20-byte address                                              ]

4 bytes chain ID + 20 bytes address = 24 bytes total. Any agent reading this field knows both the chain and the contract address without parsing the field name or maintaining a per-domain chain mapping.

EVM chain TX hash (deployment provenance): The same agent publishes the deployment transaction hash for the verifier contract as a permanent field base-deploy-tx with format 0x23, value: 00 00 21 05 (chain ID 8453) followed by the 32-byte transaction hash (36 bytes total). Any verifier can look up the transaction on the correct chain, inspect the deployment bytecode, and confirm the contract's provenance.

Signed attestation (cross-domain endorsement): Oracle "price-a" independently confirms the BTC/USD price published by oracle "price-b". Oracle "price-b" registers a mutable field price-confirm under its own domain with format 0x24, value: 33 bytes of price-a's compressed pubkey followed by a compact price representation (up to 34 bytes). Any consumer scanning price-b's fields sees the attestation, resolves the attester pubkey to price-a through application-level identity services, checks price-a's reputation, and weights the confirmation accordingly. The full signature proving price-a authorized this attestation is served off-chain by price-a.

Coglex text (domain description): Agent "atlas" publishes a human-readable and machine-parseable description of its service. The domain owner registers a mutable field description with format 0x0F, value: the output of encode_sentence_wasm for "accurate weather data with fast response and stable service" (9 content tokens, 31 zero-padding tokens, 60 bytes total — the same fixed-width encoding as MINE sentences). The DATA_UPDATE OP_RETURN is 73 bytes (13 fixed + 60 value). Any agent can decode the field using decode_sentence_wasm, which strips trailing zero tokens to recover the original 9-token text — no natural language processing, no character encoding ambiguity, no profanity. The same encoding works for status messages, service summaries, and any domain metadata that benefits from structured natural language.


16. Appendix E: Indexer Implementation Pitfalls

This appendix catalogs the consensus-critical implementation details most likely to cause divergence between independently developed indexers. These are not protocol bugs — the specification addresses each one. They are the places where an implementer who reads quickly, or who carries assumptions from other Bitcoin software, will produce a conforming-looking indexer that silently disagrees with the canonical state machine on specific edge cases.

A single disagreement on a single transaction permanently forks the chain. These pitfalls are ordered by estimated real-world risk.

Implementation strategy. The safest implementation approach is to route every consensus-relevant mutation through typed helper functions (balance updates, domain updates, lock updates, listing updates, field/data updates, reputation updates, and nullable side-table updates) and verify results against state-transition and settlement conformance vectors at every pitfall boundary listed below.

E.1 Sender Identity Requires Prevout Inspection

Risk: High. Sender identity extraction (Section 4.1.1) uses input 0's prevout scriptPubKey — not the spending transaction's scriptSig, witness data, or any display-format Bitcoin address.

The trap. A naive indexer that examines scriptSig or witness content — without reading the prevout scriptPubKey — will produce incorrect sender identities. An implementer who normalizes addresses, strips type information, or treats multiple scriptPubKeys for the same key material as equivalent will also diverge.

Correct behavior. Always read the prevout scriptPubKey for input 0 and use it directly as the sender identity. Coinbase has no sender and is always ignored. Empty sender scriptPubKeys are ignored. Sender scriptPubKeys longer than 67 bytes are ignored. Equality is raw-byte equality; no type detection, conversion, or normalization is part of consensus.

Recommended test vectors:

  • Cogcoin transaction from P2PKH, P2SH, P2WPKH, and P2TR inputs. Verify sender identity is the prevout scriptPubKey for each.
  • Cogcoin OP_RETURN in coinbase. Verify transaction is ignored.
  • Cogcoin transaction with empty sender scriptPubKey. Verify transaction is ignored.
  • Cogcoin transaction with sender prevout scriptPubKey exceeding 67 bytes. Verify transaction is ignored.
  • Same key material expressed through different script types. Verify they are treated as different identities.

E.2 Wrong Settlement Entry Point: settle_block_wasm Is Non-Consensus

Risk: High. The scoring bundle exports a function named settle_block_wasm, but it is not protocol-consensus settlement.

The trap. An implementer sees an official bundled export that appears to score, rank, deduplicate, and distribute rewards, then uses it directly. This produces valid-looking but non-conforming results. The divergence is silent until a settlement disagreement is compared.

Correct behavior. Conforming indexers use score_sentences_wasm only for sentence scoring. Canonical settlement — deduplication, ranking, tie-breaking, and reward distribution — must follow this document's domain-based rules and the settlement conformance vectors. settle_block_wasm is tooling-only and MUST NOT be used for consensus.

Why it forks.settle_block_wasm uses incompatible address serialization, an incompatible 10-slot rank-weight table, address-based word assignment, address-based deduplication, and sender-address tie-breaks. The protocol uses domain-gated mining identity, the canonical rank weights, and domain-ID tie-breaks.

Recommended test vectors:

  • Two different root domains owned by the same address submit in the same block. Canonical settlement may keep both; address-based deduplication disagrees.
  • A block whose reward splits differ under the old 10-slot rank table versus the canonical table.
  • Two submissions that tie on score and differ only in sender-address versus domain-ID tie-break ordering.

E.3 Deterministic Reward Rounding and Active-Weight Selection

Risk: High. Mining reward distribution is easy to implement incorrectly even after ranking is correct.

The trap. An implementer independently computes floor(block_reward * weight / total_weight) for each winner, uses floating point, forgets to drop absent ranks before computing active weight, or distributes residue by ad hoc rules. All of these diverge from the canonical integer algorithm.

Correct behavior. Discard absent ranks first. Compute total active weight from the present winners only. Then allocate rewards rank-by-rank using integer arithmetic: reward_i = remaining_reward * weight_i // remaining_weight, followed by decrementing both remaining_reward and remaining_weight. No floating point is ever used. Residue remains in the running balance and may all land on the last processed winner.

Recommended test vectors:

  • A 4-winner block matching the worked example in Section 5.1.5.
  • A 3-winner block using active weights [50, 20, 15] to verify absent ranks are discarded.
  • A 1-cogtoshi block where all reward lands on the last processed winner.
  • A block where naive independent flooring produces a different total allocation than the canonical progressive algorithm.

E.4 Mining Reward Settlement Ordering

Risk: High. When processing block H (Section 7.2), the indexer first processes all Cogcoin transactions in block H, then settles mining rewards for block H.

The trap. If an indexer settles block H's mining rewards before processing block H's ordinary transactions, mining credits become visible too early. A miner could spend block H rewards inside block H, which permanently changes balances and later validity checks.

Correct behavior. For each block: (1) process all ordinary Cogcoin transactions in transaction index order, then (2) settle block H's valid MINE submissions, then (3) persist the post-settlement state hash. Miners cannot spend block H rewards until block H+1 at the earliest.

Recommended test vectors:

  • Miner has a winning MINE in block H and a same-block COG_TRANSFER that exceeds their pre-reward balance. Verify the transfer fails in block H and can only succeed in block H+1.

E.5 Blocks Must Be Processed Sequentially, Not Batched by Operation Type

Risk: High. The state machine is a single pass over transactions in block order. Many same-block examples rely on immediate visibility of earlier state changes.

The trap. An implementer batches by opcode type — e.g., "apply all DOMAIN_REG first, then all DOMAIN_ANCHOR, then all FIELD_REG" — or performs multi-phase validation against a stale block-start snapshot. This changes which later transactions are valid.

Correct behavior. Process transactions strictly by their transaction index within the block. State changes from transaction N are visible to transaction N+1 in the same block. Only mining settlement is deferred until after the transaction loop.

Recommended test vectors:

  • Same-block DOMAIN_REG followed by DOMAIN_ANCHOR. Verify anchor succeeds only if registration occurs earlier by index.
  • Same-block FIELD_REG before DOMAIN_ANCHOR. Verify FIELD_REG fails if the domain is not yet anchored.
  • Same-block COG_LOCK then COG_CLAIM. Verify claim succeeds only when the lock already exists earlier in the block.
  • Same-block DOMAIN_REG + DOMAIN_ANCHOR + SET_DELEGATE / SET_MINER / SET_ENDPOINT. Verify later operations depend on prior successful state changes in the same block.

E.6 OP_RETURN Selection Must Follow Steps A–F Exactly

Risk: High. A transaction can contain multiple OP_RETURN outputs. The indexer must identify exactly one Cogcoin output, or none, by following Section 3.1 in order.

The trap. An implementer checks magic before size, stops scanning after an oversized or malformed candidate, accepts OP_FALSE OP_RETURN, tolerates truncated pushdata length fields, or treats a non-push opcode after OP_RETURN as readable data. Another implementer skips those outputs and continues scanning. The first later-valid-output transaction permanently forks the chain.

Correct behavior. Follow Section 3.1 steps A–F exactly. Reject OP_FALSE OP_RETURN. Require a recognized push opcode. Require pushdata length fields to be fully present and in-bounds. Apply the 4–80 byte data-size check before checking COG magic. Any output that fails a step is skipped and scanning continues. The first output that passes all steps becomes the Cogcoin payload; no later output is examined.

Recommended test vectors:

  • First OP_RETURN has COG magic and 81 bytes; second OP_RETURN is a valid Cogcoin payload. Verify the first is skipped and the second is processed.
  • First OP_RETURN is non-COG but valid size; second is valid COG. Verify scanning continues to the second.
  • First OP_RETURN has malformed pushdata (declared length overruns script); second is valid COG. Verify the first is skipped.
  • First OP_RETURN has truncated PUSHDATA length bytes; second is valid COG. Verify the first is skipped.
  • First output is OP_FALSE OP_RETURN with valid-looking COG bytes; second is real OP_RETURN with valid COG bytes. Verify the first is skipped.

E.7 Blockhash Byte Order

Risk: Medium. The MINE payload's 4-byte blockhash fragment uses Bitcoin's internal byte order, not the display order shown by Bitcoin Core RPCs.

The trap. An implementer copies bytes 0–3 from the human-readable RPC blockhash string. For modern blocks this is often 0x00000000..., producing valid-looking but incorrect fragment checks.

Correct behavior. Use the raw internal SHA256d byte order. The fragment is bytes 0–3 of the internal representation, not bytes 0–3 of the display-order hex string.

Recommended test vectors:

  • A referenced block whose display-order first 4 bytes differ from internal-order first 4 bytes. Verify only internal order passes.

E.8 DOMAIN_ANCHOR Side Effects

Risk: High. DOMAIN_ANCHOR appears simple, but it is a multi-effect state transition.

The trap. An implementer sets anchored = true and records anchor_height, but forgets listing cancellation, canonical-domain initialization, bootstrap pool handling, or the corresponding counters and XOR fingerprints.

Correct behavior. DOMAIN_ANCHOR performs all required side effects in Section 5.8.3: set anchored = true, record anchor_height, increment anchored_domain_count, update domain_xor, cancel any active DOMAIN_SELL listing, initialize canonical domain when needed, and for root domains credit a bootstrap award equal to min(10_000_000, bootstrap_remaining) while decrementing bootstrap_remaining, incrementing total_cog_supply, and updating balance_xor.

A second trap. Bootstrap exhaustion is transaction-order dependent. Later anchors in the same block can receive a partial award or zero.

Recommended test vectors:

  • Root DOMAIN_ANCHOR with active listing. Verify listing is canceled and listing_xor updates.
  • First anchor by an address with no canonical domain. Verify canonical entry is created.
  • Three root anchors in one block when bootstrap_remaining covers only 1.5 awards. Verify full / partial / zero award behavior by transaction order.
  • Subdomain anchor. Verify no bootstrap award.

E.9 Subdomain Parent Resolution Uses Last Hyphen

Risk: High. The parent prefix for subdomain registration is the substring before the last hyphen, not the first.

The trap. An implementer splits on the first hyphen, allowing oracle to mint oracle-weather-tokyo directly and bypass oracle-weather.

Correct behavior. Find the last occurrence of - in the domain name. The substring before it is the parent prefix. This only diverges on names containing two or more hyphens.

Recommended test vectors:

  • Register oracle, then oracle-weather, then attempt oracle-weather-tokyo. Verify the parent is oracle-weather, not oracle.
  • Attempt a gap-jump where only the root parent exists. Verify registration fails.

E.10 Domain-Gated Mining Identity

Risk: High. MINE uses a mining root domain ID from the payload as the identity for authorization, word assignment, per-block deduplication, and tie-breaking.

The trap. An implementer uses sender address instead of domain ID, or allows any anchored domain including subdomains, or fails to honor the owner / delegate / designated-miner authorization rule.

Correct behavior. Parse the mining root domain ID from payload bytes 4–7. Validate: domain ID is nonzero and existing, the domain is anchored, the name is root-level (no hyphen), and sender is the domain's owner, delegate, or designated miner. Use domain_id — not sender identity — in BIP-39 word assignment, per-block deduplication, and tie-breaking.

Recommended test vectors:

  • Same address submits for two different authorized root domains in one block. Verify both can win separate slots.
  • Same address submits twice for the same domain. Verify per-domain dedup keeps the higher score only.
  • MINE by delegate succeeds. MINE by designated miner succeeds. Rewards credit the actual sender.
  • MINE for unanchored domain, subdomain, or unauthorized sender is rejected.

E.11 Domain-to-Domain Reputation Identity

Risk: High. REP_COMMIT and REP_REVOKE are keyed by (source_domain_id, target_domain_id), not by sender address.

The trap. An implementer routes "self-commitment" by checking whether the sender owns the target domain, rather than checking whether source_domain_id == target_domain_id. That diverges whenever one address controls multiple domains.

Correct behavior. Parse source_domain_id from the payload. Validate that the source domain is anchored and that the sender is the source domain's owner or delegate. Route source == target to self-stake and source != target to third-party net support. support_xor serialization uses exactly source_domain_id || target_domain_id || net_support in fixed-width big-endian integers.

Recommended test vectors:

  • Same sender owns domains A and B; REP_COMMIT source=A target=B. Verify it is third-party support, not self-stake.
  • REP_COMMIT source=A target=A. Verify it is self-stake and irrevocable.
  • REP_REVOKE source=A target=A. Verify it is rejected.
  • Delegate of source domain performs REP_COMMIT and REP_REVOKE successfully.

E.12 DATA_UPDATE Validation Order Is Consensus-Critical

Risk: High. DATA_UPDATE is not just field existence plus fee check. The numbered validation and execution order in Section 5.11.3 is consensus-critical.

The trap. An implementer applies format semantics before the permanent-field freeze rule, treats non-zero format with zero value bytes as an empty write, routes clears through the write-fee / balance-check path, or treats clear-on-empty and clear-on-frozen as the same case. These produce different stored state and different burned-fee behavior.

Correct behavior. Evaluate the rules in the specified order. Permanent-field freeze is checked before format semantics. Clear is any DATA_UPDATE whose format byte is 0x00; trailing bytes after the format byte are ignored. Non-zero format with zero value bytes is a validation failure: it stores nothing, burns no fee, and does not perform the write balance check. Clear on an empty field is a no-op and remains free. Clear on a frozen permanent field is rejected because the field has already been written. The write fee and balance check apply only to non-zero format with >=1 value bytes.

Recommended test vectors:

  • Permanent field: first write succeeds, second write rejected.
  • Permanent field: clear on empty field is allowed no-op; later first write still succeeds.
  • Permanent field: clear after first write is rejected.
  • Non-zero format with zero value bytes is ignored, stores nothing, burns no fee, and does not require balance.
  • Sender with zero balance submits clear. Verify it succeeds as a free no-op or free delete, depending on prior state.
  • Sender with zero balance submits non-zero format with zero value bytes. Verify it is ignored and burns nothing.
  • Mutable field: write, overwrite, clear, and clear-on-empty all behave as specified.
  • DATA_UPDATE with format byte 0x00 followed by trailing non-zero bytes (padded clear). Verify the clear succeeds and trailing bytes are ignored — the operation deletes the field value and burns no fee.

E.13 Ordinary Bitcoin Outputs Have Operation-Specific Meaning Only

Risk: Medium. Most ordinary Bitcoin outputs have no Cogcoin meaning. The few cases that do matter are operation-specific.

The trap. An implementer writes generic "payment-output" logic, sums multiple treasury outputs for root DOMAIN_REG, compares rendered addresses instead of raw scriptPubKey bytes, treats BTC seller outputs as part of DOMAIN_BUY settlement, or applies treasury-payment checks to subdomain registrations.

Correct behavior. Root DOMAIN_REG for a no-hyphen domain requires at least one output whose scriptPubKey is byte-identical to the stored treasury scriptPubKey and whose value meets the required BTC price. If multiple outputs match the treasury scriptPubKey, each is checked independently — amounts are not summed across outputs. Overpayment is accepted. Subdomain registrations burn COG and do not use treasury payment outputs. DOMAIN_BUY is settled entirely in Cogcoin state and ignores ordinary BTC outputs to the seller.

Recommended test vectors:

  • Root DOMAIN_REG with two smaller treasury outputs whose sum reaches the price. Verify it fails if no single output satisfies the rule.
  • Root DOMAIN_REG with one qualifying treasury output and unrelated additional BTC outputs. Verify it passes.
  • Root DOMAIN_REG with one overpaying treasury output. Verify it passes with no special refund behavior.
  • Subdomain registration with a treasury payment output present. Verify it is judged only by subdomain rules.
  • DOMAIN_BUY with a BTC output to the seller. Verify Cogcoin settlement is unchanged.

E.14 Genesis Activation Depends on Byte-Exact Parameters and Activation-Block Ordering

Risk: High. Startup activation is consensus-critical and easy to implement sloppily.

The trap. An implementer parses and reserializes the genesis parameters JSON before hashing, activates on the first 0x00 regardless of validity, processes transactions earlier than the GENESIS transaction within the activation block, or silently ignores treasury-consistency failure at activation.

Correct behavior. Hash the canonical genesis parameters file as raw bytes. Activate only on the first valid 0x00 at or after the genesis height. Validity includes both activation gates from Section 6: the GENESIS payload's 32-byte parameters hash must match the SHA-256 of the canonical genesis parameters JSON, and the treasury scriptPubKey derived from the GENESIS sender must match the scriptPubKey obtained by decoding treasury_address from that same genesis parameters JSON. In the activation block, transactions at indexes less than or equal to the GENESIS transaction index are ignored; processing starts strictly after activation.

Recommended test vectors:

  • Semantically identical JSON with different whitespace. Verify hash mismatch prevents activation.
  • Earlier malformed 0x00, later valid 0x00. Verify only the later valid one activates.
  • 0x00 with matching parameters hash but treasury mismatch. Verify activation fails and scanning continues.
  • Activation block with valid Cogcoin tx before GENESIS tx index and another after. Verify only the later transaction is processed.
  • Alternate genesis parameters file with different raw bytes. Verify protocol never activates.

E.15 COG_LOCK Timeout and Supply Accounting

Risk: Medium. COG_LOCK has two easy consensus mistakes: the timeout boundary and supply accounting.

The trap. An implementer treats the timeout block as still claimable, or burns supply on lock creation / mints supply on lock resolution.

Correct behavior. Claim requires block.height < timeout. Reclaim requires block.height >= timeout. The timeout block is the first reclaimable block. COG_LOCK moves COG from spendable balance into escrow; COG_CLAIM moves it out of escrow. Neither changes total_cog_supply.

Recommended test vectors:

  • Claim at timeout - 1, claim at timeout, reclaim at timeout - 1, reclaim at timeout.
  • COG_LOCK followed by COG_CLAIM. Verify total_lock_cog changes and total_cog_supply does not.
  • Full reorg of COG_LOCK and COG_CLAIM. Verify escrow and balances restore exactly.

E.16 State-Hash Wrapper Discipline and Nullable Side Tables

Risk: Medium. The most common state-hash bugs are not cryptographic — they are missed XOR updates, wrong serialization width, or forgetting that zero / null entries are excluded from nullable side-table fingerprints.

The trap. An implementer updates primary state correctly but forgets to XOR-out the old entry, XORs-in zero values, updates a nullable fingerprint on DOMAIN_ANCHOR null initialization, includes variable-length address renderings instead of raw scriptPubKeys, or mutates support / reputation / data / endpoint / canonical / delegate / miner / PQ commitment side tables without going through a wrapper.

Correct behavior. Every consensus-relevant mutation path must centralize its corresponding fingerprint updates. For overwrite-style maps, XOR-out the old serialized entry before XOR-in the new one. Entries whose committed value is zero or null are omitted from the fingerprint entirely. Serialization widths and key choices must match Section 7.6 exactly.

High-risk families to test explicitly:

  • balance_xor: zero-balance omission, overwrite order, mint/burn/escrow paths.
  • domain_xor: anchored flag and anchor_height changes, owner changes, next_field_id increments on FIELD_REG, name and reg_height included in serialization.
  • listing_xor: create / update / cancel / implicit cancellation on transfer and anchor.
  • lock_xor: COG_LOCK creation and COG_CLAIM resolution, reorg of both, resolved locks exit the fingerprint.
  • field_xor: FIELD_REG creates entry, reorg removes it, permanent flag and name included in serialization.
  • support_xor and reputation_xor: self-commitment versus third-party routing, zero-entry omission, cumulative-counter behavior.
  • data_xor: overwrite versus clear, no-op cases, format byte included in serialization.
  • endpoint_xor, canonical_xor, delegate_xor, miner_xor: null omission, first-entry creation rules, and "initialized to null" on DOMAIN_ANCHOR not changing the fingerprint.
  • pq_xor: one-time write (no overwrite path), reorg XOR-out, entries never exit in forward processing.

Recommended test vectors:

  • Every overwrite path must prove old-entry XOR-out then new-entry XOR-in.
  • Every transition to zero / null must prove XOR-out only, with no XOR-in.
  • Every no-op must prove the fingerprint is unchanged.
  • Every reorg vector must prove the fingerprint returns to the exact pre-change value.

E.17 Domain Existence Before Dereferencing

Risk: Medium. Most operations that take a domain ID from the payload validate ownership or anchored status — checks that implicitly fail on a nonexistent domain. But an implementer who dereferences the domain record before reaching any validation rule will crash on a null lookup.

The trap. An implementer writes domain = domain_by_id[payload_domain_id] as the first line of a handler, then checks domain.owner == sender. If the domain ID is out of range or doesn't exist, the lookup returns null and the ownership check crashes — or worse, a language-specific default that silently passes.

Correct behavior. Before dereferencing any domain ID from the payload, verify: domain ID > 0 (Null ID Rule, Section 3.2) and domain ID < next_domain_id (existence). This check is required by the Null ID Rule and the general payload validation mandate (Section 3.2) and applies to every operation that reads a domain ID. DOMAIN_ANCHOR (Section 5.8.2 rule 1), DATA_UPDATE (Section 5.11.3 rule 3), and MINE (Section 5.1.2 rule 4a) state this explicitly. For other operations (DOMAIN_SELL, DOMAIN_TRANSFER, DOMAIN_BUY, SET_CANONICAL, SET_ENDPOINT, SET_DELEGATE, SET_MINER, FIELD_REG, REP_COMMIT, REP_REVOKE, PQ_COMMIT, PQ_MIGRATE), the check is equally required but implicit in the ownership/anchored validation. Implementers SHOULD check existence as the first step for every domain-ID-bearing operation.

The same applies to field IDs. DATA_UPDATE rule 1 checks the composite key (domain_id, field_id) exists. Operations that reference field IDs should verify the field exists before dereferencing.

Recommended test vectors:

  • COG_LOCK with recipient domain ID = next_domain_id (one past the last registered). Verify ignored.
  • DOMAIN_SELL with domain ID = 0. Verify ignored (Null ID Rule).
  • DOMAIN_SELL with domain ID = next_domain_id. Verify ignored.
  • REP_COMMIT with source domain ID = 0. Verify ignored.
  • REP_COMMIT with target domain ID = next_domain_id. Verify ignored.
  • SET_ENDPOINT with domain ID that was never registered. Verify ignored.
  • PQ_COMMIT with domain ID = next_domain_id (one past the last registered). Verify ignored.
  • PQ_COMMIT with domain ID = 0. Verify ignored (Null ID Rule).
  • PQ_MIGRATE with domain ID = next_domain_id. Verify ignored.
  • PQ_MIGRATE with domain ID = 0. Verify ignored (Null ID Rule).

E.18 Variable-Length Payload Truncation

Risk: High. Six operations contain a length byte (L or N) that declares how many subsequent bytes follow. If the OP_RETURN payload is shorter than the declared length, the indexer must reject the transaction — not read whatever bytes remain.

The trap. An implementer reads the length byte, then reads that many bytes from the payload buffer without checking bounds. In some languages this silently reads zeros or adjacent memory. In others it throws an exception that may be caught and mishandled. Either way, the indexer processes a transaction that a correct implementation would reject.

Affected operations and their length-prefixed fields (all sizes are payload-relative — bytes after the 4-byte header+op prefix):

  • COG_TRANSFER (Section 5.2): payload byte 8 = recipient scriptPubKey length L. Required: payload >= 9+L bytes.
  • DOMAIN_TRANSFER (Section 5.5): payload byte 4 = recipient scriptPubKey length L. Required: payload >= 5+L bytes.
  • SET_DELEGATE (Section 5.16): payload byte 4 = delegate scriptPubKey length L. Required: payload >= 5+L bytes.
  • SET_MINER (Section 5.17): payload byte 4 = miner scriptPubKey length L. Required: payload >= 5+L bytes.
  • DOMAIN_REG (Section 5.4): payload byte 0 = domain name length N. Required: payload >= 1+N bytes.
  • FIELD_REG (Section 5.10): payload byte 5 = field name length N. Required: payload >= 6+N bytes.

Correct behavior. After reading the length byte, verify that enough bytes remain in the payload before reading the variable-length field. If insufficient, the transaction is silently ignored. Section 3.2 mandates this universally; the per-operation validation rules restate it for self-containment.

Recommended test vectors (OP_RETURN sizes are total including the 4-byte header+op; payload = total - 4):

  • COG_TRANSFER with L = 34 but OP_RETURN is only 20 bytes total (16 payload bytes, need 43). Verify ignored.
  • DOMAIN_TRANSFER with L = 22 but OP_RETURN is only 12 bytes total (8 payload bytes, need 27). Verify ignored.
  • DOMAIN_REG with N = 50 but OP_RETURN is only 10 bytes total (6 payload bytes, need 51). Verify ignored.
  • FIELD_REG with N = 40 but OP_RETURN is only 15 bytes total (11 payload bytes, need 46). Verify ignored.
  • SET_DELEGATE with L = 67 but OP_RETURN is only 30 bytes total (26 payload bytes, need 72). Verify ignored.
  • Each operation with L/N = 1 and exactly enough bytes. Verify accepted.

E.19 Founding Message and Review Decode Requires WASM Codec

Risk: Medium. Founding messages (DOMAIN_ANCHOR, Section 5.8.7) and reviews (REP_COMMIT Section 5.13.4, REP_REVOKE Section 5.14.5) are protocol-level stored data. Conforming indexers MUST decode them using decode_sentence_wasm from the scoring module's WASM binary (Section 5.1.6). Native Coglex reimplementations are non-conforming.

The trap. An implementer treats founding messages and reviews as optional application-layer data and either skips them entirely, stores raw undecoded bytes, or decodes them with a native Coglex implementation that diverges from the WASM binary on edge cases (morphological composition, trailing zero stripping, canonical encoding verification). Any of these produces a different lookup_domain or get_reviews result than a conforming indexer.

A second trap. An implementer embeds founding message data in the domains or domain_by_id maps. Founding messages and reviews are stored in separate maps (founding_messages, reviews — Section 7.1) that do not participate in domain_xor or any state hash. Adding a non-XOR field to the domain maps breaks the pattern that every field in those maps has XOR fingerprint coverage.

A third trap. An implementer stores partial or malformed Coglex payloads as raw bytes with a "best effort" flag. The protocol requires valid-or-null: if canonical decoding fails (encode(decode(token_ids)) != token_ids), the result is null — no raw bytes, no partial decode, no fallback.

Correct behavior. For DOMAIN_ANCHOR: if the OP_RETURN is at least 68 bytes, decode payload bytes 4–63 (60 bytes) via decode_sentence_wasm. Store decoded text on success, null on failure. For OP_RETURNs shorter than 68 bytes, store null. For REP_COMMIT and REP_REVOKE: if the OP_RETURN is exactly 80 bytes, decode payload bytes 16–75 (60 bytes) via decode_sentence_wasm. Store decoded text on success, null on failure. For OP_RETURNs shorter than 80 bytes, store null. During reorgs, clean up the corresponding founding_messages or reviews entry alongside the consensus state (Section 7.3). The WASM runtime must remain loaded for the lifetime of the indexer — founding messages and reviews are processed as long as domains anchor and agents commit reputation.

Recommended test vectors: V-414 through V-428 (Section 7.4.14).

E.20 Halving-Era Right-Shift Must Not Wrap

Risk: Medium. The block reward formula 5,000,000,000 >> halving_era produces zero for halving_era >= 33 (Section 5.1.4). But in languages with modular shift semantics (C, Rust, Go), a right-shift by 64 or more bits is undefined behavior or wraps to >> (halving_era % 64), which silently restarts mining rewards.

The trap. An implementer writes let block_reward: u64 = 5_000_000_000u64 >> halving_era; in Rust. This works correctly for all eras through 63. At era 64 (block 13,440,000, approximately 240 years after activation), Rust release mode computes >> (64 % 64) = >> 0, producing block_reward = 5,000,000,000 — a phantom 50 COG reward that violates the supply cap and permanently forks the chain. C and Go exhibit similar behavior.

Correct behavior. If halving_era >= 64, the block reward is zero. Implementations MUST either clamp the shift operand or return zero explicitly before performing the shift. Bitcoin Core uses the same guard: if (halvings >= 64) return 0;.

Recommended test vectors:

  • Block at height 13,440,000 (era 64). Verify block reward is 0, not 5,000,000,000.
  • Block at height 6,930,000 (era 33). Verify block reward is 0.
  • Block at height 6,929,999 (era 32). Verify block reward is 1 cogtoshi.

E.21 Bootstrap Award Is Granted at DOMAIN_ANCHOR, Not DOMAIN_REG

Risk: High. The genesis parameter bootstrap_award_per_registration_cogtoshi contains "registration" in the key name, but the award is granted at DOMAIN_ANCHOR processing.

The trap. An implementer reads the genesis parameters JSON, sees a key that says "per_registration," and wires the bootstrap award to the DOMAIN_REG handler. The indexer grants 0.1 COG at registration instead of at anchor. Every subsequent balance, supply counter, and state hash diverges.

Correct behavior. The bootstrap award (0.1 COG per root-level domain) is granted at DOMAIN_ANCHOR (Section 5.8.3 step 7). The genesis parameter key name is fixed on-chain and cannot be corrected. The signed genesis announcement in the @cogcoin/genesis package states this explicitly in its clarifications section.

Recommended test vectors:

  • DOMAIN_REG for a root domain. Verify no bootstrap COG is credited.
  • DOMAIN_ANCHOR for the same root domain. Verify 0.1 COG (10,000,000 cogtoshi) is credited, bootstrap_remaining is decremented, and total_cog_supply is incremented.
  • DOMAIN_ANCHOR for a subdomain. Verify no bootstrap COG is credited.

17. Appendix F: Canonical Field Naming Conventions

This appendix documents RECOMMENDED field naming patterns for common use cases. These are conventions, not protocol rules. The indexer does not enforce or interpret field names beyond the character validation in Section 5.10.3. Agents and applications that follow these conventions benefit from interoperability without coordination.

17.1 Principles

  1. Lowercase, hyphenated, descriptive. Field names follow the same character rules as domain names: a-z, 0-9, hyphens, no leading/trailing hyphens, 1–63 characters.
  2. Prefix by category. Related fields share a prefix, enabling namespace browsing: api-* for endpoints, audit-* for attestations.
  3. Chain-specific fields use chain name prefix. When a domain publishes data for a specific chain, the field name starts with the chain: base-verifier, arb-bridge, op-settler. This is a human-readable hint; the format byte (0x22 or 0x23) carries the machine-readable chain ID.
  4. Singular nouns.api-endpoint not api-endpoints. One field, one value. Multiple values use numbered suffixes or separate fields.

17.2 Identity and Discovery

Field nameFormatPerm?Description
description0x02eitherShort human-readable description of the domain
data-format0x02mutablePrimary data type descriptor (e.g., "price-oracle", "compute", "translation") for format-based discovery
category0x02mutableService category for marketplace discovery (e.g., "oracle", "auditor", "infrastructure")
version0x1FmutableCurrent service/protocol version (semver)
created0x07permTimestamp the agent considers its genesis — distinct from domain registration block height

category vs. data-format: these serve different discovery paths. data-format describes what kind of data the domain publishes in its fields — useful for indexer queries across the entire namespace ("find all price oracles"). category describes what the agent does as a service — useful for marketplace browsing ("find all translators"). An oracle publishes data-format: price-feed and category: oracle. A translator publishes no data-format (it doesn't publish structured data) but sets category: translation. Both fields are mutable because agents pivot.

17.3 Service Endpoints

Field nameFormatPerm?Description
api-endpoint0x11mutableSecondary or alternative endpoint URI. Primary endpoint is domain.endpoint (set via SET_ENDPOINT).
api-docs0x14mutableURL to API documentation
api-health0x14mutableURL to health check / status endpoint
nostr-relay0x15mutablePreferred Nostr relay hostname for reaching this agent

Every Cogcoin agent can have a Nostr identity, but the relay where it listens is not discoverable without a published field. Without a published relay, counterparties must guess or use a broadcast approach. One relay is sufficient — agents that need more should publish a relay list via IPFS (0x1A) or a SHA-256 hash pointer (0x06).

The primary service endpoint is domain.endpoint, a first-class domain property set via SET_ENDPOINT (Section 5.12). The api-endpoint field is available for agents that need a secondary endpoint, an alternative protocol, or a legacy reference. Most agents need only SET_ENDPOINT.

17.4 Operator

Field nameFormatPerm?Description
operator0x0DmutableDomain reference to the entity that operates this domain
operator-pubkey0x12mutableCompressed secp256k1 pubkey of the operator, if the operator has no Cogcoin domain

operator is the most important delegation field. An anchored domain's owner is permanent, but the human or organization behind it may change roles, delegate operations, or want to be discoverable. The field is mutable — if operations transfer, update it. It is a domain reference (0x0D), not a pubkey, because the operator should have their own Cogcoin identity with their own reputation. An agent operated by a reputable entity inherits trust by association. An agent without an operator field is either self-sovereign (rare, legitimate) or hiding its provenance (common, suspicious).

17.5 Cross-Chain References

Field nameFormatPerm?Description
eth-address0x18permEthereum mainnet address (when chain is unambiguous)
base-address0x22permAddress on Base (chain ID 8453)
base-verifier0x22mutableZK verifier contract on Base
base-deploy-tx0x23permDeployment transaction on Base
arb-address0x22permAddress on Arbitrum (chain ID 42161)
op-address0x22permAddress on Optimism (chain ID 10)
sol-pubkey0x1EpermSolana public key (algorithm tag + 32 bytes Ed25519)

Cross-chain addresses that are deterministically linked to the agent's identity should be permanent fields — the value will never change because the agent's identity is permanently anchored. Contract addresses for deployed verifiers or bridges should be mutable if the agent may upgrade or redeploy.

17.6 Attestation and Audit

Field nameFormatPerm?Description
audit-by-[name]0x24permSecurity audit attestation by named auditor
endorsed-by-[name]0x24mutableGeneral endorsement by named entity
price-confirm0x24mutableIndependent price confirmation (for oracles)

Audit attestations should typically be permanent — an audit happened on a specific date and applies to a specific version. A new audit is a new field (audit-by-alpha-v2), not an overwrite. Endorsements are mutable because the field owner may clear or update them.

17.7 Content and Storage

Field nameFormatPerm?Description
avatar0x1AmutableIPFS CID of avatar image
source-code0x1AmutableIPFS CID of source code archive
terms0x1AmutableIPFS CID of terms of service document

17.8 Operational

Field nameFormatPerm?Description
status0x02mutableOperational status text (e.g., "operational", "degraded", "maintenance")
model0x02mutablePrimary LLM or model identifier (e.g., "claude-sonnet", "llama-70b-weather-v2")
uptime-since0x07mutableTimestamp of last service restart or outage recovery

model will be one of the most frequently queried fields in the ecosystem. Every orchestrator doing service discovery wants to know what model an agent runs. The value is free-text (0x02 UTF-8) rather than an enumerated type because model names proliferate faster than any format table can track. The convention of using the model's commonly known name (not a full path or version hash) keeps the field human-readable and machine-parseable.

17.9 Agent Lifecycle

Field nameFormatPerm?Description
deprecated0x1DmutableBoolean: true if this agent is deprecated and should not receive new traffic
deprecated-by0x0DmutableDomain reference to the successor agent

Agents die. Models get obsolete. Services shut down. Without a deprecation signal, orchestrators discover this through timeouts and errors. A deprecated: true field with a deprecated-by pointer lets the ecosystem gracefully redirect traffic. The deprecated agent's reputation and history remain on-chain forever (domains are permanent), but live traffic routes to the successor.

17.10 Anti-Patterns

  • Chain in the value, not the name. Don't use verifier-8453 when base-verifier with format 0x22 (which encodes 8453 as chain ID) is clearer. The name is for humans; the format byte is for machines.
  • Overloading raw bytes. Don't use format 0x01 with ad-hoc binary encoding when a defined format exists. 0x01 is a last resort for genuinely novel data, not a workaround for unfamiliarity with the format table.
  • Versioned field names. Don't use api-endpoint-v2 when a mutable field called api-endpoint can simply be updated via DATA_UPDATE. Versioning belongs in the value (via 0x1F semver) or in the service itself, not in the field name.
  • Giant JSON blobs. Don't cram an agent's entire configuration into a single 0x09 JSON field. The 67-byte limit enforces discipline. If your data doesn't fit, store it on IPFS and publish the CID on-chain (0x1A).
  • Missing operator. Every agent operated by a known entity should publish operator. It costs 100 cogtoshi to register and 1 cogtoshi to update. The accountability signal it provides is worth orders of magnitude more than the cost.

18. Conclusion

This document specifies Cogcoin completely. Twenty operations, one indexer, no governance tokens, no staking yields, no bridges, no upgradeable contracts. A domain registered today will resolve to the same owner in fifty years.

The protocol makes three additions to Bitcoin: human-readable identity that never expires, domain-scoped data fields where domains publish named values about themselves, and reputation quantified as irreversibly burned value. Every state transition is a standard Bitcoin transaction. Every claim is verifiable from raw block data.

Mining produces English sentences instead of hashes. The token supply is finite and follows Bitcoin's own emission schedule. No entity holds a pre-allocated token position.

The trust assumptions are narrow and stated: the scoring models were trained once by their authors and cannot be updated, the protocol is English-only, and domain squatting is mitigated by pricing but not prevented. These are constraints, not bugs. They are documented in Section 1.12 so that participants can evaluate them before committing resources.

Any entity that can construct a Bitcoin transaction can participate. The only credential is a valid signature. The protocol is permanent. The specification is this document.