BIP300 / BIP301 · Drivechain

Drivechain Messages M1–M8

Eight messages carry every drivechain operation — proposing a sidechain, moving coins in and out, and blind merged mining. Five of them can only be minted into a block's coinbase by a miner running the enforcer. Three travel the peer-to-peer network as ordinary transactions. Nearly every confusing failure comes from mistaking one kind for the other.

The distinction that governs everything

A drivechain message is either a coinbase output in a mainchain block, or an output in an ordinary transaction. That single fact decides who can produce it, how it reaches the network, and what it costs to get it accepted.

Coinbase lane

M1 · M2 · M3 · M4 · M7

An OP_RETURN output in the block's own coinbase transaction. It exists only because the miner who found that block chose to put it there.

Emitted by: the block producer. In practice, a miner whose template comes from a BIP300/301 enforcer. A miner on a stock getblocktemplate cannot produce these at all.

Transaction lane

M5 · M6 · M8

Outputs in normal mainchain transactions. They relay through the mempool like any other transaction and pay ordinary fees.

Emitted by: anyone. Any node can broadcast one; any miner can mine one. No enforcer required to create or relay them.

The enforcer parses the coinbase lane by iterating every output of the coinbase transaction and attempting CoinbaseMessage::parse on each scriptPubKey. Its CoinbaseMessage enum has exactly five variants: M1, M2, M3, M4, M7. Nothing else is a coinbase message.

All eight at a glance

Tags are the leading bytes of the OP_RETURN payload. Sidechain number S is always one byte.
Msg Name Tag Lives in Purpose
M1ProposeSidechain D5 E0 C4 AF coinbase Nominate a sidechain into slot S
M2AckSidechain D6 E1 C5 DF coinbase One miner vote for a pending proposal
M3ProposeBundle D4 5A A9 43 coinbase Nominate a withdrawal bundle
M4AckBundles D7 7D 17 76 coinbase Vote on the bundle slate
M5Deposit transaction Move BTC into the sidechain treasury
M6Withdrawal transaction Pay an approved bundle out of the treasury
M7BmmAccept D1 61 73 68 coinbase Accept one sidechain block per slot
M8BmmRequest 00 BF 00 transaction Bid to have a sidechain block accepted

M5 and M6 carry no tag because they are not tagged OP_RETURN messages at all — they are recognised by their shape, specifically the OP_DRIVECHAIN treasury output they create or spend.

The messages in detail

M1ProposeSidechaincoinbase

Nominates a sidechain for slot S, carrying the full description. The proposal starts a voting window; it does nothing on its own.

D5 E0 C4 AFtag
S1 byte
descriptionrest of payload
Who can emit: block producer onlyEffect: opens a proposal
M2AckSidechaincoinbase

One miner's vote for a pending proposal, identified by the double-SHA256 of its description. Accumulated votes are what activate a slot.

D6 E1 C5 DFtag
S1 byte
description_hash32 bytes · sha256d
Script length: exactly 38 bytesOtherwise: read as an ordinary script
M3ProposeBundlecoinbase

Nominates a withdrawal bundle — a batch of sidechain exits — by its txid. Like M1, it opens a vote rather than settling anything.

D4 5A A9 43tag
S1 byte
bundle_txid32 bytes
Who can emit: block producer onlyEffect: opens a bundle vote
M4AckBundlescoinbase

Votes across the whole slate of pending bundles at once. Four encodings trade precision against coinbase bytes.

D7 7D 17 76tag
00repeat previous
01upvotes, 1 byte each
02upvotes, 2 bytes each
03leading by 50
Abstain: 0xFF / 0xFFFF Alarm: 0xFE / 0xFFFE
M5Deposittransaction

An ordinary transaction that spends the sidechain's current treasury UTXO and recreates it with more value in it. The destination on the sidechain rides along in a separate OP_RETURN.

OP_DRIVECHAIN OP_PUSHBYTES_1 <S> OP_TRUEtreasury scriptPubKey
old_ctip + depositnew nValue
Who can emit: anyoneRecognised by: output shape, not a tag
M6Withdrawaltransaction

Pays an approved bundle out of the treasury. Exactly one input (the old treasury UTXO); output 0 is the new treasury UTXO, and every output after it is a payout.

1inputs · exactly
vout 0new treasury UTXO
vout 1…npayouts
F = T₍ₙ₋₁₎ − Tₙ − Pimplied fee
Its M6id is computed with the input list clearedMust match an approved bundle
M7BmmAcceptcoinbase

The accept half of blind merged mining. It names one sidechain block hash as accepted for slot S in this block — and it is the only thing that actually advances a sidechain.

D1 61 73 68tag
S1 byte
sidechain_block_hash32 bytes · H*
Costs the block 192 weight unitsAt most one per sidechain, per block
M8BmmRequesttransaction

The bid. A normal transaction whose OP_RETURN commits to a candidate sidechain block hash, with the bribe paid as the transaction fee. It is bound to one specific parent block and dies with it.

00 BF 00tag · 3 bytes
S1 byte
sidechain_block_hash32 bytes · H*
prev_mainchain_block_hash32 bytes
Bribe: the tx feeExpires when: the mainchain tip moves

Flow: proposing and activating a sidechain

%%{init: {"theme":"base","themeVariables":{"fontFamily":"IBM Plex Mono, monospace","fontSize":"13px","primaryColor":"#EDEFF3","primaryTextColor":"#15181D","primaryBorderColor":"#A9761C","lineColor":"#5E6672","actorBkg":"#FFFFFF","actorBorder":"#5E6672","actorTextColor":"#15181D","signalColor":"#15181D","signalTextColor":"#15181D","noteBkgColor":"#F6EEDC","noteBorderColor":"#A9761C","noteTextColor":"#15181D","sequenceNumberColor":"#FFFFFF"}}}%%
sequenceDiagram
    autonumber
    participant Op as Sidechain operator
    participant Miners as Mainchain miners
    participant CB as Block coinbase
    participant Enf as Enforcer (every node)

    Op->>Miners: ask for slot S (out of band)
    Miners->>CB: M1 ProposeSidechain (S, description)
    Enf->>Enf: record proposal, start age counter
    loop each subsequent block
        Miners->>CB: M2 AckSidechain (S, sha256d(description))
        Enf->>Enf: vote_count += 1
    end
    Enf->>Enf: vote_count > threshold AND age within window?
    Enf-->>Op: slot S activated
Both halves are coinbase messages. A sidechain cannot be proposed or approved by broadcasting anything — every step requires miners to put bytes in their own coinbase, which is why activation is a miner vote by construction.
Activation and bundle thresholds by preset. A proposal activates when vote_count > threshold (strictly) and age ≤ max_age (inclusive).
Preset Bundle max age Bundle threshold Used slot age / votes Unused slot age / votes
MAINNET26,30013,15026,300 / 13,1502,016 / 1,815
FORKNET14472144 / 7236 / 30
SHORT10510 / 510 / 5

A slot that was previously occupied is a used slot and gets the longer window; a never-used slot gets the shorter one. Reading the wrong row is an easy way to conclude an activation was impossible when it was not — a proposal 119 blocks old with 73 votes fails the FORKNET unused rule (36 / 30) but passes the used one (144 / 72).

Flow: deposits and withdrawals

%%{init: {"theme":"base","themeVariables":{"fontFamily":"IBM Plex Mono, monospace","fontSize":"13px","primaryColor":"#EDEFF3","primaryTextColor":"#15181D","primaryBorderColor":"#2B7A87","lineColor":"#5E6672","actorBkg":"#FFFFFF","actorBorder":"#5E6672","actorTextColor":"#15181D","signalColor":"#15181D","signalTextColor":"#15181D","noteBkgColor":"#E2F0F2","noteBorderColor":"#2B7A87","noteTextColor":"#15181D","sequenceNumberColor":"#FFFFFF"}}}%%
sequenceDiagram
    autonumber
    participant User as Depositor / withdrawer
    participant Mem as Mainchain mempool
    participant CB as Block coinbase
    participant Tre as Treasury UTXO (Ctip)

    rect rgb(226, 240, 242)
    Note over User,Tre: Deposit — no coinbase message needed
    User->>Mem: M5 tx, spends Ctip, recreates it larger
    Mem->>Tre: mined by any miner
    Tre->>Tre: Ctip value += deposit
    end

    rect rgb(246, 238, 220)
    Note over User,Tre: Withdrawal — gated by two miner votes
    User->>CB: bundle proposed via M3 (S, bundle_txid)
    loop voting window
        CB->>CB: M4 AckBundles upvotes the slate
    end
    CB-->>Mem: bundle approved
    Mem->>Tre: M6 tx pays out, recreates Ctip smaller
    end
Money in is permissionless; money out is not. A deposit is a plain transaction anyone can make. A withdrawal only becomes spendable after M3 and M4 — both coinbase messages — have carried it through a miner vote.

Flow: blind merged mining

%%{init: {"theme":"base","themeVariables":{"fontFamily":"IBM Plex Mono, monospace","fontSize":"13px","primaryColor":"#EDEFF3","primaryTextColor":"#15181D","primaryBorderColor":"#A9761C","lineColor":"#5E6672","actorBkg":"#FFFFFF","actorBorder":"#5E6672","actorTextColor":"#15181D","signalColor":"#15181D","signalTextColor":"#15181D","noteBkgColor":"#F6EEDC","noteBorderColor":"#A9761C","noteTextColor":"#15181D","sequenceNumberColor":"#FFFFFF"}}}%%
sequenceDiagram
    autonumber
    participant SC as Sidechain node
    participant W as Enforcer wallet
    participant Mem as Mainchain mempool
    participant Plain as Plain miner
    participant EnfM as Enforcer-driven miner

    SC->>SC: build candidate block, hash it as H*
    SC->>W: CreateBmmCriticalDataTransaction(S, H*, prev_tip)
    W->>W: reject if prev_tip is no longer the tip
    W->>Mem: broadcast M8 (fee = bribe)
    Mem-->>Plain: relayed
    Mem-->>EnfM: relayed

    alt mined by a plain miner
        Plain->>Plain: includes M8, keeps the fee
        Plain--xSC: no M7 in coinbase — sidechain does NOT advance
    else mined by an enforcer-driven miner
        EnfM->>EnfM: includes M8 AND appends M7 to its coinbase
        EnfM-->>SC: commitment found; block connects
    end
Relaying an M8 is not the same as accepting it. The bid reaches everyone, but only a template that appends M7 turns it into a sidechain block. A miner without an enforcer collects the bribe and advances nothing.
The consequence worth internalising

Raising the bribe on an M8 does not persuade a plain miner to help — they structurally cannot emit M7. A higher fee only matters when competing against other enforcer-driven miners for the single M7 slot that sidechain gets in that block.

The enforcer keys pending requests on (prev_mainchain_block_hash, sidechain_number), so two M8s for the same parent and slot are recorded as conflicting. One can win; the rest are dead weight.

What this looks like in the log

A sidechain node bidding into a network with no enforcer-driven miners produces exactly this, block after block — the request is made, relayed, and never accepted:

INFO  attempt BMM: created TX: 436ed0e0…
WARN  confirm BMM: received new block without our BMM commitment
      side_hash=26817a96… main_height=996455 bmm_commitment=none

bmm_commitment=none is the tell: a mainchain block arrived carrying no M7 for this slot at all. Nothing about the bid was wrong; nobody was in a position to accept it.

Reading a block, in order

Given a mainchain block, the enforcer answers "what happened to the drivechains?" in two passes, and they are not interchangeable:

PassWhere it looksWhat it finds
1 Every output of the coinbase transaction, parsed as a CoinbaseMessage M1, M2, M3, M4, M7 — proposals, votes, and this block's BMM accepts
2 The block's ordinary transactions, matched by shape M5 and M6 by their OP_DRIVECHAIN treasury output; M8 by its tagged OP_RETURN

An M8 found in pass 2 with no matching M7 from pass 1 raises NotAcceptedByMiners — but that error is explicitly non-fatal. The mainchain block stays valid and the transaction's fee is collected; the M8 simply is not treated as a BMM request, and the sidechain does not advance. Two M7s for the same slot in one coinbase are a different matter: MultipleBmmBlocks is fatal and the block is rejected.