|
| 1 | +# The Design of CKB Bitcoin SPV |
| 2 | + |
| 3 | +CKB Bitcoin SPV is a library, for doing Bitcoin simplified payment |
| 4 | +verification on CKB. |
| 5 | + |
| 6 | +## Abstract |
| 7 | + |
| 8 | +This document describes the design and explains the technical details of CKB |
| 9 | +Bitcoin SPV, which allows users to do on-chain verification for bitcoin |
| 10 | +transactions on CKB chain. |
| 11 | + |
| 12 | +## Background |
| 13 | + |
| 14 | +For understanding this document, the knowledge of the following concepts are |
| 15 | +**required**.\ |
| 16 | +But we won't discuss them here, please learn them on their own documents. |
| 17 | + |
| 18 | +### Simplified Payment Verification (SPV) |
| 19 | + |
| 20 | +[Simple Payment Verification][SPV], usually abbreviated to SPV, is noted in |
| 21 | +Bitcoin whitepaper. It allows a transaction recipient to prove that the |
| 22 | +sender has control of the source funds of the payment they are offering |
| 23 | +without downloading the full Blockchain, by utilizing the properties of |
| 24 | +Merkle proofs. |
| 25 | + |
| 26 | +### Bitcoin Difficulty Adjustments |
| 27 | + |
| 28 | +Every 2016 blocks (which should take two weeks if this goal is kept |
| 29 | +perfectly), every Bitcoin client compares the actual time it took to |
| 30 | +generate these blocks with the 2 weeks goal and modifies the target by the |
| 31 | +percentage difference.[^1] |
| 32 | + |
| 33 | +> [!Note] |
| 34 | +> The difficulty re-target being based on the time taken for the previous |
| 35 | +> 2015 blocks instead of 2016 blocks.[^2] |
| 36 | +
|
| 37 | +### Bitcoin Merkle Proof |
| 38 | + |
| 39 | +A proof that proves a transaction (in fact, just transaction hash) was |
| 40 | +included in a block. |
| 41 | + |
| 42 | +It could be fetched through the RPC API [`gettxoutproof`], and be verified |
| 43 | +with the RPC API [`verifytxoutproof`]. |
| 44 | + |
| 45 | +### Merkle Mountain Range (MMR) |
| 46 | + |
| 47 | +A [Merkle Mountain Range (MMR)][MMR] is a binary hash tree that allows for |
| 48 | +efficient appends of new leaves without changing the value of existing nodes. |
| 49 | + |
| 50 | +An MMR proof could be used to prove whether an item is included in an MMR |
| 51 | +root or not. |
| 52 | + |
| 53 | +## Overview |
| 54 | + |
| 55 | +First, we could divide the whole problem into 2 smaller and standalone problems. |
| 56 | + |
| 57 | +### 1. On CKB, prove a header belongs to the bitcoin chain |
| 58 | + |
| 59 | +#### 1.1. Data preparation stage |
| 60 | + |
| 61 | +Since we want to do on-chain verification, so the resources are limited, for |
| 62 | +example, we couldn't afford 100 MiB storage or 30 seconds expensive |
| 63 | +computation, on CKB. |
| 64 | + |
| 65 | +So, we introduce the [Merkle Mountain Range (MMR)][MMR] to solve this |
| 66 | +problem: we only save the MMR root of bitcoin headers on CKB. |
| 67 | + |
| 68 | +- First, we initialize a cell with a bitcoin header at any height. |
| 69 | + |
| 70 | + An MMR tree will be constructed with this header only, and its root will |
| 71 | + be saved in the cell data. |
| 72 | + |
| 73 | + No on-chain verification will be done for this data. |
| 74 | + Users have to check the data off-chain, then trust it. |
| 75 | + |
| 76 | +- Also, there will be a service, which builds the same MMR tree but off-chain. |
| 77 | + |
| 78 | + This service will listen to the bitcoin chain and wait for the next block. |
| 79 | + |
| 80 | + When the next bitcoin block is mined, this service will append this new |
| 81 | + bitcoin block into the MMR tree, calculate a new MMR root, then send the |
| 82 | + new MMR root and the new header to the CKB chain. |
| 83 | + |
| 84 | +- An on-chain script will check those new data. |
| 85 | + |
| 86 | + - First, check the new header with two parts: |
| 87 | + |
| 88 | + - The field "previous block header hash" in headers[^3] should be correct. |
| 89 | + |
| 90 | + - The POW for the block should be valid. |
| 91 | + |
| 92 | + For security, the on-chain script has to calculate the POW target for |
| 93 | + the next block by itself. |
| 94 | + |
| 95 | + So, there are two more data have to be cached on chain: |
| 96 | + |
| 97 | + - The start time of the first block after difficulty adjustment. |
| 98 | + |
| 99 | + - If the next block is one of the first blocks after difficulty |
| 100 | + adjustment, its target should be calculated and cached. |
| 101 | + |
| 102 | + - Then, check the new MMR root: |
| 103 | + |
| 104 | + - The new MMR root should be constructed based on the previous MMR root, |
| 105 | + and only the new header should be appended. |
| 106 | + |
| 107 | + After the above checks passed, then save the new data into the cell. |
| 108 | + |
| 109 | +> [!NOTE] |
| 110 | +> In bitcoin headers, the height is not stored, but we have to store all |
| 111 | +> heights on CKB chain.\ |
| 112 | +> The heights are required for two reasons: calculate the index of MMR and |
| 113 | +> calculate the block confirmations. |
| 114 | +
|
| 115 | +#### 1.2. Verification stage |
| 116 | + |
| 117 | +With the stored MMR root on CKB, an on-chain script can check whether a |
| 118 | +bitcoin header is contained in that MMR tree. |
| 119 | + |
| 120 | +There are 3 items required to be submitted to the CKB chain: |
| 121 | +- The MMR proof of the header which is required to be proven. |
| 122 | +- The full data of the header, or its hash. |
| 123 | +- The height of the header. |
| 124 | + |
| 125 | +As the PoW of the header has been verified, if a header is contained within the |
| 126 | +MMR tree on CKB, it implies that the corresponding header is part of the Bitcoin |
| 127 | +chain. |
| 128 | + |
| 129 | +### 2. On CKB, prove a transaction is in a bitcoin block |
| 130 | + |
| 131 | +#### 2.1. Data preparation stage |
| 132 | + |
| 133 | +No more data is required to be stored in the CKB chain for transactions |
| 134 | +verification. |
| 135 | + |
| 136 | +#### 2.2. Verification stage |
| 137 | + |
| 138 | +There is a field "merkle root hash" in bitcoin headers[^3]. |
| 139 | + |
| 140 | +A merkle root is derived from the hashes of all transactions included in |
| 141 | +that block, ensuring that none of those transactions can be modified without |
| 142 | +modifying the header. |
| 143 | + |
| 144 | +So, a transaction could be verified whether it's in a header, with the |
| 145 | +merkle root hash and a merkle proof which contains it. |
| 146 | + |
| 147 | +## Optimization |
| 148 | + |
| 149 | +Save any data on chain will occupy the capacity of CKBytes permanently. And, |
| 150 | +not all bitcoin headers will be used.\ |
| 151 | +So, we won't save all bitcoin headers on the chain.\ |
| 152 | +For verification, we can just put them into the witnesses. |
| 153 | + |
| 154 | +When users want to verify a bitcoin header, they should submit that header |
| 155 | +to CKB chain, or only its hash is enough. |
| 156 | + |
| 157 | +But when verifies a bitcoin transaction, the full header is required to be |
| 158 | +submitted to CKB chain; because the "merkle root hash" in the header is |
| 159 | +required. \ |
| 160 | +An interesting fact is, that the merkle proof of the transaction already |
| 161 | +contains the full header.[^4] So the header doesn't have to be submitted |
| 162 | +alone. |
| 163 | + |
| 164 | +## Disadvantages |
| 165 | + |
| 166 | +- Calculate the MMR proof is not simple for normal users. |
| 167 | + |
| 168 | + A service is required, to collect all headers which are contained in the |
| 169 | + MMR root. |
| 170 | + |
| 171 | +## References |
| 172 | + |
| 173 | +- [`CalculateNextWorkRequired(..)`] |
| 174 | + |
| 175 | + The function, which is used to calculate the next target. |
| 176 | + |
| 177 | +- [`CPartialMerkleTree::ExtractMatches(..)`] |
| 178 | + |
| 179 | + The function ensures that the partial Merkle tree is correctly constructed. |
| 180 | + It is used to verify that a proof points to transactions. |
| 181 | + |
| 182 | +- [Merkle Mountain Ranges][MMR] |
| 183 | + |
| 184 | +<!-- |
| 185 | +
|
| 186 | + Links |
| 187 | +
|
| 188 | + --> |
| 189 | + |
| 190 | +[^1]: [Bitcoin Target](https://en.bitcoin.it/wiki/Target) |
| 191 | +[^2]: [Gaming the "off-by-one" bug (difficulty re-target based on 2015 instead of 2016 block time span)?](https://bitcoin.stackexchange.com/questions/1511) |
| 192 | +[^3]: [Bitcoin Block Headers](https://developer.bitcoin.org/reference/block_chain.html#block-headers) |
| 193 | +[^4]: [Bitcoin serialization format: Merkle proof](https://daniel.perez.sh/blog/2020/bitcoin-format/#merkle-proof) |
| 194 | + |
| 195 | +[`gettxoutproof`]: https://developer.bitcoin.org/reference/rpc/gettxoutproof.html |
| 196 | +[`verifytxoutproof`]: https://developer.bitcoin.org/reference/rpc/verifytxoutproof.html |
| 197 | + |
| 198 | +[`CalculateNextWorkRequired(..)`]: https://github.com/bitcoin/bitcoin/blob/v26.0/src/pow.cpp#L49 |
| 199 | +[`CPartialMerkleTree::ExtractMatches(..)`]: https://github.com/bitcoin/bitcoin/blob/v26.0/src/merkleblock.cpp#L149 |
| 200 | + |
| 201 | +[SPV]: https://bitcoinwiki.org/wiki/simplified-payment-verification |
| 202 | +[MMR]: https://github.com/opentimestamps/opentimestamps-server/blob/master/doc/merkle-mountain-range.md |
0 commit comments