Bitcoin node in your pocket in under an hour.
Turn any Android phone into a fully-validating Bitcoin full node. No server dependency, no ongoing tethering. Your phone becomes a sovereign Bitcoin node.
📖 Project overview and how chainstate copy works
- Two proven bootstrap paths: sync from home node (under 1 hour) or download from internet (3-6 hours, on-chain only)
- Phone-to-phone sharing (built, untested on second device): scan a QR code, get a full node. No servers, no accounts
- 3 Bitcoin implementations: Core 30, Core 29.3, Knots 29.3 (all with BIP 110 toggle). Switch with one tap, same chainstate
- No thermal load: phone shows no sign of load or overheat during normal operation
- ~26 GB total disk with Lightning (11 GB chainstate + 2 GB pruned blocks + 13 GB block filters), ~13 GB without
- Pure Kotlin Electrum server with wallet tracking: balance, transactions, UTXOs all served from your own pruned node
- Built-in Lightning wallet powered by LDK: send, receive, BOLT12 offers, open/close channels, peer browser, QR codes
- LNDHub API for external Lightning wallets (BlueWallet)
- P2P port exposed on localhost:8333 for Neutrino-compatible wallets
- Proactive prune recovery re-downloads missed blocks on startup when node was offline
- Embedded Tor for direct .onion watchtower connections (no Orbot, no SSH tunnel needed)
Running on a Pixel 7 Pro with GrapheneOS
First run
| Setup screen | Setup checklist | Version picker |
![]() |
![]() |
![]() |
Node + On-chain wallet
| Node dashboard | Electrum server | BlueWallet connected | BlueWallet wallet |
![]() |
![]() |
![]() |
![]() |
Lightning Wallet
| Dashboard | Lightning wallet | Watchtower + Seed | Peer browser |
![]() |
![]() |
![]() |
![]() |
Three bootstrap paths. Pick whichever suits your situation:
- App connects to your home node (Umbrel, Start9, any Bitcoin node) via SSH
- Briefly stops bitcoind, archives chainstate + block index + block filters
- Downloads the archive (~24 GB with Lightning filters), extracts, starts bitcoind
- Full node at chain tip. Includes block filters for Lightning if your node has them
- A friend with Pocket Node opens Share, which shows a QR code
- You scan it (or visit the URL on any browser to download the app first)
- Chainstate + block filters transfer directly over WiFi, phone to phone
- No home node needed. Zero accounts, zero servers, just two phones on the same network
- Download a UTXO snapshot (~9 GB) from utxo.download
- App loads it via
loadtxoutset(cryptographically verified by Bitcoin Core) - Phone syncs forward from the snapshot height (~30 min to load, 2-5 hours to reach tip)
- Background validation confirms everything independently from genesis
Note: AssumeUTXO does not build block filter indexes, so Lightning is not available until background validation completes. Good for on-chain use (BlueWallet, Electrum) while validation runs.
See Direct Chainstate Copy for a detailed comparison.
Your node, your rules. Choose which Bitcoin implementation runs on your phone:
| Implementation | Size | Policy |
|---|---|---|
| Bitcoin Core 29.3 | 8 MB | Standard relay rules, BIP 110 compatible (v72t's port) |
| Bitcoin Core 30 | 8.6 MB | Permissive: larger OP_RETURN data allowed |
| Bitcoin Knots 29.3 | 12 MB | Restrictive: filters non-standard transactions |
All implementations support the universal BIP-110 signaling toggle.
All three share the same chainstate format. Switch without re-syncing. Tap "Change" on the dashboard, confirm, and the node restarts with the new binary.
BIP 110 (bip110.dev) temporarily limits arbitrary data embedding at the consensus level. A universal toggle enables version bit 4 signaling and peer preference for reduced data carriers on both Core 29.3 and Knots. Built from Dathon Ohm's reference implementation with a 55% activation threshold.
See Version Selection Design and BIP 110 Research for details.
- 3 Bitcoin implementations with one-tap switching: Core 30, Core 29.3, Knots 29.3. Universal BIP 110 signaling toggle
- Two proven bootstrap paths: home node or internet download (phone-to-phone built, untested)
- Pure Kotlin Electrum server purpose-built for pruned nodes: the only Electrum server that works with
prune=2048. Balances from the UTXO set, transaction history persisted forever (survives pruning), unsolicited notifications push new transactions to BlueWallet in real time - Built-in Lightning node powered by LDK (send, receive, channels, peer browser, seed backup/restore with automatic fund recovery)
- LNDHub API on localhost:3000 for external wallet connectivity (BlueWallet)
- P2P port exposed on localhost:8333 for Neutrino-compatible wallets
- Wallet birthday recovery: automatic fund discovery on seed restore via UTXO scan with live progress, instant restore for wallets with saved birthday
- Home node watchtower with automatic channel protection via LDK-to-LND bridge (direct Tor .onion or SSH fallback)
- BOLT12 support: send to offers, create reusable offers, variable-amount offers
- QR codes: generate on receive, scan with camera on send (CameraX + ZXing, no Google Play)
- Sovereign price discovery using UTXOracle (BTC/USD from on-chain data, no exchange APIs)
- Mempool viewer with fee estimates, projected blocks, and transaction search
- Wallet tracking with history recovery from mempool.space, transaction hex caching, and gap limit discovery
- BlueWallet integration tested: balance display, transaction history, pull-to-refresh all working on pruned node
- Snapshot validation checks block hash before loading, auto-redownloads if wrong
- Non-blocking snapshot load with progress tracking
- Network-aware sync with automatic power mode detection
- VPN-aware networking: Detects actual connection type behind VPN (cellular vs WiFi)
- Data budgets for WiFi and cellular
- Power modes: Max Data, Low Data, Away Mode with burst sync for mobile efficiency
- Auto data mode: detects WiFi/cellular and charging state, adjusts automatically
- Auto-start on boot
- Secure node pairing with restricted SFTP account (no access to your bitcoin data)
- Setup checklist with auto-detection of completed steps
- Live dashboard showing block height, sync progress, peers, mempool, disk usage
- Partial mempool (50 MB) with persistence across restarts (survives nightly reboot)
The app connects to your home node via SSH, briefly stops bitcoind, and copies:
chainstate/(the UTXO set, ~11 GB)blocks/index/(block metadata, ~2 GB)blocks/xor.dat(block file obfuscation key)- Tip block/rev files (latest block data)
Total transfer ~13 GB over LAN (~5 min). Node operational in under an hour including setup.
- Generates a UTXO snapshot using
dumptxoutset rollback - Downloads via SFTP over LAN (~5 min for 9 GB)
- Loads via
loadtxoutset
The app tries saved pocketnode SFTP credentials first. If a snapshot already exists on the server, no admin credentials are needed.
Download from https://utxo.download/utxo-910000.dat (9 GB). Same loadtxoutset flow, just a different download source. The snapshot is cryptographically verified against the block hash compiled into Bitcoin Core before loading.
Note: This path provides an on-chain node only. Lightning support requires block filters (~13 GB) which can be added later by copying from a home node via SSH.
┌──────────────────────────────────────────────────┐
│ Android App (Kotlin) │
│ │
│ ┌──────────┐ ┌───────────┐ ┌───────────┐ │
│ │Chainstate│ │ Network │ │ Sync │ │
│ │ Manager │ │ Monitor │ │ Controller│ │
│ └────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ ┌────┴──────────────┴──────────────┴─────────┐ │
│ │ bitcoind (ARM64), user selects: │ │
│ │ Core 30 | Core 29.3 | Knots 29.3 │ │
│ │ (all with BIP 110 toggle) │ │
│ │ Foreground service, local RPC │ │
│ └────────────────┬───────────────────────────┘ │
│ │ RPC │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ ┌───┴──────┐ ┌───┴──────┐ ┌──┴───────────┐ │
│ │ Electrum │ │ ldk-node │ │ UTXOracle │ │
│ │ :50001 │ │(in-proc) │ │ price feed │ │
│ └───┬──────┘ └───┬──────┘ └──────────────┘ │
│ │ │ │
│ │ ┌──────┴───────┐ │
│ │ │ LNDHub API │ │
│ │ │ :3000 │ │
│ │ └──────┬───────┘ │
└──────┼────────────┼──────────────────────────────┘
│ │
BlueWallet BlueWallet
(on-chain) (Lightning)
When you pair with your home node, the app creates a restricted pocketnode user:
- SFTP-only. Cannot run commands, no shell access
- Chroot jailed. Can only see
/home/pocketnode/, nothing else - Zero data access. Cannot read your bitcoin data directory, wallet, configs, or logs
- Root-owned copy scripts bridge the gap, copying only snapshot files to the SFTP location
Admin SSH credentials are never saved (username is saved for pre-fill convenience). Always prompted, used once, discarded.
You can view the pocketnode credentials and fully remove access from the app at any time.
- Snapshots are verified against block hashes compiled into the Bitcoin Core binary
- The app also validates the snapshot file header before attempting to load
- A tampered or wrong-height snapshot is rejected before any data is used
- Background IBD independently validates everything from genesis (AssumeUTXO path)
network_security_config.xmlallows cleartext HTTP only to127.0.0.1(local RPC)- bitcoind runs as
libbitcoind.soinjniLibs/for GrapheneOS W^X compliance - No internet-facing ports. RPC and Electrum server are both localhost only
Built-in Lightning wallet powered by LDK (ldk-node 0.7.0). Runs in-process, connects to your local bitcoind via RPC. No external apps needed.
- Start your Bitcoin node and wait for sync
- Open the Lightning wallet from the dashboard
- Fund your on-chain wallet (receive bitcoin to the displayed address)
- Browse peers (Most Connected, Largest, Lowest Fee, or search) and open a channel
- Send and receive Lightning payments
bitcoind ← RPC → ldk-node (in-process)
│
┌───────┴────────┐
│ │
Built-in UI LNDHub API (:3000)
(send/receive/ │
channels) External wallets
(BlueWallet)
Why LDK? Earlier versions used Zeus with embedded LND, which required BIP 157/158 block filters and had a NODE_NETWORK service bit limitation with pruned nodes. LDK connects via RPC directly, so pruned nodes work natively. No service bit checks, no cross-app restrictions, no duplicate sync engine.
The app runs an LNDHub-compatible API server on localhost:3000. Connect BlueWallet in LNDHub mode to use your Lightning node from another app on the same phone.
Built-in peer browser using mempool.space API. Browse nodes by:
- Most Connected: highest channel count
- Largest: biggest total capacity
- Lowest Fee: cheapest routing fees
- Search: find nodes by name or pubkey
- OS: Android 7+ (tested on GrapheneOS, EMUI, Samsung OneUI)
- Hardware: Any ARM64 device (tested on Pixel, Samsung, Huawei)
- Default: Bitcoin Core 29.3 (BIP 110 compatible, standard relay rules)
- Also bundled: Core 30, Knots 29.3 (user selects from dashboard, all with BIP 110 toggle)
- AssumeUTXO heights: 840k (upstream) + 880k, 910k (backported from Core 30)
- macOS or Linux build machine
- Android SDK + NDK r27
- JDK 17
- Bitcoin Core 29.3 source (with BIP 110 and chainparams patches)
See docs/cross-compile-android.md
export ANDROID_HOME=/path/to/android-sdk
export JAVA_HOME=/path/to/jdk-17
./gradlew assembleDebugadb install -r app/build/outputs/apk/debug/app-debug.apkapp/src/main/java/com/pocketnode/
├── service/
│ ├── BitcoindService.kt # Foreground service managing bitcoind
│ ├── ElectrumService.kt # Electrum server lifecycle management
│ └── SyncController.kt # Network-aware sync pause/resume
├── lightning/
│ ├── LightningService.kt # ldk-node wrapper (start/stop, channels, payments)
│ └── LndHubServer.kt # LNDHub-compatible API server on localhost:3000
├── electrum/
│ ├── ElectrumServer.kt # Electrum protocol TCP server (batch JSON array responses)
│ ├── ElectrumMethods.kt # Electrum RPC method handlers (pruned-node tx fallbacks)
│ ├── AddressIndex.kt # Descriptor wallet, UTXO cache, tx hex cache, recovery
│ ├── HistoryRecovery.kt # mempool.space history recovery with gap limit + backoff
│ └── SubscriptionManager.kt # Address/header subscription notifications
├── power/
│ └── PowerModeManager.kt # Max/Low/Away power modes with burst sync
├── network/
│ └── NetworkMonitor.kt # WiFi/cellular/VPN detection + data tracking
├── snapshot/
│ ├── ChainstateManager.kt # AssumeUTXO snapshot flow (generate/download/load)
│ ├── BlockFilterManager.kt # Lightning block filter copy/remove
│ ├── NodeSetupManager.kt # SSH setup + teardown
│ └── SnapshotDownloader.kt # SFTP download with progress
├── ssh/
│ └── SshUtils.kt # Shared SSH/SFTP utilities
├── rpc/
│ └── BitcoinRpcClient.kt # Local bitcoind JSON-RPC (configurable timeouts)
├── ui/
│ ├── PocketNodeApp.kt # Navigation + top-level routing
│ ├── NodeStatusScreen.kt # Main dashboard
│ ├── LightningScreen.kt # Lightning node (balances, channels, watchtower status)
│ ├── SetupChecklistScreen.kt # Config mode setup wizard
│ ├── SnapshotSourceScreen.kt # Source picker
│ ├── ChainstateCopyScreen.kt # Snapshot load progress (4-step flow)
│ ├── ConnectWalletScreen.kt # RPC / Electrum / LNDHub connection guide
│ ├── BlockFilterUpgradeScreen.kt # Lightning block filter management
│ ├── WatchtowerScreen.kt # Home node watchtower setup
│ ├── DataUsageScreen.kt # Data usage breakdown
│ ├── NetworkSettingsScreen.kt # Cellular/WiFi budgets
│ ├── NodeAccessScreen.kt # View/remove node access
│ ├── NodeConnectionScreen.kt # Remote node connection setup
│ ├── InternetDownloadScreen.kt # HTTPS snapshot download
│ ├── lightning/
│ │ ├── SendPaymentScreen.kt # Pay BOLT11 invoices
│ │ ├── ReceivePaymentScreen.kt # Generate invoices
│ │ ├── PaymentHistoryScreen.kt # Payment list
│ │ ├── OpenChannelScreen.kt # Open channel to peer
│ │ ├── PeerBrowserScreen.kt # Browse/search Lightning peers
│ │ ├── SeedBackupScreen.kt # BIP39 seed view and restore
│ │ ├── QrCode.kt # QR code generation (ZXing)
│ │ └── QrScannerScreen.kt # Camera QR scanner (CameraX + ZXing)
│ ├── PowerModeSelector.kt # Three-segment power mode toggle + burst banner
│ └── components/
│ ├── NetworkStatusBar.kt # Sync status banner
│ └── AdminCredentialsDialog.kt # SSH creds prompt
├── lightning/
│ ├── LightningService.kt # ldk-node singleton wrapper
│ ├── LndHubServer.kt # LNDHub API server (:3000)
│ ├── WatchtowerBridge.kt # LDK-to-LND watchtower push via SSH + Brontide
│ ├── WatchtowerNative.kt # JNA bindings to native Rust watchtower client
│ └── Bip39.kt # Pure Kotlin BIP39 (mnemonic ↔ entropy)
├── oracle/
│ └── UTXOracle.kt # Sovereign price discovery from on-chain data
└── util/
├── ConfigGenerator.kt # Mobile-optimized bitcoin.conf
├── BinaryExtractor.kt # Version selection, 3 bundled bitcoind binaries
└── SetupChecker.kt # Auto-detect completed setup steps
- Build Guide
- Cross-Compile Guide
- Tor Integration
- Chainparams Patch
- Direct Chainstate Copy
- Snapshot Testing
- Umbrel Integration
- Block Filter Design
- Block Index Consistency
- Version Selection Design
- BIP 110 Research
- LDK Research
- Watchtower Mesh Design
- LDK-to-LND Watchtower Bridge
- Desktop Port Design
- Power Modes Design
- Pruned Node Risk Analysis
- LDK Upstream Contribution
- LDK Anchor Downgrade Bug
- Ark Integration Plan
- Built-in Tor Design
- iOS Port Feasibility
- Phone-to-Phone Sharing
- Tor for all traffic: route bitcoind, LDK peers, and HTTP calls through embedded Arti SOCKS proxy. One toggle for full network privacy. See design doc
- LDK upstream contribution: improving watchtower API in rust-lightning ChannelMonitor (#813). Draft PR submitted.
- Upstream PRs: rust-lightning #4453 (justice tx API), ldk-node #822 (wallet birthday), rust-lightning #4485 (anchor downgrade bug)
- Ark integration: Community-scale trustless payments. Run an Ark Service Provider on your Umbrel, friends connect from their phones over Tor. No individual channel management, no routing failures, ASP can't steal funds. See design doc
- Desktop port: Same app on Linux, macOS, Windows via Compose Multiplatform. See design doc
- iOS port: Burst sync + watchtower + in-process LDK make iOS viable. See feasibility analysis
| Device | SoC | OS | Result |
|---|---|---|---|
| Pixel 9 | Tensor G4 | GrapheneOS | ✅ Full stack: chainstate copy, LDK Lightning, BIP 110, all features verified |
| Samsung Galaxy Z Fold | Snapdragon | Android | ✅ Dual-pane foldable layout working, IBD syncing |
| Huawei Mate 20 Lite | Kirin 710 | EMUI | ✅ Clean install, IBD syncing from genesis |
| Pixel 9 | Tensor G4 | GrapheneOS | ✅ Lightning send/receive verified, 7-day uptime confirmed by independent tester |
- 16KB page alignment warning on GrapheneOS (cosmetic only)
getblockchaininforeports background validation progress, not snapshot chain tip (AssumeUTXO path only)
MIT










