chore: migrate motoko/basic_bitcoin to icp-cli#1372
Draft
marc0olo wants to merge 29 commits into
Draft
Conversation
Replace dfx.json with icp.yaml, restructure sources under backend/, and migrate management canister calls to mo:ic@4.0.0. Actor class with network parameter replaced by persistent actor with hardcoded regtest network. ECDSA/Schnorr APIs updated to call ic.ecdsa_public_key, ic.sign_with_ecdsa, ic.schnorr_public_key, and ic.sign_with_schnorr directly instead of through typed actor handles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…setup - Convert actor to persistent actor class with network init arg - Use test_key_1 for all networks (available in PocketIC) - Add Dockerfile + docker/start.sh for self-contained bitcoind regtest - Update icp.yaml with networks/environments and init_arg per env - Update CI workflow with Docker build steps, version 0.3.2, --cycles 30t - Expand Makefile with mining tests, topup target, BTC JSON-RPC tests - Fix BitcoinApi.mo and Utils.mo for mops check compatibility - Update README with Docker setup and multi-environment docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…keyword; drop type aliases - Dockerfile: icp-cli-network-launcher:0.3.2 → v14.0.0-2026-06-04-04-52 (correct tag) - app.mo: remove 'persistent' from actor class (redundant with --default-persistent-actors, M0217) - app.mo: remove redundant type aliases inside actor body; use Types.X directly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bitcoind is not in Debian trixie's apt repos. Download the official bitcoin-27.2 tarball from bitcoincore.org, verify the SHA256, extract only the two needed binaries, then purge curl to keep the image clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When icp-cli runs inside a container (icp-dev-env-motoko), it creates a temp status dir inside the container filesystem, then asks the host Docker daemon to bind-mount that path — which the daemon can't see. Run the job directly on ubuntu-24.04 (no container: wrapper) and install icp-cli + ic-wasm via npm. Paths created on the host are visible to Docker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tings icp-cli uses 'init_args' as a top-level environment field with canister names as keys, not 'init_arg' nested inside 'settings'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mo:ic@4.0.0 defines BitcoinNetwork = { #mainnet; #testnet } — no #regtest.
The local PocketIC Bitcoin subnet runs in regtest mode and rejects calls
using #testnet. Define an inline management canister actor type that uses
our own Network type (which includes #regtest) for the Bitcoin API calls.
mo:ic is still used for ECDSA and Schnorr signing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GetUtxosResponse → re-export IC.BitcoinGetUtxosResult (Blob for hashes) - BlockHash / Page type aliases removed (use Blob directly) - MillisatoshiPerVByte → MillisatoshiPerByte (matches IC spec naming) - BitcoinAddress → alias IC.BitcoinAddress - UtxosFilter: lowercase variants (#min_confirmations/#page) + Blob, matching IC - Cycles alias removed from all files (inlined as Nat) - BitcoinApi.mo: no more [Nat8] conversion for tip_block_hash/next_page - Types kept custom: Network (lowercase+regtest), NetworkCamelCase bridge, SendRequest, P2trDerivationPaths, EcdsaSignFunction, SchnorrSignFunction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rpcbind=127.0.0.1 bound RPC only to localhost inside the container, blocking connections from outside even with the port mapped in icp.yaml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
icp-cli applies port mappings correctly, but relying on curl over a mapped port introduces fragile network assumptions (port availability, NAT, IPv4/IPv6 resolution). docker exec runs bitcoin-cli directly inside the already-running container — zero network configuration, always reliable. - Makefile: mine blocks via docker exec (find container by ancestor image) - icp.yaml: remove unused 18443:18443 port mapping Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename Docker image basic-bitcoin-launcher → icp-cli-network-launcher-bitcoin to make clear this is a network launcher variant - Test 6: grep for 'tip_height = 101' instead of 'utxos' — the blob field in the Candid output contains binary data that interferes with grep; tip_height = 101 unambiguously confirms the Bitcoin blockchain synced Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- P2WPKH address generation (adapted from mo:bitcoin PR#9) Send function pending BIP143 sighash support in mo:bitcoin - get_block_headers via IC management canister - ecdsa_mock_signer → mock_sign_with_ecdsa (matches Rust naming) - schnorr_mock_signer → mock_sign_with_schnorr - Improve fee estimation comments to match Rust clarity Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ble) - Remove get_p2wpkh_address and P2wpkh.mo — send_from_p2wpkh_address requires BIP143 sighash support not yet in mo:bitcoin; commented on PR#9 with details - Add get_blockchain_info via inline management canister actor — returns chain height, block hash, timestamp, difficulty, and UTXO set size Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BitcoinApi.mo: replace management canister proxy with direct Bitcoin canister
calls. bitcoinCanister(network) selects the right principal at runtime:
#mainnet → ghsi2-tqaaa-aaaan-aaaca-cai
#testnet/#regtest → g4xu7-jiaaa-aaaan-aaaaq-cai
Actor type mirrors the official Bitcoin canister Candid:
https://github.com/dfinity/bitcoin-canister/blob/master/canister/candid.did
- get_block_headers and get_blockchain_info now go through BitcoinApi
(no inline actor workarounds needed)
- app.mo: derive KEY_NAME from NETWORK:
#mainnet → 'key_1' (ICP mainnet Bitcoin production key)
#testnet/#regtest → 'test_key_1' (ICP mainnet staging + local)
- Only ECDSA/Schnorr threshold signing still goes through aaaaa-aa
(management canister, as intended)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove NetworkCamelCase and network_to_network_camel_case from Types.mo (implementation detail, not part of public API); inline the PascalCase conversion directly in P2pkh.mo where it is actually used - Remove P2WpkhAddress type (P2WPKH was removed from the example) - Drop PR#22 reference from Network type comment — that issue is closed; simplify to state the factual reason (mo:bitcoin uses PascalCase) - Remove repeated 'See docs URL' doc comments from BitcoinApi.mo — one link in the README is sufficient; per-function links add noise Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On Apple Silicon (arm64), Docker runs linux/arm64 containers natively. Downloading the x86_64 binary silently fails and hangs the startup loop. Use TARGETARCH to select the correct binary for amd64 or arm64. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The arm64 variant of icp-cli-network-launcher:latest does not support --pocketic-config-bind (added in interface v1.1.0). Remove it — the launcher binds the config port on all interfaces by default. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a macos-latest (arm64) CI job with continue-on-error: true. Currently expected to fail due to a canister_status Candid decode error on the arm64 icp-cli-network-launcher image (log_memory_store_size field not handled by icp-cli 0.3.2). Tracked in dfinity/icp-cli#601. Uses colima to provide Docker on macOS runners. Remove continue-on-error once the upstream icp-cli issue is resolved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The default QEMU VM type fails on GitHub Actions arm64 runners. Apple Virtualization Framework (vz) is required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Standard GitHub-hosted macOS runners don't support VM creation (neither QEMU nor Apple VZ), so Docker containers can't run. The arm64 issue is tracked upstream in dfinity/icp-cli#601. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds an ubuntu-24.04-arm job that natively replicates the arm64 canister_status Candid decode failure (log_memory_store_size) seen on Apple Silicon. Uses continue-on-error: true until dfinity/icp-cli#601 is resolved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The arm64 Linux runner passes. The canister_status decode failure is macOS arm64 icp-cli binary-specific, not a Linux arm64 issue. Updated dfinity/icp-cli#601 with the confirmed root cause. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates
motoko/basic_bitcoinfrom dfx to icp-cli with a self-contained local Bitcoin testing environment.Infrastructure:
dfx.jsonwithicp.yamlusing@dfinity/motoko@v5.0.0; three environments:local(regtest),staging(testnet4),production(mainnet)actor class BasicBitcoin(network : Types.Network)configured viainit_argsper environmenticp-cli-network-launcher-bitcoin) that extends the official network launcher withbitcoindin regtest mode — fully self-contained local testing, no external Bitcoin node requireddfx.json,BUILD.md,.devcontainer/Canister code:
src/basic_bitcoin/src/→backend/; renameMain.mo→app.moBitcoinApi.mo: call the Bitcoin canister directly at its network-specific principal (not the management canister proxy).bitcoinCanister(network)selectsghsi2-...(mainnet) org4xu7-...(testnet/regtest) at runtime. Actor type mirrors the official Bitcoin canister CandidEcdsaApi.mo/SchnorrApi.mo: usemo:icdirectly (ic.ecdsa_public_key,ic.sign_with_ecdsa,ic.schnorr_public_key,ic.sign_with_schnorr) — threshold signing still goes through the management canisteraaaaa-aaKEY_NAMEderived from network:key_1(mainnet) ortest_key_1(testnet4 + local regtest)get_block_headersandget_blockchain_infoviaBitcoinApimops.toml: moc 1.9.0, core 2.5.0, ic 4.0.0,--default-persistent-actorsTypes.mo: reduced to types not available inmo:bitcoinormo:ic;Utxo/OutPointaliased frommo:bitcoin; useBlobfor block hashes (not[Nat8])Tests (
Makefile):docker execinto the running network launcher container (no port mapping needed)Test plan
motoko-basic_bitcoinCI passes🤖 Generated with Claude Code