Skip to content

Broadcasting and merkle proofs

An index-free application still needs the Bitcoin network for two things. It needs to get its Transactions to the miners, and it needs the merkle proof that shows each Transaction was mined. In this section we will look at how we do both through a single service: Arcade.

In 2020 we sent Transactions to a miner through the Merchant API (mAPI). mAPI was replaced by ARC, a broadcast service that takes a Transaction, sends it to the network, and follows it until it is mined. ARC has in turn been succeeded by Arcade, its Teranode-era successor.

Arcade serves the same API as ARC, so an application can talk to either one with the same code. Two differences matter:

  • Arcade serves its API at the root of its address. Where an ARC address ends in /v1, an Arcade address does not.
  • Arcade answers every submission at once with RECEIVED, and takes the Transaction to the network afterwards. An application has to ask again to find out how it went.

Do note that Arcade was renamed BSV Broadcaster in its v0.19.0 release. The API is unchanged, and the public instances still carry the old name in their addresses.

At the time of writing, these public BSV Broadcasters run on mainnet, open to anyone and with no API key:

Operator Address
BSV Association (US) https://arcade-us-1.bsvblockchain.tech
BSV Association (EU) https://arcade-eu-1.bsvblockchain.tech
BSV Association (Asia-Pacific) https://arcade-ap-1.bsvblockchain.tech
GorillaPool https://arcade.gorillapool.io

The BSV Association’s list of broadcasting services is kept up to date, and also covers running a BSV Broadcaster of one’s own.

ARC is no longer developed by the BSV Association, and the hosted ARC instances are going away. Teranode Infrastructure Services has given notice that its ARC instance stops issuing API keys on 26 November 2026, and that its existing keys stop working at 12:00 CET on 30 November 2026. Transactions sent to it after that are not processed. An application still pointed at an ARC should move to a BSV Broadcaster before then. For most, that is a change of address: drop the /v1 from it, send Extended Format, and follow the status after the RECEIVED reply rather than waiting on X-WaitFor.

On our own machine, the RegTest Teranode tutorial runs Arcade against a regtest Teranode, so we can test all of this before going near mainnet.

A Transaction goes to Arcade in Extended Format: each Input carries the amount and the Locking Script of the Output it spends. This lets Arcade check the Transaction, its Signatures and its fee without looking anything up. Arcade refuses a Transaction that is not in Extended Format.

Figure 1 shows what happens after a wallet submits a Transaction.

The wallet submits a Transaction in Extended Format; Arcade answers RECEIVED. The wallet asks for its status after 1, 2, 4, 8 and 15 seconds until Arcade reports it seen on the network, then keeps asking until Arcade reports it mined with a merkle path. The wallet checks the path against its own header chain and stores the proof with the Transaction.WalletArcadesubmit Transaction (Extended Format)RECEIVEDstatus? after 1, 2, 4, 8, 15 sSEEN_ON_NETWORKstatus? until minedMINED, with the merkle pathcheck the path: own headersstore the proof with the Tx
Figure 1: Broadcasting through Arcade, and the merkle proof that comes back

Let’s walk through it:

  1. Arcade answers the submission with RECEIVED straight away.
  2. The wallet asks for the Transaction’s status a few times in quick succession (libspiffy waits 1, 2, 4, 8 and then 15 seconds), until Arcade reports something other than “in flight”. Usually that is SEEN_ON_NETWORK.
  3. The wallet keeps asking, less often, until Arcade reports the Transaction as MINED, together with its merkle path.
  4. The wallet checks the merkle path against the Block Header in its own header chain. Only a path that matches is stored, together with the Transaction.

From that point on the wallet holds the proof itself, and can hand it to anyone the coin is later paid to.

Do note that a broadcaster can be wrong, or out of date, just like an indexer can. This is why step 4 matters: we never store a merkle path we haven’t checked against our own headers.

Every ARC and Arcade server publishes the fee rate it will accept, in satoshis per kilobyte, at its /policy endpoint. A libspiffy wallet has no fee rate of its own. It reads the policy rate, and pays it on the signed size of each Transaction it builds. If the policy can’t be read, the wallet refuses to guess.

An application can also set a minimum fee rate. The wallet then pays the published rate or the minimum, whichever is higher. This is useful because some servers publish a rate that no miner will actually mine at, e.g. GorillaPool’s testnet ARC publishes 0 satoshis per kilobyte.

Networks fail, and so do servers. A broadcast that fails is put on a durable queue and retried with an increasing delay, from 10 seconds up to 5 minutes, at most 10 times. The queue is stored with the wallet, so it survives the application being closed or the phone restarting. The application is told about each failure, and whether it will be retried.