Direct Integration with Bitcoin

The Bitcoin canister, which tracks the UTXO set, does not know which addresses all the user canisters created and gave out. A user canister can create a deposit address in canister code and hand it out to a some other user who can then make a deposit into that address. Then the user canister later wants to be able to ask the Bitcoin canister about the balance in that address. If the Bitcoin canister did not have the entire UTXO set then it would not be able to answer. The addresses that user canisters create cannot be foreseen as they are chosen from a practically unbounded hierarchical address space.


How about notifying the Bitcoin Canister to cache the related utxo like light client

Seems to make for unnecessarily complicated programming and possibly even serious limitation. If a notification is required then the canister code can not directly answer a call with a deposit address. It has to do a round trip through the Bitcoin canister first, adding latency. If we notify the Bitcoin canister about an address only later then there is a race condition. Does the notification come in first or the deposit? If the latter then the deposit would get missed. Unless the Bitcoin canister gets a feature to query UTXOs that were created in the past from other Bitcoin nodes, which now complicates its code. It now has to be able to process Merkle proofs and the Bitcoin adapter has to get a new feature to make those queries. It just seems to get really messy. The serious limitation could be if deposit address are created outside (externally, off-chain), e.g. in frontend code or even in scenarios that are entirely offline, which are possible with HD-derivation. Then there is no way to notify the Bitcoin canister.

Notification also open an attack vector on the Bitcoin canister. I can now ask the Bitcoin canister to track millions of address that I never actually use.


Gotu. So how about only calculating the utxo for new addresses of the btc network. Considering snapshoting all existing addresses in a set, and only cache utxo for newly generated addresses. That would still cut all pre existing utxos

Good idea. I think that could work. Or could have worked if that path had been chosen earlier. From where the implementation stands now the fastet way to launch is propably not touching that aspect anymore and increasing the stable memory size instead (my guess, I can’t speak for the team that is working on it).

A different aspect: over time I would certainly like to see the Bitcoin integration move into the opposite direction and store the entire Bitcoin blockchain, i.e. all historical transaction including spent outputs. Could be spread over multiple canisters. Then we would have a block explorer running on chain which is something that doesn’t exist in the world. There simply are no decentralized block explorers, hence there are no trustless block explorers right now. Likewise, there are no trustless Bitcoin full nodes that SPV nodes can connect to. A decentralized Bitcoin full node on the IC would be hugely beneficial for the Bitcoin ecosystem. For example, for smartcards or IoT devices accepting Bitcoin. They can then just validate a single signature created by the IC subnet instead of having to validate Merkle proofs and proof-of-work header segments.


See the threshold ECDSA forum thread

1 Like

That Bitcoin to/from ckBTC demo in the Global R&D Meeting just now was fantastic. Does anyone know who gave that presentation, or where the demo code lives? I’m looking to integrate payments into my grant project at this exact moment and that code would be incredibly helpful!

The demo I’m talking about is the ckBTC Minting Demo hosted on the IC here, that lets you convert Bitcoin to/from ckBTC, which can be transferred easily/cheaply/quickly throughout the IC.


Glad you liked the demo! The canister code is ic/rs/bitcoin/ckbtc at master · dfinity/ic · GitHub, I don’t think the front end is checked in as it’s just for the demo, but I guess the backend is what you’re most interested in?


I’m definitely interested most in the backend. But it looks like I might need to learn Rust; the rest of my codebase is in Motoko and that’s where my experience lies. Any chance there will be a Motoko version of demo code? Or am I wrong when thinking that I would need to implement all the backend code you linked to in my own canisters, and maybe it’s just a public canister on the IC somewhere that I would be interacting with, or maybe a library I could import with Vessel?

Either way, frontend code would be handy to see the usage of the backend canister during all the operations shown in the demo.


Hi @mymikemiller, I am the one who gave the demo. Really happy to hear that you liked it :slight_smile:
If you want I can make a repo with the frontend code, it’s a react app. It may be a good starting point if you want to understand how to interact with the minter and the ledger.
If don’t know rust you can still interact with the minter using minter.did. You just have to know the canister id and the did interface to interact with another canister from your canister. But probably that taking a look at the code will help you to understand.
We will probably not make a motoko version any soon. I will try to see where is the best place to share my code and keep you up to date.


Fantastic demo, @0rions! If I’m interpreting you correctly, I ought to be able to import your ic-ckbtc-minter canister by specifying its IC cid in an Actor’s constructor like this, which also currently requires me to duplicate the canister’s interface (i.e. there’s no way to specify the .did file you linked to and have it infer the interface from that), then use its public functions like any of my local canisters, right? I’ve never imported a canister from the IC.

I believe that means I will need to provide my own implementation for local development since local canisters can’t access IC canisters, and I could do that by compiling my own local canister from your above-linked Rust source, or at least by making a mock canister with the same interface as described here.

The cid I would pass to the constructor when creating the ic-ckbtc-minter Actor is not the cid in the url you listed in the demo, waaaa-aaaag-qazsa-cai, though, since that’s the cid for the frontend, right? What’s the cid for the backend canister where the backend functions live?

1 Like

An amazing project which has a high futuristic growth potential, capable of moving to the moon

Hey Manu,

Has Dfinity given further thought as to how it wants to approach the Ethereum integration? It will be amazing when we can use ICP Dexes to do bitcoin <> eth swaps. Will create demand to burn cycles among folks who don’t even want to use icp!


Hey everyone, we’re happy to share that we are still on track to launch the Bitcoin integration this week. Since the Bitcoin mainnet canister will be under NNS control (just like existing NNS canisters and internet identity), the launch will consist of three NNS proposals, all in the topic of “system canister management”:

  1. A proposal to install an uploader canister. This is a canister that will be used to upload a precomputed state of the Bitcoin mainnet canister at a height of 764,684.

  2. A proposal to upgrade the uploader canister to the Bitcoin mainnet canister. The canister will start syncing new blocks, but the endpoints of the canister will be disabled.

  3. A proposal to enable the endpoints of the Bitcoin mainnet canister, making them accessible and concluding the launch.

Why upload a precomputed state of the Bitcoin mainnet canister?

The alternative to precomputing the state of the canister would be to sync from genesis. However, a full sync of Bitcoin mainnet from genesis would take weeks. Precomputing the state offline, on the other hand, takes ~24 hours and uploading it takes ~12-18 hours.

How can I verify the Wasm hash of the uploader canister and the bitcoin canister?

  • Clone the bitcoin-canister repo.
  • Checkout the launch branch.
  • Run docker build -t canisters . to build the canisters and output their Wasm hashes.

How can I verify the state that will be uploaded?

We’ll be uploading the state using what we call the uploader canister. Once the uploader canister is deployed, we can upload “chunks” of the bitcoin canister’s state using ingress messages. The uploader canister is initialized with the hashes of each of these chunks to verify their correctness, meaning that the NNS still controls the state that will be uploaded. Here you’ll find the hashes of the chunks, which are hard-coded in the uploader canister.

If you’d like to compute the Bitcoin canister’s state for yourself to verify the correctness of these hashes, please follow the instructions here, setting the HEIGHT to 764684. Note that the computation takes around 24 hours. At different points in the computation process, the checksums of various files are emitted. If everything is working as expected, you should see the following checksums:

sha256sum unstable_blocks
c62e653e80c11c5463cfd24af8d26eef4392d6b9600ab6278d61f29f159c1e1a  unstable_blocks

sha256sum block_headers
b7047039bccb1eb81c7df97ba4dcd04ae6163277909bcded7789b73512e29544  block_headers

sha256sum utxodump.csv
ec09112894aad807b90f9991be76105e41e9038687b59dce5a1aaadcedf52ddc  utxodump.csv

sha256sum utxodump_shuffled.csv
9730fddcf70afc60bfb94d0bcddd82b2e807cf57842733176dec1d31b0dedc05  utxodump_shuffled.csv

sha256sum canister_state.bin
1cf90cc7abdd859be021f35e1066965b7d1f23add33ddc4650ff3d27663211ec  canister_state.bin

Once you’re done with the instructions, you’ll have a file called chunk_hashes.txt, which should be identical to the hard-coded chunk_hashes.txt file in the uploader canister.

git switch launch   # switch to the launch branch.

# The chunk hashes you computed and the ones hard-coded in the uploader canister
# should be identical.
diff chunk_hashes.txt ./uploader/src/chunk_hashes.txt 

If you managed to recompute this state and verify its integrity, or if you tried but ran into issues, please let us know here!


I am running the verification steps and will report back when it’s done!


Quick update: we just submitted proposal 94253, the first of the three proposals mentioned in my previous post, that installs the uploader canister.


Does this mean Bitcoin Integration is finally released after the proposal passes?

No, the first proposal will allow us to start uploading the bitcoin state. The Bitcoin integration will be considered released once all the three proposals I mention are submitted and passed.


Why don’t you submit the proposals at the same time? Do we really have to wait 3 days for each proposal to pass (in total 9 days)?


I managed to complete all the verification steps in an ubuntu VM on my laptop, and also landed on the initial canister state

1cf90cc7abdd859be021f35e1066965b7d1f23add33ddc4650ff3d27663211ec canister_state.bin

It did take a long time to sync the full bitcoin blockchain and compute everything from it. I computed unstable_blocks and block_headers without issues. I did run into an issue with computing utxodump.csv and utxodump_shuffled.csv: it seems that sort -n is not fully deterministic and my result was slightly differently sorted than @ielashi’s. I resolved this by downloading @ielashi’s versions, and ensured that what I computed is equal to his versions after doing a sort (without the -n), such that I’m still entirely sure that it contains the right UTXOs. From that, I computed the expected canister_state.bin.

We’ll make @ielashi’s utxodump_shuffled.csv available here, such that if anybody else runs into the sort -n issue, they can follow the same steps as I did to still verify the correctness of the initial state.