Skip to content

chore: migrate motoko/basic_bitcoin to icp-cli#1372

Draft
marc0olo wants to merge 17 commits into
masterfrom
chore/migrate-basic-bitcoin-to-icp-cli
Draft

chore: migrate motoko/basic_bitcoin to icp-cli#1372
marc0olo wants to merge 17 commits into
masterfrom
chore/migrate-basic-bitcoin-to-icp-cli

Conversation

@marc0olo

Copy link
Copy Markdown
Member

Summary

  • Replace dfx.json with icp.yaml using @dfinity/motoko@v5.0.0 recipe
  • Move all source files from src/basic_bitcoin/src/ to backend/, renaming Main.mobackend/app.mo
  • Convert actor class BasicBitcoin(network) to a persistent actor with hardcoded #regtest network (suitable for local development; change to #testnet for IC deployment)
  • Replace all actor("aaaaa-aa") and inline management canister actor types with import { ic } "mo:ic" (mo:ic@4.0.0)
  • Update EcdsaApi.mo and SchnorrApi.mo to call ic.ecdsa_public_key, ic.sign_with_ecdsa, ic.schnorr_public_key, ic.sign_with_schnorr directly — no longer accept canister actor handles as parameters
  • Update BitcoinApi.mo to use ic.bitcoin_get_balance, ic.bitcoin_get_utxos, ic.bitcoin_get_current_fee_percentiles, ic.bitcoin_send_transaction; bridge the #regtest variant (not in mo:ic's BitcoinNetwork) by mapping it to #testnet at the API boundary; convert Blob[Nat8] as needed
  • Update Types.mo and Utils.mo: remove per-canister actor type aliases; update EcdsaSignFunction/SchnorrSignFunction to omit the canister actor parameter
  • Update mops.toml: bump moc to 1.9.0, core to 2.5.0, add ic = "4.0.0", add --default-persistent-actors moc flag
  • Add Makefile with 5 numbered tests covering address generation and balance/fee queries
  • Add CI workflow .github/workflows/basic_bitcoin.yml (Motoko-only job, Rust migration is a separate PR)
  • Update README.md to use icp-cli commands
  • Delete dfx.json, BUILD.md, .devcontainer/, src/basic_bitcoin/basic_bitcoin.did

Test plan

  • icp network start -d — local replica starts successfully
  • icp deploy — backend canister compiles and deploys without errors
  • make test — all 5 tests pass:
    • Test 1: get_p2pkh_address returns a non-empty string address
    • Test 2: get_p2tr_key_only_address returns a non-empty string address
    • Test 3: get_p2tr_address returns a non-empty string address
    • Test 4: get_balance for the P2PKH address returns a Nat64 (0 is acceptable on local replica)
    • Test 5: get_current_fee_percentiles returns without error
  • CI workflow runs on pull_request targeting motoko/basic_bitcoin/**

🤖 Generated with Claude Code

marc0olo and others added 17 commits June 10, 2026 17:29
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant