XChain Platform Action - ANCHOR
On-chain commitment of federation-signed state — checkpoints and the cross-chain match archive — in a single action with three version-discriminated phases:
- v0 — Checkpoint. Validator-broadcast. Commits one chain’s quorum-signed state checkpoint
(the per-block
ledger/actions/contracthash triple) to the anchor chain. - v1 — Checkpoint + match archive. Validator-broadcast. A v0 checkpoint plus a compressed
batch of full
cross_chain_matchesrecords (including their validator signatures and thecapability_snapshotsrows needed to re-verify them), making cross-chain match data recoverable from chain parse alone. - v2 — Archive continuation. Validator-broadcast. Carries overflow chunks when a v1 archive payload exceeds the per-action data limit. Authenticated by its parent v1 (carries no signatures of its own).
ANCHOR is valid only on the anchor chain — DOGE (all networks). Indexers on other chains
reject it. BTC and LTC state is still covered: each v0/v1 names the CHAIN it checkpoints, so
one cheap chain carries the commitments for all three.
ANCHOR supersedes the hub’s legacy raw XDEXANCHOR payload (which was not a protocol action and
was invisible to the decoder). The XDEXANCHOR publisher (CrossChainDexAnchor) was removed
from the hub on 2026-06-11 after ANCHOR verified end-to-end on mainnet; rows it stamped
(batch_root) remain readable but nothing publishes the legacy payload anymore.
Purpose
- Verifiable state. Light clients verify any indexer/explorer response against a
checkpoint signed by
2f+1oracle_publishvalidators, without trusting a single operator. - Full-parse recoverability. Cross-chain match records are the only consensus-relevant dataset not natively on-chain (they are mirror-delivered; see Cross-Chain DEX). The v1/v2 archive places the records themselves on-chain, so the entire platform state is reconstructible from a full parse of the three blockchains with no surviving hub database.
PARAMS
| Name | Type | Versions | Description |
|---|---|---|---|
VERSION |
Integer | all | Format version (0=checkpoint, 1=checkpoint+archive, 2=continuation) |
CHAIN |
String | 0, 1 | Chain being checkpointed: BTC | LTC | DOGE |
NETWORK |
String | 0, 1 | mainnet | testnet | regtest |
BLOCK_INDEX |
Integer | 0, 1 | Checkpointed block height on CHAIN |
BLOCK_HASH |
String | 0, 1 | 64-hex block hash of CHAIN at BLOCK_INDEX |
LEDGER_HASH |
String | 0, 1 | 64-hex chained ledger hash (blocks.ledger_hash at BLOCK_INDEX) |
ACTIONS_HASH |
String | 0, 1 | 64-hex chained actions hash |
CONTRACT_HASH |
String | 0, 1 | 64-hex chained contract hash |
CHECKPOINT_SEQ |
Integer | 0, 1 | Monotonic checkpoint counter per (CHAIN,NETWORK) |
SNAPSHOT_BLOCK |
Integer | 0, 1 | BTC block selecting the oracle_publish validator set for the sigs |
MATCH_BATCH_SEQ |
Integer | 1, 2 | Monotonic archive-batch counter (ties v2 chunks to their v1) |
MATCH_COUNT |
Integer | 1 | Number of match records in this archive batch |
BATCH_CRC32 |
String | 1 | 8-hex CRC32 of the uncompressed archive JSON bytes |
ARCHIVE_B64 |
String | 1 | base64url of gzip(archive JSON) — chunk 0 when the batch is chunked |
CHUNK_INDEX |
Integer | 2 | 1-based continuation index (the v1 itself carries chunk 0) |
TOTAL_CHUNKS |
Integer | 1, 2 | Total chunks in the batch (1 = unchunked, v1-only) |
ARCHIVE_B64_CHUNK |
String | 2 | This continuation’s slice of the base64url payload |
SIG_COUNT |
Integer | 0, 1 | Number of (pubkey, sig) pairs that follow |
PUBKEY_n |
String | 0, 1 | 64-hex Ed25519 pubkey, in the oracle_publish set at SNAPSHOT_BLOCK |
SIG_n |
String | 0, 1 | 128-hex Ed25519 signature over the canonical checkpoint message |
Formats
Version 0 — Checkpoint (validator-broadcast)
ANCHOR|0|CHAIN|NETWORK|BLOCK_INDEX|BLOCK_HASH|LEDGER_HASH|ACTIONS_HASH|CONTRACT_HASH|CHECKPOINT_SEQ|SNAPSHOT_BLOCK|SIG_COUNT|PUBKEY1|SIG1|PUBKEY2|SIG2|...
Version 1 — Checkpoint + match archive (validator-broadcast)
ANCHOR|1|CHAIN|NETWORK|BLOCK_INDEX|BLOCK_HASH|LEDGER_HASH|ACTIONS_HASH|CONTRACT_HASH|CHECKPOINT_SEQ|SNAPSHOT_BLOCK|MATCH_BATCH_SEQ|MATCH_COUNT|BATCH_CRC32|TOTAL_CHUNKS|ARCHIVE_B64|SIG_COUNT|PUBKEY1|SIG1|...
Version 2 — Archive continuation (validator-broadcast; no signatures)
ANCHOR|2|MATCH_BATCH_SEQ|CHUNK_INDEX|TOTAL_CHUNKS|ARCHIVE_B64_CHUNK
Examples
ANCHOR|0|BTC|mainnet|900123|00000000...|3f9a...|b81c...|44d0...|417|900120|3|a1b2...|c3d4...|e5f6...|0718...|292a...|3b4c...
Quorum-signed checkpoint of BTC mainnet block 900123, published on DOGE
ANCHOR|1|BTC|mainnet|900123|00000000...|3f9a...|b81c...|44d0...|418|900120|42|17|9c4e1b22|1|H4sIAAAA...|3|a1b2...|c3d4...|...
Checkpoint plus archive batch 42 (17 match records, single chunk)
ANCHOR|2|42|1|3|AAAB7Rxe...
Continuation chunk 1 of 3 for archive batch 42
Canonical signing message (v0 / v1)
Each SIG_n covers the UTF-8 bytes of:
XCHECKPOINT|CHAIN|NETWORK|BLOCK_INDEX|BLOCK_HASH|LEDGER_HASH|ACTIONS_HASH|CONTRACT_HASH|CHECKPOINT_SEQ|SNAPSHOT_BLOCK
and for v1, with the archive structure appended:
XCHECKPOINT|...|SNAPSHOT_BLOCK|MATCH_BATCH_SEQ|MATCH_COUNT|BATCH_CRC32|TOTAL_CHUNKS
ARCHIVE_B64 is not part of the signed bytes — the blob is bound to the signed structure by
BATCH_CRC32, computed over the uncompressed JSON. (CRC over uncompressed bytes keeps
verification independent of the zlib version that produced the gzip stream.) Chain/network are
uppercase/lowercase exactly as on the wire; numerics are decimal with no leading zeros; hashes
are lowercase hex. A signature counts only if its pubkey is in the oracle_publish capability
snapshot at SNAPSHOT_BLOCK and the Ed25519 signature verifies.
Archive JSON (v1/v2 payload, after gunzip)
A single JSON object with fixed key order (required — BATCH_CRC32 is computed over these
exact bytes):
{
"v": 1,
"network": "mainnet",
"batch_seq": 42,
"matches": [ { ...full cross_chain_matches row... } ],
"calls": [ { ...cross_chain_calls relay row... } ],
"rewards": [ { "validator_pubkey": "...", "source": "1Stake...", "round_number": 17, "reward_type": "anchor_BTC", "amount": "10.00000000", "block_index": 900120 } ],
"capability_snapshots": [ { "snapshot_block": 900120, "capability": "cross_chain", "signing_pubkey": "...", "amount": "..." } ]
}
matches[]rows carry every wire-relevantcross_chain_matchescolumn —match_id,snapshot_block,network, both legs (a_*/b_*includingkind/filled_before),effective_time,validator_signatures(the raw JSON string, verbatim), andstatus(finalizedorretracted). Hub-side audit columns (batch_root,anchor_txid) are excluded.capability_snapshots[]carries thecross_chainsnapshot rows for every distinctsnapshot_blockreferenced bymatches[](to re-verify match signatures) plus theoracle_publishrows at the wrapper checkpoint’sSNAPSHOT_BLOCK(to re-verify the v1 anchor’s own signatures). They are included because historicalmin_stakegovernance values are not on-chain — archiving the snapshot rows makes signature re-verification self-contained during recovery. Recovery additionally cross-checks archived pubkeys against on-chain BTC stakes (a fabricated snapshot row cannot survive — staking is on-chain), so the chain remains the root of trust.rewards[]carries the anchor-publish reward rows (reward_typeanchor_<chain>/anchor_archiveonly) that have not yet ridden an archive. These are the onevalidator_rewardsrail a chain parse cannot re-derive (oracle_roundandattest_feerows are derived deterministically from PRICE/ATTEST actions and are never archived — recovery rejects an archive that claims them). Reward rows carry no per-row signatures; every co-signing hub instead re-derives each field before signing: the pubkey must be in its ownoracle_publishresolution atblock_index, the amount must equal its configured publish reward, andsourcemust match its own block-scoped indexer resolution of the earn-time staking address (pinned into the archive because recovery restores rewards into an EMPTY BTC DB, and a later re-stake of the pubkey must not move the credit).block_indexis the quorum-agreedSNAPSHOT_BLOCKof the rewarded checkpoint, so every hub records identical row bytes.- All amounts are decimal strings (full precision, as stored).
- A match retracted after it was archived is re-published in a later batch with
status:"retracted". Recovery applies latest-status-wins ordered bybatch_seq. callsandrewardsare additive keys — archives published before each existed simply omit them, and recovery treats a missing key as an empty list.
Rules
All versions
- Valid only where
COIN = DOGE— indexers on other chains mark the action invalid. - No XCHAIN fee and no native-coin protocol fee (validator protocol action — same fee treatment
as
PRICEv0). The publisher pays only the DOGE miner fee.
Version 0 / 1
CHAINmust be one ofBTC/LTC/DOGE;NETWORKmust equal the indexer’s own network.- Each
PUBKEY_nis checked against theoracle_publishcapability snapshot atSNAPSHOT_BLOCK(a BTC height; non-BTC indexers resolve it from the hub-mirroredcapability_snapshotstable, exactly as cross-chain settlement resolvescross_chain). - Each
SIG_nmust Ed25519-verify against the canonical message. - Valid signatures must reach
max(2f+1, ceil((N+1)/2))of the snapshot set — PBFT2f+1floored at a simple majority, so N=3 requires 2 (single-validator sets require 1). CHECKPOINT_SEQmust be ≥ any previously accepted seq for (CHAIN,NETWORK) — replays of older checkpoints are recorded but flaggedstale, nevervalid. Equal-seq records are accepted: a v0 and its v1 share the same wrapper seq by design, and an exact replay is signature-bound to identical content (harmless duplicate). The same ≥ rule applies toMATCH_BATCH_SEQon v1.
Version 1 only
MATCH_COUNTmust equalmatches.lengthafter decompression (whenTOTAL_CHUNKS= 1; otherwise checked at reassembly).BATCH_CRC32must match the CRC32 of the uncompressed JSON (checked at reassembly when chunked).MATCH_BATCH_SEQmust be ≥ any previously accepted batch seq for the network.
Version 2 only
MATCH_BATCH_SEQmust reference a previously indexed v1 withTOTAL_CHUNKS> 1 (out-of-order arrival within the same block is tolerated; the batch assembles when all chunks are present).CHUNK_INDEXmust be in[1, TOTAL_CHUNKS-1]and not a duplicate.- Carries no signatures — a v2 is meaningful only joined to its authenticated v1; orphan or
CRC-failing batches are flagged
invalid_archiveand ignored by recovery.
Effects
- Persists into
anchor_actions(action-indexed; rolled back on reorg like any data table). - A
validv0/v1 records the checkpoint; the indexer’s mirroredstate_checkpointscopy is the live source for verification APIs, whileanchor_actionsis the permanent on-chain record. - No ledger effect. ANCHOR never credits, debits, escrows, or alters token state. A bad or missing anchor can never corrupt balances — the worst failure mode is a missing audit/recovery record.
Publisher
- Published by the hub’s
StateAnchorPublisher. Per-chain publisher election: each pending checkpoint elects its own publisher from theoracle_publishcapability snapshot at the checkpoint’ssnapshot_block, ordered bySHA256(election key ‖ pubkey)ascending (the attestation responsible-set idiom; the key binds chain/network/seq/snapshot_block, so a different validator typically wins each chain’s anchor in a cycle). Rank 0 publishes from its own funded DOGE wallet; each further rank unlocks afterANCHOR_ELECTION_TOLERANCE_BLOCKSmore BTC blocks elapse without a publish (deterministic failover ladder; a gossipedXANC_V0_DONEback-fill stops peers from re-anchoring a checkpoint someone already paid for). The v1/v2 archive round elects a single leader the same way, keyed per election block. A single-validator federation degenerates to today’s serialized single-wallet behavior. - Each successful publish records an
anchor_<chain>(round =checkpoint_seq) oranchor_archive(round =batch_seq) reward ofANCHOR_REWARD_PER_PUBLISHXCHAIN (default 10) on thevalidator_rewardsrail, collectable on BTC viaCOLLECTlike oracle-round rewards. - P2SH encoding via the standard encoder pipeline.
- Default cadence: one v0 per chain plus pending v1/v2 archive batches per anchor interval
(
ANCHOR_INTERVAL_MS, default daily), or early whenANCHOR_MATCH_BATCH_SIZEmatches are pending. Checkpoint signing happens more often (hourly, mirror-only, no chain writes); the anchor commits the latest signed checkpoint at publish time. Operators can also trigger an immediate flush via the hub’s authenticatedanchorflushJSON-RPC method.
Recovery procedure (full-parse)
- Sync DOGE through the decoder/indexer from genesis —
anchor_actionspopulates from the chain alone. - Run
xchain-indexer/src/recovery.jswithBTC_INDEXER_DB_NAMEset: reassembles chunked batches byMATCH_BATCH_SEQ, gunzips, verifiesBATCH_CRC32, verifies each archived match’s/call’svalidator_signaturesagainst the archivedcapability_snapshots, rebuildscross_chain_matches+cross_chain_calls+capability_snapshots(latest-status-wins), and restores archivedrewards[]rows into the BTC indexer DB’svalidator_rewards(seeding the id maps is safe pre-reindex — they are append-only get-or-create). - Reindex BTC/LTC/DOGE from genesis against the recovered tables — cross-chain settlements,
XCALL injections,
oracle_round/attest_feerewards, and historical COLLECT claims all re-derive identically; finalblockshash triples must match the anchored checkpoints.
Ordering is load-bearing: the reward restore (step 2) MUST complete before the BTC reindex
(step 3) — COLLECT validation reads validator_rewards synchronously at parse time, so a
reindex that reaches a historical COLLECT before its anchor rewards are restored replays it
invalid: no unclaimed rewards and the recovered ledger diverges. (--verify-stakes is for a
post-reindex verification pass — against the empty pre-reindex BTC DB it would fail every
batch.)
Notes
SNAPSHOT_BLOCKis distinct fromBLOCK_INDEX:BLOCK_INDEXis the checkpointed height onCHAIN;SNAPSHOT_BLOCKis always a BTC height (capability staking is BTC-only).- The handler reads
BLOCK_INDEX/SNAPSHOT_BLOCKfrom the wire payload — not from the DOGE block the ANCHOR lands in. - Checkpoints for a reorged height are simply re-signed and re-anchored for the canonical
chain; the superseding record has a higher
CHECKPOINT_SEQ.
Copyright © 2025–2026 Dankest, LLC
Based on XChain Platform by Dankest, LLC – https://dankest.llc
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) with a commercial license available for proprietary use.
You may use, modify, and distribute this material under the terms of the License. See LICENSE and NOTICE for full terms. See the licensing overview.