Ephemeral Sidechains

Ephemeral Sidechains: pruning headers, not just bodies, by anchoring the checkpoint to Bitcoin

(Follow-up to a previous discussion with @SergioDemianLerner about RSKIP215.)

TL;DR. RSKIP215 (Ephemeral Blockchain) removes old block bodies from consensus, but a syncing node still downloads every RSK header from genesis — the spec explicitly starts by “requesting all block headers from genesis”. For Rootstock that is the expensive part: ~500 B per header, ~600 B of merge-mining proof, plus uncles on roughly half the blocks. Even a Superchain-style 20× reduction leaves a lot of data. But a merge-mined sidechain has an asset that standalone chains lack: Bitcoin itself, whose headers are 80 bytes and whose canonical blocks provide external timestamps and difficulty-weighted samples of hashrate. Ephemeral Sidechains use Bitcoin as the header backbone, so initial sync downloads zero RSK headers before a well-defined checkpointing period.

Assumptions and security model

We assume the following:

  1. Majority of Rootstock miners in the past 14 days are honest.
  2. Reorganizing more than 14 days of Rootstock blocks is impossible.

These are fair assumptions especially giving that currently the PowPeg makes it impossible to reorg that deep without a hard fork, and in any future trust minimized or trustless bridge situation, reverting 14 days worth of Rootstock blocks is most probably going to cause a catastrophic failure of the peg, as the challenging period of a withdrawal attempt is most likely less than two weeks.

Sync algorithm

Finding Checkpointing Period

  1. Download all Bitcoin headers, as any SPV wallet does (~70 MB total today, and checkpointable).

  2. Partition them into difficulty-adjustment periods of 2016 blocks. Call the latest (possibly incomplete) period P(L), and the ones before it P(-1), P(-2), … Within a period every block shares one difficulty D(P), read directly from the already-downloaded headers — so difficulty weighting below costs zero extra data.

  3. Walking backwards from the Bitcoin tip, download each block’s coinbase transaction + Merkle inclusion proof (~600 B per block) and count how many coinbases in each period carry an RSKBLOCK: tag. Define each period’s observed merge-mining work as

    W(P) = tags(P) × D(P)
    
  4. Checkpoint Period: the first P(i), walking back, such that

    W(P(i+1)) + … + W(P(L))  >  W(P(i))
    

    i.e. the merge-mining work observed after the period exceeds the work observed inside it. This mirrors the removal condition of RSKIP215 and serves the same purpose: if participation suddenly drops, the checkpoint retreats until the tail accumulates enough observed work to make re-mining from inside the Checkpoint Period at least as expensive as the honest tail.

Bitcoin headers:  ...──| P(-4) |──| P(-3) |──| P(-2) |──| P(-1) |──| P(L) partial |──▶ tip
tags per period:         1450       1500        380        410           260
difficulty D(P):          100        110        120        130           135     (relative units)
W = tags × D:          145,000    165,000     45,600     53,300        35,100

walk back from tip:
  i = -1 : tail = 35,100                     35,100 > 53,300 ?  no
  i = -2 : tail = 53,300 + 35,100 = 88,400   88,400 > 45,600 ?  YES  
  →  Checkpoint Period = P(-2)

Finding Latest Checkpoint Block

Our purpose is to ensure that the checkpoint block has NOT being mined in a long range attack to overpower other forks in a the fork choice rule. To achieve that, our main constraint is that the checkpoint has to be mined later than the Checkpoint Period start.

To prove that, we define the Checkpoint Block as the earliest block that has in its merge mined bitcoin header a Previous Block hash points to an actual Bitcoin block in the canonical chain, within the Checkpoint Period.

BITCOIN (canonical headers, from SPV sync)

 [B*]...──[b2015]────[ b2016 ]──[ t1 ]──[ t2 ]──[ t3 ]── ... ──▶ btc tip
 └───── Checkpoint Period ───┘  └───────────── tail ─────────────┘
                            ▲
                            └──────┐ Previous Block
                               ┌───┴──────────────────────────┐
                               │ Bitcoin Merged Mining Header │
                               └──────────────────────────────┘
ROOTSTOCK                          │
                               ┌───┴────┐
 (pruned headers) ── ✂ ────────│ RSK_C  │──[c1]──[c2]── ... ──▶ rsk tip
                               └────────┘
                            Checkpoint Block 

Fork Choice and SAFE block

Given two forks with valid Checkpoint Blocks, the one with the heaviest observed subtree (GHOST) is the canonical rootstock chain.

Once a block in the canonical chain is buried under enough confirmations we can consider it SAFE from reversion.

Armadillo

Even if we only see one Rootstock fork, we can then depend on the Armadillo algorithm to detect any hidden forks, and if we think there is one, we delay our subjective SAFE block tagging until we are satisfied a block is buried under enough blocks that don’t seem to be contested with a hidden fork.

FINAL Block

Once we settle which Checkpoint Block is in the canonical chain, using the fork choice rule with or without Armadillo’s help, we can then consider that Checkpoint Block to be FINAL.

                     ┌─────────┐
   Fork A:  ─── ✂ ───│ RSK_C_A │──[a1]──[a2]──[a3]──[a4]     subtree work W_A
                     └─────────┘         └──[a2']            (uncles count, GHOST)

                     ┌─────────┐
   Fork B:  ─── ✂ ───│ RSK_C_B │──[b1]──[b2]                 subtree work W_B
                     └─────────┘

   Both Checkpoint Blocks reference canonical BTC >= B*  ⇒  both ADMISSIBLE
   Fork choice: heaviest observed subtree,  W_A > W_B    ⇒  Fork A canonical
   Fork A's Checkpoint Block                             ⇒  FINAL
   Node downloads state at RSK_C_A, validates forward

   Fork X:  ──[x1]──[x2]──[x3]── ...   every prevHash < height(B*)
                                       (pre-mined long-range fork)
                                   ⇒  INADMISSIBLE — never reaches GHOST

State Download

The state at the FINAL block is then trusted to be downloaded by full nodes that are willing to validate blocks going forward. Otherwise, light clients can check state proofs at any block they consider SAFE.

Cost comparison (initial sync, before the horizon)

RSKIP215 Ephemeral Sidechains
RSK headers from genesis ~500B × 2 * 60 * 24 *365 (~500MB/yr ) none
Merge-mining proofs ~600B × 2 * 60 * 24 *365 (~600MB/yr) ~600B × 2 * 60 * 24 *14 (~25MB)
Uncle headers ~50% of blocks ~50% of blocks
Bitcoin headers 80 B × ~52.5k/yr (~4 MB/yr, checkpointable)
Coinbase + Merkle proof ~600B × 2016 × (2-5) (~2.5-6MB)
Sum 1.65 GB ~50MB

Implementation

I am keeping track of a reference implementation here.

Feedback very welcome.

While thinking about this, I found myself contemplating not only leveraging Armdaillo/SFAMM (Strong fork aware merge mining) but also Inclusive Fork-Aware Merge-Mining; basically:

  1. Check the coinbase txns in the latest complete difficulty epoch in bitcoin (2016 blocks with the same difficulty).
  2. Each block containing an RSK tag, endorses the block in that tag and all its ancestors.
  3. Each block that does not contain an RSK tag, endorses the block its parent endorses.
    • For simplicity only check coinbase txns within the epoch, so if the first block if it is missing a tag, endorses nothing.
  4. Consider a Rootstock block FINAL (discard earlier blocks and do initial headers download starting from it) if and only if it is the root of a tree (canonical and uncles) endorsed by 1009/2016 blocks.

Edit: to be on the safer side, we can increase the threshold from 50%+1 (1009/2016) to 2/3 + 1 (1345/2016) .. making sure that any dissenting (possibly hidden) fork is not strong enough + mute any statistical variants causing this bitcoin-side metric to be different from the consensus fork choice rule in Rootstock.

This means miners with 33% of the bitcoin hash rate can stall removing historical Rootstock headers, but that is not a security issue, instead it just disables most of the benefit of the ephemeral sidechain for light clients.

Some data scrapping Bitcoin coinbase txns and RSK tags to inform my decisions, considering different lengths of tail blocks, and count the number of participating blocks (with RSK tags) and how many of them agree on the same fork (using Armadillo brilliant CPV):

  1. Latest complete epoch (2016 blocks) + incomplete current epoch (2272 blocks total):
================ CPV agreement (RSKIP110) ================
blocks in tail           : 2272
rsk tagged (T)           : 1360
untagged (neutral)       : 912
participation P          : 59.86%  (OK >= 50%)
cpv-consistent tags      : 1359 / 1360
agreement A              : 99.93%  (OK >= 90%)
divergent tags           : 1
  btc 961061: disagrees at rsk#9123008 (deepest 9123008)
-----------------------------------------------------------
verdict                  : AGREEMENT CONFIRMED
  1. 26208 blocks:
================ CPV agreement (RSKIP110) ================
blocks in tail           : 26208
rsk tagged (T)           : 20777
untagged (neutral)       : 5431
participation P          : 79.28%  (OK >= 50%)
cpv-consistent tags      : 20761 / 20777
agreement A              : 99.92%  (OK >= 90%)
divergent tags           : 16
  btc 936236: disagrees at rsk#8520960 (deepest 8520960)
  btc 936976: disagrees at rsk#8535872 (deepest 8535872)
  btc 944836: disagrees at rsk#8727360 (deepest 8727360)
  btc 944837: disagrees at rsk#8727360 (deepest 8727360)
  btc 944890: disagrees at rsk#8728448 (deepest 8728448)
  btc 945580: disagrees at rsk#8745216 (deepest 8745216)
  btc 945717: disagrees at rsk#8748160 (deepest 8748160)
  btc 947439: disagrees at rsk#8791744 (deepest 8791744)
  btc 947524: disagrees at rsk#8793472 (deepest 8793472)
  btc 950253: disagrees at rsk#8857920 (deepest 8857920)
  btc 954403: disagrees at rsk#8962688 (deepest 8962688)
  btc 954558: disagrees at rsk#8966016 (deepest 8966016)
  btc 955340: disagrees at rsk#8983616 (deepest 8983616)
  btc 955951: disagrees at rsk#8998336 (deepest 8998336)
  btc 959316: disagrees at rsk#9084928 (deepest 9084928)
  btc 961061: disagrees at rsk#9123008 (deepest 9123008)
-----------------------------------------------------------
verdict                  : AGREEMENT CONFIRMED

Evidently the agreement increase when the window is larger, also there is more chance to satisfy a much more demanding threshold (67%) which makes it quite hard to fake even if 33% of bitcoin miners are trying to screw with Rootstock:

================ CPV agreement (RSKIP110) [iteration 5] ================
blocks in tail        : 10354
rsk tagged            : 7058
untagged (neutral)    : 3296
participation P       : 68.17%
cpv-consistent tags   : 7052 / 7058
agreement A           : 99.91%
t = P x A             : 0.681   (T = 0.67) PASS
divergent tags        : 6
  btc 954403: disagrees at rsk#8962688 (deepest 8962688)
  btc 954558: disagrees at rsk#8966016 (deepest 8966016)
  btc 955340: disagrees at rsk#8983616 (deepest 8983616)
  btc 955951: disagrees at rsk#8998336 (deepest 8998336)
  btc 959316: disagrees at rsk#9084928 (deepest 9084928)
  btc 961061: disagrees at rsk#9123008 (deepest 9123008)

Source code of this script: rsk/crates/rsk-node/examples/epoch_tags.rs at 3ee334aad02c2bfabbb8189e56195f29d49df4b7 · Nuhvi/rsk · GitHub