diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 07f5c90..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-# EditorConfig helps maintain consistent coding styles
-# https://editorconfig.org
-
-root = true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[Makefile]
-indent_style = tab
diff --git a/.github/workflows/amd64-image-test.yml b/.github/workflows/amd64-image-test.yml
deleted file mode 100644
index bc403df..0000000
--- a/.github/workflows/amd64-image-test.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: amd64-image-test
-
-concurrency:
- group: amd64-image-test-${{ github.event.workflow_run.id || inputs.run_id || github.run_id }}
- cancel-in-progress: true
-
-on:
- workflow_run:
- workflows: ["amd64-image-build"]
- types: [completed]
- workflow_dispatch:
- inputs:
- run_id:
- description: "amd64-image-build workflow run ID to test"
- required: true
- type: string
-
-permissions:
- actions: read
- contents: read
-
-jobs:
- bats-image-test:
- name: Run Bats against amd64 image artifact
- runs-on: ubuntu-22.04
- timeout-minutes: 240
- if: ${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_repository.full_name == github.repository) }}
-
- steps:
- - uses: actions/checkout@v4
- with:
- repository: ${{ github.event.workflow_run.head_repository.full_name || github.repository }}
- ref: ${{ github.event.workflow_run.head_sha || github.ref }}
-
- - name: Check out bats-core
- uses: actions/checkout@v4
- with:
- repository: bats-core/bats-core
- # bats-core v1.12.0
- ref: 713504bc0224a19b3d7c7958c18dc07f64f54b44
- path: .bats-core
- persist-credentials: false
-
- - name: Download amd64 image artifact
- uses: actions/download-artifact@v4
- with:
- github-token: ${{ github.token }}
- run-id: ${{ github.event.workflow_run.id || inputs.run_id }}
- pattern: joininbox-amd64-image-*
- path: artifacts
- merge-multiple: true
-
- - name: Verify and decompress image
- shell: bash
- run: |
- set -euo pipefail
-
- cd artifacts
- sha256sum -c joininbox-amd64-debian.qcow2.gz.sha256
- gzip -dk joininbox-amd64-debian.qcow2.gz
- sha256sum -c joininbox-amd64-debian.qcow2.sha256
-
- - name: Run image Bats tests
- timeout-minutes: 30
- run: ci/amd64/test.amd64-image-bats.sh "${GITHUB_WORKSPACE}/artifacts/joininbox-amd64-debian.qcow2"
diff --git a/.github/workflows/packer-syntax-check.yml b/.github/workflows/packer-syntax-check.yml
deleted file mode 100644
index d6dbd6f..0000000
--- a/.github/workflows/packer-syntax-check.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-name: Packer Syntax Check
-
-concurrency:
- group: packer-syntax-check-${{ github.head_ref || github.ref }}
- cancel-in-progress: true
-
-on:
- push:
- branches: [ "master" ]
- paths:
- - '.github/workflows/packer-syntax-check.yml'
- - 'ci/amd64/**/*.pkr.hcl'
- - 'ci/amd64/**/*.pkrvars.hcl'
- - 'ci/amd64/packer.build.amd64-debian.sh'
- - 'ci/arm64-rpi/**/*.pkr.hcl'
- - 'ci/arm64-rpi/**/*.pkrvars.hcl'
- - 'ci/arm64-rpi/arm64-rpi.sh'
- pull_request:
- branches: [ "master" ]
- paths:
- - '.github/workflows/packer-syntax-check.yml'
- - 'ci/amd64/**/*.pkr.hcl'
- - 'ci/amd64/**/*.pkrvars.hcl'
- - 'ci/amd64/packer.build.amd64-debian.sh'
- - 'ci/arm64-rpi/**/*.pkr.hcl'
- - 'ci/arm64-rpi/**/*.pkrvars.hcl'
- - 'ci/arm64-rpi/arm64-rpi.sh'
- workflow_dispatch:
-
-jobs:
- validate-packer-syntax:
- name: Validate Packer Syntax
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Setup Packer
- uses: hashicorp/setup-packer@v3
-
- - name: Show Packer version
- run: packer version
-
- - name: Validate amd64 templates (syntax only)
- shell: bash
- run: |
- set -euo pipefail
-
- mapfile -t templates < <(find ci/amd64 ci/arm64-rpi -type f \( -name '*.pkr.hcl' -o -name '*.pkrvars.hcl' \) | sort)
-
- if [ ${#templates[@]} -eq 0 ]; then
- echo "No Packer templates found under ci/amd64 or ci/arm64-rpi"
- exit 1
- fi
-
- for template in "${templates[@]}"; do
- echo "Validating $template"
- packer validate -syntax-only "$template"
- done
diff --git a/FAQ.md b/FAQ.md
index db608dd..ae14865 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -30,7 +30,6 @@
- [Wallet recovery](#wallet-recovery)
- [on JoininBox](#on-joininbox)
- [on the remote node](#on-the-remote-node)
-- [Migrating from legacy wallet.dat to descriptor wallet](#migrating-from-legacy-walletdat-to-descriptor-wallet)
- [USB SSD recommendation](#usb-ssd-recommendation)
- [Pruned node notes](#pruned-node-notes)
- [External drive](#external-drive)
@@ -196,7 +195,7 @@ Use `ssh` with `torsocks` on the desktop (needs Tor installed):
server=1
daemon=1
disablewallet=0
-main.wallet=watch-only-descriptor-wallet
+main.wallet=wallet.dat
# Connection settings
rpcuser=REDACTED
@@ -429,7 +428,7 @@ JoinMarket docs:
* https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/USAGE.md#recover
### on JoininBox
-* Connect the remote bitcoind with `CONFIG` -> `CONNECT` menu so it checks if the connection is successful. It will also set the remote watch-only-descriptor-wallet in bitcoind to "joininbox" so will need to rescan that after recovering an old wallet with previously used addresses.
+* Connect the remote bitcoind with `CONFIG` -> `CONNECT` menu so it checks if the connection is successful. It will also set the remote watch-only wallet in bitcoind to "joininbox" so will need to rescan that after recovering an old wallet with previously used addresses.
* When using the CLI and connecting to the remote node over Tor, you will need to use the script with the torsocks prefix like:
`torsocks python3 wallet-tool.py --recoversync -g 20 ~/.joinmarket/wallets/wallet.jmdat`
@@ -438,7 +437,7 @@ JoinMarket docs:
* Use the menu option `WALLET` -> `RESCAN` or follow manually
* the wallet defined as
`rpc_wallet =`
-in the joinmarket.cfg is the wallet which is used as a watch-only-descriptor-wallet in the remote bitcoind.
+in the joinmarket.cfg is the wallet which is used as watch only in the remote bitcoind.
You need to run rescanblockchain on that wallet in bitcoind after importing the joinmarket wallet.
* The wallet is set in the joinmarket.cfg (by default called `joininbox` should show up when you run:
`bitcoin-cli listwallets`
@@ -450,65 +449,6 @@ Rescanning from the first SegWit block is sufficient for the default SegWit wall
* Monitor progress (on a RaspiBlitz):
`sudo tail -fn 100 /mnt/hdd/app-storage/bitcoin/debug.log`
Once the rescan is finished you balances should appear in the `INFO` menu (`wallet-tool.py`)
-
-## Migrating from legacy wallet.dat to descriptor wallet
-
-Starting with the 0.9.0 version, JoininBox uses Bitcoin Core's descriptor wallets (`watch-only-descriptor-wallet`) instead of the legacy `wallet.dat`. This change provides better compatibility with modern Bitcoin Core versions (v26+) and aligns with Bitcoin Core's default wallet format.
-
-### Why this change?
-
-Bitcoin Core has deprecated BDB (Berkeley DB) wallets in favor of descriptor wallets. The new descriptor wallets:
-- Are the default in Bitcoin Core v26+
-- Don't require the `deprecatedrpc=create_bdb` configuration
-- Have better performance and features
-- Are actively maintained and improved
-
-### How automatic migration works
-
-When `rpc_wallet_file` is still set to `wallet.dat`, JoininBox queries the connected Bitcoin Core node using RPC before changing the configuration:
-
-- Bitcoin Core v30.0 and newer: JoininBox atomically changes `rpc_wallet_file` to `watch-only-descriptor-wallet`, creates or loads that descriptor wallet, and displays the migration notice when the old `wallet.dat` is present.
-- Bitcoin Core v29.x and earlier: JoininBox keeps using `wallet.dat` and does not start automatic migration.
-- Version unavailable: JoininBox leaves `wallet.dat` configured rather than migrating without confirming compatibility.
-
-The migration does not rename, modify, or delete the old `wallet.dat`. It changes which Bitcoin Core wallet JoinMarket uses for watch-only address imports and transaction history.
-
-### Migration steps for existing users
-
-If you're upgrading from a previous version of JoininBox that used `wallet.dat`, follow these steps:
-
-1. **The migration notice will appear automatically on Bitcoin Core v30.0 and newer**
- When you first use any wallet-related function after updating, JoininBox checks the connected Bitcoin Core version. On v30.0 and newer it switches the configured RPC wallet to `watch-only-descriptor-wallet`, detects the old `wallet.dat`, and displays a migration notice. Bitcoin Core v29.x and earlier continue using `wallet.dat` without starting the automatic migration.
-
-2. **Open each JoinMarket wallet**
- Go to `WALLET` -> `DISPLAY` and open each of your JoinMarket wallets (`.jmdat` files) at least once. This imports the addresses into the new `watch-only-descriptor-wallet` in Bitcoin Core.
-
-3. **Run a blockchain rescan**
- After opening all your wallets, go to `WALLET` -> `RESCAN` and enter a blockheight:
- - Use `481824` (first SegWit block) for wallets created after August 2017
- - Can use a later blockheight if you know when your wallet had its first deposit
-
-4. **Wait for the rescan to complete**
- The rescan can take several hours depending on the blockheight and your hardware. Monitor progress with:
- ```bash
- # On standalone JoininBox:
- sudo tail -f /home/bitcoin/.bitcoin/debug.log
-
- # On RaspiBlitz:
- sudo tail -f /mnt/hdd/bitcoin/debug.log
- ```
-
-5. **Verify your balances**
- Once the rescan completes, check your wallet balances with `WALLET` -> `DISPLAY`.
-
-### Notes
-
-- The old `wallet.dat` is not deleted and remains in Bitcoin Core
-- Automatic migration only runs when the connected Bitcoin Core version is v30.0 or newer
-- You only need to perform this migration once
-- The migration notice will not appear again after you acknowledge it
-- If you have issues, you can reset the migration flag by removing `walletMigrationDone=true` from `/home/joinmarket/joinin.conf`
-
## USB SSD recommendation
**JoininBox operates on the minimum viable hardware under the assumption that the seed (and passphrase) of the wallets used is safely backed up and can be recovered fully**
* The above warning is especially true for SDcard as they fail often, use a good quality one.
@@ -579,7 +519,7 @@ Alternatively to a pruned node there could be a larger >400 GB storage connected
# -rw------- 1 bitcoin bitcoin 1521305 Mar 21 10:38 peers.dat
# -rw-r--r-- 1 bitcoin bitcoin 7 Mar 21 10:08 settings.json
# drwx------ 34 bitcoin bitcoin 4096 Dec 7 23:39 specter
- # drwx------ 2 bitcoin bitcoin 4096 Mar 21 10:38 watch-only-descriptor-wallet
+ # drwx------ 2 bitcoin bitcoin 4096 Mar 21 10:38 wallet.dat
installMainnet
...
# # OK - the bitcoind.service is now enabled
@@ -588,7 +528,7 @@ Alternatively to a pruned node there could be a larger >400 GB storage connected
#
# # Monitor the bitcoind with: sudo tail -f /home/bitcoin/.bitcoin/mainnet/debug.log
#
- # # Create watch-only-descriptor-wallet ...
+ # # Create wallet.dat ...
# error code: -28
# error message:
# Loading block index...
diff --git a/README.md b/README.md
index f9e7ef4..3aa7a3b 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ A minimalistic, security focused linux environment for JoinMarket with a termina
- [Features](#features)
- [Required Hardware](#required-hardware)
- [A computer running a Debian / Ubuntu Linux flavour.](#a-computer-running-a-debian--ubuntu-linux-flavour)
- - [RaspberryPi 5 or 4](#raspberrypi-5-or-4)
+ - [RaspberryPi 4 or 3](#raspberrypi-4-or-3)
- [VPS eg: host4coins.net](#vps-eg-host4coinsnet)
- [Set up using an SDcard image](#set-up-using-an-sdcard-image)
- [Set up JoininBox on Linux](#set-up-joininbox-on-linux)
@@ -32,6 +32,7 @@ A minimalistic, security focused linux environment for JoinMarket with a termina
- [More info](#more-info)
- [About JoinMarket](#about-joinmarket)
- [Forums](#forums)
+- [Donations](#donations)
## Features
@@ -43,19 +44,19 @@ A minimalistic, security focused linux environment for JoinMarket with a termina
* RaspiBlitz over [LAN or Tor](prepare_remote_node.md#raspiblitz)
* RoninDojo over [LAN or Tor](prepare_remote_node.md#ronindojo)
* Start a pruned node from https://pruned.host4coins.net/blocks
-* JoininBox is part of the RaspiBlitz SERVICES
+* JoininBox is part the RaspiBlitz SERVICES
-**The addresses, transactions and balances of JoinMarket can be seen in the watch-only-descriptor-wallet of the connected node.**
+**The addresses, transactions and balances of JoinMarket can be seen in the watch-only wallet of the connected node.**
* use your own or a trusted node
* to protect privacy in case of physical access use disk encryption
## Required Hardware
### A computer running a Debian / Ubuntu Linux flavour.
* See the [tested-environments](#tested-environments).
-### RaspberryPi 5 or 4
+### RaspberryPi 4 or 3
* Power supply (5V 3A and above recommended)
* Heatsink case
-* 32 GB Endurance type SDcard
+* 32 GB Endurence type SDcard
* [(USB SSD to run a pruned bitcoin node locally)](FAQ.md#usb-ssd-recommendation)
### VPS eg: [host4coins.net](https://host4coins.net/)
Recommended minimum:
@@ -161,3 +162,8 @@ the default password is: `joininbox` - will be prompted to change it on the firs
* IRC: #joinmarket on [libera.chat](https://libera.chat/) or [hackint.org](https://hackint.org/)
* Reddit:
* Keybase:
+
+## Donations
+* For JoinMarket (general): https://bitcoinprivacy.me/joinmarket-donations
+* To waxwing for JoinMarket:
+* To openoms for JoininBox (LN + payjoin enabled - open in the [Tor Browser](https://www.torproject.org/)):
diff --git a/build_joininbox.sh b/build_joininbox.sh
index ade914a..e8074c5 100644
--- a/build_joininbox.sh
+++ b/build_joininbox.sh
@@ -276,30 +276,22 @@ echo "##########"
echo
# apt dependencies for python
apt-get install -y python3 virtualenv python3-venv python3-dev python3-wheel python3-jinja2 python3-pip
-if [ -f "/usr/bin/python3.13" ]; then
- # use python 3.13 if available
- update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1
- echo "# python calls python3.13"
-elif [ -f "/usr/bin/python3.12" ]; then
- # use python 3.12 if available
- update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1
- echo "# python calls python3.12"
-elif [ -f "/usr/bin/python3.11" ]; then
- # use python 3.11 if available
- update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1
- echo "# python calls python3.11"
-elif [ -f "/usr/bin/python3.10" ]; then
- # use python 3.10 if available
- update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1
- echo "# python calls python3.10"
+if [ -f "/usr/bin/python3.8" ]; then
+ # use python 3.8 if available
+ update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1
+ echo "# python calls python3.8"
elif [ -f "/usr/bin/python3.9" ]; then
# use python 3.9 if available
update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1
echo "# python calls python3.9"
-elif [ -f "/usr/bin/python3.8" ]; then
- # use python 3.8 if available
- update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1
- echo "# python calls python3.8"
+elif [ -f "/usr/bin/python3.10" ]; then
+ # use python 3.10 if available
+ update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1
+ echo "# python calls python3.10"
+elif [ -f "/usr/bin/python3.11" ]; then
+ # use python 3.11 if available
+ update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1
+ echo "# python calls python3.11"
else
echo "# FAIL- there is no tested version of python present"
exit 1
@@ -399,11 +391,11 @@ else
exit 1
fi
-command="bash /home/joinmarket/joininbox/scripts/verify.git.sh \
+command="sudo -u joinmarket bash /home/joinmarket/joininbox/scripts/verify.git.sh \
${PGPsigner} ${PGPpubkeyLink} ${PGPpubkeyFingerprint}"
echo "running: ${command}"
chmod 777 /dev/shm
-sudo -u joinmarket ${command} || exit 1
+${command} || exit 1
runuser joinmarket -c "cp /home/joinmarket/joininbox/scripts/* /home/joinmarket/"
runuser joinmarket -c "cp /home/joinmarket/joininbox/scripts/.* /home/joinmarket/ 2>/dev/null"
diff --git a/ci/amd64/debian/build.amd64-debian.pkr.hcl b/ci/amd64/debian/build.amd64-debian.pkr.hcl
deleted file mode 100644
index f5a34d9..0000000
--- a/ci/amd64/debian/build.amd64-debian.pkr.hcl
+++ /dev/null
@@ -1,120 +0,0 @@
-# images, checksums and signatures are at:
-# https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/
-# NOTE: This template is intended to be invoked via the wrapper script:
-# ci/amd64/packer.build.amd64-debian.sh
-# The wrapper resolves and injects the latest point-release ISO name and matching checksum
-# at runtime. Defaults below are placeholders and are not guaranteed to work if you run
-# `packer build` directly.
-variable "iso_name" { default = "debian-13-amd64-netinst.iso" }
-variable "iso_checksum" { default = "file:https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS" }
-
-variable "github_user" { default = "openoms" }
-variable "branch" { default = "master" }
-
-variable "boot" { default = "uefi" }
-variable "preseed_file" { default = "preseed.cfg" }
-variable "hostname" { default = "joininbox-amd64" }
-
-variable "image_size" { default = "30000" }
-variable "image_type" { default = "qcow2" }
-
-variable "memory" { default = "2048" }
-variable "cpus" { default = "2" }
-
-locals {
- name_template = "joininbox-amd64-debian"
- image_extension = var.image_type == "raw" ? "img" : var.image_type
- bios_file = var.boot == "uefi" ? "OVMF.fd" : "bios-256k.bin"
- boot_command = var.boot == "uefi" ? [
- "c",
- "linux /install.amd/vmlinuz ",
- "auto=true ",
- "url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/${var.preseed_file} ",
- "hostname=${var.hostname} ",
- "domain=${var.hostname}.local ",
- "interface=auto ",
- "vga=788 noprompt quiet --",
- "initrd /install.amd/initrd.gz",
- "boot"
- ] : [
- "install ",
- " preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/${var.preseed_file} ",
- "debian-installer=en_US.UTF-8 ",
- "auto ",
- "locale=en_US.UTF-8 ",
- "kbd-chooser/method=us ",
- "keyboard-configuration/xkb-keymap=us ",
- "netcfg/get_hostname=${var.hostname} ",
- "netcfg/get_domain=${var.hostname}.local ",
- "fb=false ",
- "debconf/frontend=noninteractive ",
- "console-setup/ask_detect=false ",
- "console-keymaps-at/keymap=us ",
- "grub-installer/bootdev=default ",
- ""
- ]
-}
-
-source "qemu" "debian" {
- boot_command = local.boot_command
- boot_wait = "5s"
- cpus = var.cpus
- disk_size = var.image_size
- http_directory = "./http"
- iso_checksum = var.iso_checksum
- iso_url = "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/${var.iso_name}"
- memory = var.memory
- output_directory = "../builds/${local.name_template}-qemu"
- shutdown_command = "echo 'joininbox' | sudo /sbin/shutdown -hP now"
- ssh_password = "joininbox"
- ssh_port = 22
- ssh_timeout = "10000s"
- ssh_username = "joinmarket"
- format = var.image_type
- vm_name = "${local.name_template}.${local.image_extension}"
- headless = false
- vnc_bind_address = "127.0.0.1"
- vnc_port_max = 5900
- vnc_port_min = 5900
- qemuargs = [
- ["-m", var.memory],
- ["-bios", local.bios_file],
- ["-display", "none"]
- ]
-}
-
-build {
- description = "JoininBox amd64 Debian image build"
- sources = ["source.qemu.debian"]
-
- provisioner "shell" {
- environment_vars = [
- "HOME_DIR=/home/joinmarket",
- "github_user=${var.github_user}",
- "branch=${var.branch}"
- ]
-
- execute_command = "echo 'joininbox' | {{.Vars}} sudo -S -E sh -eux '{{.Path}}'"
- expect_disconnect = true
- scripts = [
- "./scripts/update.sh",
- "./../_common/sshd.sh",
- "./scripts/networking.sh",
- "./scripts/sudoers.sh",
- "./scripts/systemd.sh",
- "./scripts/joininbox.sh",
- "./scripts/cleanup.sh"
- ]
- }
-}
-
-packer {
- required_version = ">= 1.7.0, < 2.0.0"
-
- required_plugins {
- qemu = {
- source = "github.com/hashicorp/qemu"
- version = ">= 1.0.0, < 2.0.0"
- }
- }
-}
diff --git a/ci/amd64/debian/http/debian-9/preseed.cfg b/ci/amd64/debian/http/debian-9/preseed.cfg
new file mode 100644
index 0000000..4bc9d0d
--- /dev/null
+++ b/ci/amd64/debian/http/debian-9/preseed.cfg
@@ -0,0 +1,47 @@
+choose-mirror-bin mirror/http/proxy string
+d-i apt-setup/use_mirror boolean true
+d-i base-installer/kernel/override-image string linux-server
+d-i clock-setup/utc boolean true
+d-i clock-setup/utc-auto boolean true
+d-i finish-install/reboot_in_progress note
+d-i grub-installer/only_debian boolean true
+d-i grub-installer/with_other_os boolean true
+d-i keymap select us
+d-i mirror/country string manual
+d-i mirror/http/directory string /debian
+d-i mirror/http/hostname string ftp.de.debian.org
+d-i mirror/http/proxy string
+d-i partman-auto-lvm/guided_size string max
+d-i partman-auto/choose_recipe select atomic
+d-i partman-auto/method string lvm
+d-i partman-lvm/confirm boolean true
+d-i partman-lvm/confirm_nooverwrite boolean true
+d-i partman-lvm/device_remove_lvm boolean true
+d-i partman/choose_partition select finish
+d-i partman/confirm boolean true
+d-i partman/confirm_nooverwrite boolean true
+d-i partman/confirm_write_new_label boolean true
+d-i passwd/root-login boolean false
+d-i passwd/root-password-again password joininbox
+d-i passwd/root-password password joininbox
+d-i passwd/user-fullname string joinmarket
+d-i passwd/user-uid string 1000
+d-i passwd/user-password password joininbox
+d-i passwd/user-password-again password joininbox
+d-i passwd/username string joinmarket
+d-i pkgsel/include string sudo bzip2 acpid cryptsetup zlib1g-dev wget curl dkms fuse make nfs-common net-tools cifs-utils rsync
+d-i pkgsel/install-language-support boolean false
+d-i pkgsel/update-policy select none
+d-i pkgsel/upgrade select full-upgrade
+# Prevent packaged version of VirtualBox Guest Additions being installed:
+d-i preseed/early_command string sed -i \
+ '/in-target/idiscover(){/sbin/discover|grep -v VirtualBox;}' \
+ /usr/lib/pre-pkgsel.d/20install-hwpackages
+d-i time/zone string UTC
+d-i user-setup/allow-password-weak boolean true
+d-i user-setup/encrypt-home boolean false
+d-i preseed/late_command string sed -i '/^deb cdrom:/s/^/#/' /target/etc/apt/sources.list
+apt-cdrom-setup apt-setup/cdrom/set-first boolean false
+apt-mirror-setup apt-setup/use_mirror boolean true
+popularity-contest popularity-contest/participate boolean false
+tasksel tasksel/first multiselect standard, ssh-server
diff --git a/ci/amd64/debian/http/preseed.cfg b/ci/amd64/debian/http/preseed.cfg
deleted file mode 100644
index 244ea2b..0000000
--- a/ci/amd64/debian/http/preseed.cfg
+++ /dev/null
@@ -1,72 +0,0 @@
-# https://github.com/chef/bento/blob/main/packer_templates/http/debian/preseed.cfg
-# https://www.debian.org/releases/stable/example-preseed.txt
-# https://github.com/tylert/packer-build/blob/master/source/debian/12_bookworm/base-uefi.preseed
-# variables: https://github.com/tylert/packer-build/blob/master/source/debian/12_bookworm/base-uefi.pkr.hcl
-
-# Locale Setup
-d-i debian-installer/language string en
-d-i debian-installer/country string US
-d-i debian-installer/locale string en_US.UTF-8
-# d-i localechooser/supported-locales multiselect en_CA.UTF-8 fr_CA.UTF-8 zh_CN.UTF-8
-# d-i pkgsel/install-language-support boolean true
-
-# Keyboard Setup
-d-i keyboard-configuration/xkb-keymap select us
-
-# Clock Setup
-# d-i time/zone string Canada/Eastern
-d-i time/zone string UTC
-d-i clock-setup/utc boolean true
-# set above to false if making a bootable USB to run on same system as Windows
-
-# Network Setup
-d-i netcfg/get_hostname string joininbox-amd64
-d-i netcfg/get_domain string
-# https://bugs.launchpad.net/ubuntu/+source/netcfg/+bug/713385
-d-i netcfg/choose_interface select auto
-# make sure you also add "interface=auto" to your boot command too
-# https://bugs.launchpad.net/ubuntu/+source/netcfg/+bug/713385
-
-# User Setup
-d-i passwd/root-login boolean false
-d-i passwd/root-password-again password joininbox
-d-i passwd/root-password password joininbox
-d-i passwd/user-fullname string joinmarket
-d-i passwd/user-uid string 1000
-d-i passwd/user-password password joininbox
-d-i passwd/user-password-again password joininbox
-d-i passwd/username string joinmarket
-
-# Package Setup
-d-i hw-detect/load_firmware boolean false
-d-i hw-detect/load_media boolean false
-apt-cdrom-setup apt-setup/cdrom/set-first boolean false
-d-i mirror/country string manual
-d-i mirror/http/hostname string httpredir.debian.org
-d-i mirror/http/directory string /debian
-d-i mirror/http/proxy string
-d-i apt-setup/contrib boolean true
-d-i apt-setup/non-free boolean true
-
-tasksel tasksel/first multiselect ssh-server, standard
-d-i pkgsel/include string sudo bzip2 acpid cryptsetup zlib1g-dev wget curl dkms fuse make nfs-common net-tools cifs-utils rsync
-d-i pkgsel/install-language-support boolean false
-d-i pkgsel/update-policy select none
-d-i pkgsel/upgrade select full-upgrade
-
-popularity-contest popularity-contest/participate boolean false
-
-# Drive setup
-d-i partman-auto-lvm/guided_size string max
-d-i partman-auto/choose_recipe select atomic
-d-i partman-auto/method string lvm
-d-i partman-lvm/confirm boolean true
-d-i partman-lvm/confirm_nooverwrite boolean true
-d-i partman-lvm/device_remove_lvm boolean true
-d-i partman/choose_partition select finish
-d-i partman/confirm boolean true
-d-i partman/confirm_nooverwrite boolean true
-d-i partman/confirm_write_new_label boolean true
-
-# Final Setup
-d-i finish-install/reboot_in_progress note
diff --git a/ci/amd64/debian/joininbox-amd64-debian.json b/ci/amd64/debian/joininbox-amd64-debian.json
new file mode 100644
index 0000000..7e1bef0
--- /dev/null
+++ b/ci/amd64/debian/joininbox-amd64-debian.json
@@ -0,0 +1,70 @@
+{
+ "variables": {
+ "iso_name": "debian-12.11.0-amd64-netinst.iso",
+ "iso_checksum": "30ca12a15cae6a1033e03ad59eb7f66a6d5a258dcf27acd115c2bd42d22640e8",
+ "box_basename": "debian",
+ "build_directory": "../builds",
+ "headless": "false",
+ "http_directory": "{{template_dir}}/http",
+ "name": "debian",
+ "preseed_path": "debian-9/preseed.cfg",
+ "qemu_bios": "bios-256k.bin",
+ "template": "joininbox-amd64-debian",
+ "boot_command": "install preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/{{user `preseed_path`}} debian-installer=en_US.UTF-8 auto locale=en_US.UTF-8 kbd-chooser/method=us keyboard-configuration/xkb-keymap=us netcfg/get_hostname={{ .Name }} netcfg/get_domain=vagrantup.com fb=false debconf/frontend=noninteractive console-setup/ask_detect=false console-keymaps-at/keymap=us grub-installer/bootdev=default ",
+ "memory": "2048"
+ },
+ "builders": [
+ {
+ "boot_command": "{{user `boot_command`}}",
+ "boot_wait": "5s",
+ "cpus": "2",
+ "disk_size": "30000",
+ "headless": "{{ user `headless` }}",
+ "http_directory": "{{user `http_directory`}}",
+ "iso_checksum": "{{user `iso_checksum`}}",
+ "iso_url": "http://cdimage.debian.org/cdimage/release/current/amd64/iso-cd/{{user `iso_name`}}",
+ "memory": "{{ user `memory` }}",
+ "output_directory": "{{ user `build_directory` }}/{{user `template`}}-qemu",
+ "shutdown_command": "echo 'joininbox' | sudo /sbin/shutdown -hP now",
+ "ssh_password": "joininbox",
+ "ssh_port": "22",
+ "ssh_timeout": "10000s",
+ "ssh_username": "joinmarket",
+ "type": "qemu",
+ "format": "qcow2",
+ "vm_name": "{{ user `template` }}.qcow2",
+ "vnc_bind_address": "127.0.0.1",
+ "vnc_port_max": "5900",
+ "vnc_port_min": "5900",
+ "qemuargs": [
+ [ "-m", "{{ user `memory` }}" ],
+ [ "-bios", "{{ user `qemu_bios` }}" ],
+ [ "-display", "none" ]
+ ]
+ }
+ ],
+ "provisioners": [
+ {
+ "type": "shell",
+ "environment_vars": [
+ "HOME_DIR=/home/joinmarket",
+ "http_proxy={{user `http_proxy`}}",
+ "https_proxy={{user `https_proxy`}}",
+ "no_proxy={{user `no_proxy`}}",
+ "github_user={{user `github_user`}}",
+ "branch={{user `branch`}}"
+ ],
+ "execute_command": "echo 'joininbox' | {{.Vars}} sudo -S -E sh -eux '{{.Path}}'",
+ "expect_disconnect": true,
+ "scripts": [
+ "{{template_dir}}/scripts/update.sh",
+ "{{template_dir}}/../_common/sshd.sh",
+ "{{template_dir}}/scripts/networking.sh",
+ "{{template_dir}}/scripts/sudoers.sh",
+ "{{template_dir}}/scripts/systemd.sh",
+ "{{template_dir}}/scripts/joininbox.sh",
+ "{{template_dir}}/scripts/cleanup.sh"
+ ]
+ }
+ ]
+}
diff --git a/ci/amd64/packer.build.amd64-debian.sh b/ci/amd64/packer.build.amd64-debian.sh
index 776410d..1970b41 100644
--- a/ci/amd64/packer.build.amd64-debian.sh
+++ b/ci/amd64/packer.build.amd64-debian.sh
@@ -1,135 +1,39 @@
#!/bin/bash -e
-sudo apt-get update
-
# install packer
if ! packer version 2>/dev/null; then
- curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
- sudo apt-add-repository -y "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
- sudo apt-get update
- echo -e "\nInstalling packer..."
- sudo apt-get install -y packer
+ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
+ sudo apt-add-repository -y "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
+ sudo apt-get update
+ echo -e "\nInstalling packer..."
+ sudo apt-get install -y packer
else
- echo "# Packer is installed"
+ echo "# Packer is installed"
fi
-# install qemu and UEFI firmware
+# install qemu
echo "# Install qemu ..."
sudo apt-get update
-sudo apt-get install -y qemu-system ovmf
+sudo apt-get install -y qemu-system
+
+# install qemu plugin
+packer plugins install github.com/hashicorp/qemu
-# set vars from positional arguments (for backward compatibility with CI)
if [ $# -gt 0 ]; then
- github_user=$1
+ github_user=$1
else
- github_user=openoms
+ github_user=openoms
fi
if [ $# -gt 1 ]; then
- branch=$2
+ branch=$2
else
- branch=master
+ branch=master
fi
-# Resolve latest Debian 13 amd64 netinst ISO from SHA256SUMS.
-# This avoids 404s and checksum mismatches when Debian point releases rotate.
-debian_major=${DEBIAN_MAJOR:-13}
-debian_iso_dir="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd"
-debian_sums_url="${debian_iso_dir}/SHA256SUMS"
-debian_sums_sig_url="${debian_iso_dir}/SHA256SUMS.sign"
-debian_cd_key_urls=(
- "https://www.debian.org/CD/key-DA87E80D6294BE9B.txt"
- "https://www.debian.org/CD/key-988021A964E6EA7D.txt"
-)
-debian_cd_expected_fprs=(
- "DF9B9C49EAA9298432589D76DA87E80D6294BE9B"
- "10460DAD76165AD81FBC0CE9988021A964E6EA7D"
-)
-
-if ! command -v gpgv >/dev/null 2>&1; then
- echo "# Installing gpgv"
- sudo apt-get install -y gpgv
-fi
-
-if ! command -v gpgv >/dev/null 2>&1; then
- echo "ERROR: gpgv is required for signature verification"
- exit 1
-fi
-
-tmp_checksums_dir=$(mktemp -d)
-trap 'rm -rf "${tmp_checksums_dir}"' EXIT
-
-echo "# Downloading checksum files"
-curl -fsSL "${debian_sums_url}" -o "${tmp_checksums_dir}/SHA256SUMS"
-curl -fsSL "${debian_sums_sig_url}" -o "${tmp_checksums_dir}/SHA256SUMS.sign"
-
-echo "# Verifying SHA256SUMS signature (PGP)"
-cd_keyring="${tmp_checksums_dir}/debian-cd-signing-keys.gpg"
-tmp_gnupg_home="${tmp_checksums_dir}/gnupg-home"
-mkdir -p "${tmp_gnupg_home}"
-chmod 700 "${tmp_gnupg_home}"
-
-for i in "${!debian_cd_key_urls[@]}"; do
- key_url="${debian_cd_key_urls[$i]}"
- expected_fpr="${debian_cd_expected_fprs[$i]}"
- key_file="${tmp_checksums_dir}/cd-key-${i}.asc"
- curl -fsSL "${key_url}" -o "${key_file}"
- actual_fpr=$(gpg --homedir "${tmp_gnupg_home}" --show-keys --with-colons "${key_file}" 2>/dev/null | awk -F: '/^fpr:/ {print $10; exit}')
- if [ -z "${actual_fpr}" ] || [ "${actual_fpr}" != "${expected_fpr}" ]; then
- echo "# SHA256SUMS signature: FAIL"
- echo "ERROR: Unexpected fingerprint for ${key_url}"
- exit 1
- fi
- gpg --homedir "${tmp_gnupg_home}" --no-default-keyring --keyring "${cd_keyring}" --import "${key_file}" >/dev/null 2>&1
-done
-
-if gpgv --keyring "${cd_keyring}" "${tmp_checksums_dir}/SHA256SUMS.sign" "${tmp_checksums_dir}/SHA256SUMS" >/dev/null 2>&1; then
- echo "# SHA256SUMS signature: PASS"
-else
- echo "# SHA256SUMS signature: FAIL"
- echo "ERROR: PGP signature verification failed for ${debian_sums_url}"
- exit 1
-fi
-
-echo "# Resolving latest Debian ${debian_major} amd64 netinst ISO from ${debian_sums_url}"
-latest_iso_line=$(awk -v major="${debian_major}" '$2 ~ ("^\\*?\\.?/?debian-" major "\\.[0-9]+\\.[0-9]+-amd64-netinst\\.iso$") {print $1 " " $2}' "${tmp_checksums_dir}/SHA256SUMS" | \
- sort -k2 -V | tail -1)
-
-if [ -z "${latest_iso_line}" ]; then
- echo "ERROR: Could not resolve latest Debian ${debian_major} amd64 netinst ISO from ${debian_sums_url}"
- exit 1
-fi
-
-latest_iso_checksum=$(echo "${latest_iso_line}" | awk '{print $1}')
-latest_iso_name=$(echo "${latest_iso_line}" | awk '{print $2}' | sed 's#^\*##; s#^\./##; s#^/##')
-
-if [ -z "${latest_iso_name}" ] || [ -z "${latest_iso_checksum}" ]; then
- echo "ERROR: Failed parsing ISO name/checksum from: ${latest_iso_line}"
- exit 1
-fi
-
-resolved_checksum=$(awk -v iso="${latest_iso_name}" '($2 == iso || $2 == "*" iso || $2 == "./" iso || $2 == "/" iso) {print $1; exit}' "${tmp_checksums_dir}/SHA256SUMS")
-if [ -z "${resolved_checksum}" ]; then
- echo "ERROR: Could not find checksum entry for ${latest_iso_name} in ${debian_sums_url}"
- exit 1
-fi
-
-echo "# Debian ISO selection"
-echo "# ISO filename : ${latest_iso_name}"
-echo "# SHA256 (selected) : ${latest_iso_checksum}"
-echo "# SHA256 (resolved) : ${resolved_checksum}"
-if [ "${latest_iso_checksum}" = "${resolved_checksum}" ]; then
- echo "# Checksum verify : PASS"
-else
- echo "# Checksum verify : FAIL"
- echo "ERROR: Checksum mismatch for ${latest_iso_name}"
- exit 1
-fi
-
-vars="-var github_user=${github_user} -var branch=${branch} -var iso_name=${latest_iso_name} -var iso_checksum=${latest_iso_checksum}"
-
# Build the image
-echo "# Build the image with: github_user=${github_user} branch=${branch}"
+echo "# Building image ..."
cd debian
-packer init -upgrade .
-PACKER_LOG=1 packer build ${vars} -only=qemu.debian build.amd64-debian.pkr.hcl || exit 1
+PACKER_LOG=1 packer build \
+ -var github_user=${github_user} -var branch=${branch} \
+ -only=qemu joininbox-amd64-debian.json
diff --git a/ci/amd64/test.amd64-image-bats.sh b/ci/amd64/test.amd64-image-bats.sh
deleted file mode 100755
index 5313656..0000000
--- a/ci/amd64/test.amd64-image-bats.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-image="${1:-${GITHUB_WORKSPACE:-$(pwd)}/ci/amd64/builds/joininbox-amd64-debian-qemu/joininbox-amd64-debian.qcow2}"
-ssh_port="${SSH_PORT:-2222}"
-ssh_password="${SSH_PASSWORD:-joininbox}"
-qemu_pid_file="${RUNNER_TEMP:-/tmp}/joininbox-qemu.pid"
-bats_core_dir="${BATS_CORE_DIR:-${GITHUB_WORKSPACE:-$(pwd)}/.bats-core}"
-
-if [ ! -f "${image}" ]; then
- echo "Missing image: ${image}" >&2
- exit 1
-fi
-
-if [ ! -x "${bats_core_dir}/bin/bats" ]; then
- echo "Missing bats-core checkout: ${bats_core_dir}" >&2
- exit 1
-fi
-
-sudo apt-get update
-sudo apt-get install -y ovmf qemu-system-x86 sshpass
-
-ssh_opts=(
- -o StrictHostKeyChecking=no
- -o UserKnownHostsFile=/dev/null
- -o ConnectTimeout=5
- -p "${ssh_port}"
-)
-
-ovmf_code="${OVMF_CODE:-${OVMF_BIOS:-}}"
-ovmf_vars_template="${OVMF_VARS:-}"
-ovmf_vars="${RUNNER_TEMP:-/tmp}/joininbox-ovmf-vars.fd"
-qemu_firmware_args=()
-
-if [ -z "${ovmf_code}" ]; then
- for candidate in \
- /usr/share/OVMF/OVMF_CODE_4M.fd \
- /usr/share/OVMF/OVMF_CODE_4M.secboot.fd \
- /usr/share/OVMF/OVMF_CODE_4M.ms.fd \
- /usr/share/OVMF/OVMF_CODE.fd \
- /usr/share/OVMF/OVMF.fd \
- /usr/share/ovmf/OVMF_CODE_4M.fd \
- /usr/share/ovmf/OVMF_CODE_4M.secboot.fd \
- /usr/share/ovmf/OVMF_CODE_4M.ms.fd \
- /usr/share/ovmf/OVMF_CODE.fd \
- /usr/share/ovmf/OVMF.fd \
- OVMF.fd; do
- if [ -f "${candidate}" ]; then
- ovmf_code="${candidate}"
- break
- fi
- done
-fi
-
-if [ -z "${ovmf_code}" ] || [ ! -f "${ovmf_code}" ]; then
- echo "No OVMF firmware found. Set OVMF_CODE or OVMF_BIOS to the firmware path." >&2
- find /usr/share/OVMF /usr/share/ovmf -maxdepth 1 -type f -name '*.fd' -print 2>/dev/null || true
- exit 1
-fi
-
-case "${ovmf_code##*/}" in
- *CODE*)
- if [ -z "${ovmf_vars_template}" ]; then
- for candidate in \
- "${ovmf_code/CODE/VARS}" \
- /usr/share/OVMF/OVMF_VARS_4M.fd \
- /usr/share/OVMF/OVMF_VARS.fd \
- /usr/share/ovmf/OVMF_VARS_4M.fd \
- /usr/share/ovmf/OVMF_VARS.fd; do
- if [ -f "${candidate}" ]; then
- ovmf_vars_template="${candidate}"
- break
- fi
- done
- fi
-
- if [ -z "${ovmf_vars_template}" ] || [ ! -f "${ovmf_vars_template}" ]; then
- echo "No OVMF VARS template found for ${ovmf_code}. Set OVMF_VARS to the template path." >&2
- find /usr/share/OVMF /usr/share/ovmf -maxdepth 1 -type f -name '*.fd' -print 2>/dev/null || true
- exit 1
- fi
-
- cp "${ovmf_vars_template}" "${ovmf_vars}"
- qemu_firmware_args=(
- -drive "if=pflash,format=raw,readonly=on,file=${ovmf_code}"
- -drive "if=pflash,format=raw,file=${ovmf_vars}"
- )
- ;;
- *)
- qemu_firmware_args=(-bios "${ovmf_code}")
- ;;
-esac
-
-cleanup() {
- if [ -f "${qemu_pid_file}" ]; then
- qemu_pid="$(cat "${qemu_pid_file}")"
- if kill -0 "${qemu_pid}" 2>/dev/null; then
- kill "${qemu_pid}" 2>/dev/null || true
- timeout 30s tail --pid="${qemu_pid}" -f /dev/null 2>/dev/null ||
- kill -9 "${qemu_pid}" 2>/dev/null ||
- true
- fi
- fi
-}
-trap cleanup EXIT
-
-rm -f "${qemu_pid_file}"
-
-qemu-system-x86_64 \
- -m 2048 \
- -smp 2 \
- "${qemu_firmware_args[@]}" \
- -drive "file=${image},format=qcow2" \
- -netdev "user,id=net0,hostfwd=tcp:127.0.0.1:${ssh_port}-:22" \
- -device e1000,netdev=net0 \
- -display none \
- -snapshot \
- -pidfile "${qemu_pid_file}" \
- -daemonize
-
-echo "Waiting for SSH in the booted image"
-for attempt in {1..120}; do
- if sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 "true" 2>/dev/null; then
- break
- fi
- if [ "${attempt}" -eq 120 ]; then
- echo "Timed out waiting for SSH" >&2
- exit 1
- fi
- sleep 5
-done
-
-tar -C "${bats_core_dir}" -cf - . |
- sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 \
- "mkdir -p /tmp/bats-core && tar -C /tmp/bats-core -xf -"
-
-sshpass -p "${ssh_password}" ssh "${ssh_opts[@]}" joinmarket@127.0.0.1 \
- "PATH=/tmp/bats-core/bin:\$PATH /home/joinmarket/joininbox/test/run-bats-local.sh"
diff --git a/prepare_remote_node.md b/prepare_remote_node.md
index f5c78bd..628bc24 100644
--- a/prepare_remote_node.md
+++ b/prepare_remote_node.md
@@ -45,7 +45,7 @@ This can be skipped if you [connect through Tor](#tor-connection)
Add the values:
* `rpcallowip=JOININBOX_IP` or `RANGE`
* either specify the LAN IP of the computer (here JoininBox)
- * or use a range like: `192.168.1.0/24` - edit to your local subnet - the first 3 numbers of the LAN IP address, the example used here is: 192.168.1.x
+ * or use a range like: `192.168.1.0/24` - edit to your local subnet - the first 3 numbes of the LAN IP address, the example used here is: 192.168.1.x
* `rpcbind=LAN_IP_OF_THE_NODE`
* use the local IP of the bitcoin node in the example: `192.168.1.4`
* can keep the other `rpcallowip` and `rpcbind` entries especially for the localhost: `127.0.0.1`
diff --git a/scripts/.dialogrc b/scripts/.dialogrc
index e60c81a..23b648f 100644
--- a/scripts/.dialogrc
+++ b/scripts/.dialogrc
@@ -42,7 +42,7 @@ dialog_color = (CYAN,BLACK,OFF)
title_color = (CYAN,BLACK,ON)
# Dialog box border color
-border_color = (CYAN,BLACK,ON)
+border_color = (BLACK,BLACK,ON)
# Active button color
button_active_color = (BLACK,CYAN,ON)
diff --git a/scripts/_functions.bitcoincore.sh b/scripts/_functions.bitcoincore.sh
index 4c1988c..ea03c49 100755
--- a/scripts/_functions.bitcoincore.sh
+++ b/scripts/_functions.bitcoincore.sh
@@ -9,7 +9,7 @@ joininConfPath="/home/joinmarket/joinin.conf"
function downloadBitcoinCore() {
# set version
# https://bitcoincore.org/en/download/
- bitcoinVersion="29.2"
+ bitcoinVersion="26.1"
if bitcoin-cli --version | grep $bitcoinVersion >/dev/null; then
echo "# Bitcoin Core $bitcoinVersion is already installed"
@@ -247,8 +247,8 @@ setJMconfigToSignet() {
sed -i "s/^rpc_password =.*/rpc_password = $RPCPWSIGNET/g" $JMcfgPath
echo "# rpc_password = $RPCPWSIGNET"
# rpc_wallet_file
- sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath
- echo "# using the bitcoind watch-only-descriptor-wallet"
+ sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/g" $JMcfgPath
+ echo "# using the bitcoind wallet: wallet.dat"
# rpc_host
sed -i "s/^rpc_host =.*/rpc_host = 127.0.0.1/g" $JMcfgPath
echo "# rpc_host = 127.0.0.1"
@@ -321,79 +321,38 @@ function getRPC {
fi
}
-# getConnectedBitcoinCoreVersion - read the numeric version over node RPC
-function getConnectedBitcoinCoreVersion {
- local tor=""
- if [ "$(echo "$rpc_host" | grep -c .onion)" -gt 0 ]; then
- tor="torsocks"
- fi
- $tor curl -sS --data-binary \
- '{"jsonrpc": "1.0", "id":"get_bitcoin_core_version", "method": "getnetworkinfo", "params": []}' \
- "http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/" 2>/dev/null |
- jq -r '.result.version // empty' 2>/dev/null
-}
-
-# migrateLegacyRPCWalletConfig - switch the persisted JoinMarket RPC wallet
-# from the legacy wallet.dat name to the descriptor wallet used by JoininBox
-# when the connected Bitcoin Core version is v30.0 or newer
-function migrateLegacyRPCWalletConfig {
- if [ "$rpc_wallet" != "wallet.dat" ]; then
- return 0
- fi
-
- local bitcoinCoreVersion
- bitcoinCoreVersion=$(getConnectedBitcoinCoreVersion)
- if ! [[ "$bitcoinCoreVersion" =~ ^[0-9]+$ ]]; then
- echo "# Could not determine the connected Bitcoin Core version; keeping wallet.dat"
- return 0
- fi
- # Bitcoin Core's numeric version is 290200 for v29.2 and 300000 for v30.0.
- if [ "$bitcoinCoreVersion" -lt 300000 ]; then
- echo "# Connected Bitcoin Core is v29.x or earlier; keeping wallet.dat"
- return 0
- fi
-
- echo "# Migrating the configured Bitcoin Core wallet from wallet.dat to watch-only-descriptor-wallet"
- local migrationConfigOutput
- if ! migrationConfigOutput=$(mktemp "${JMcfgPath}.XXXXXX"); then
- echo "# Failed to create a temporary descriptor wallet configuration" >&2
- return 1
- fi
- if ! sed \
- "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" \
- "$JMcfgPath" >"$migrationConfigOutput"; then
- rm -f "$migrationConfigOutput"
- echo "# Failed to prepare the descriptor wallet configuration" >&2
- return 1
- fi
- if ! mv "$migrationConfigOutput" "$JMcfgPath"; then
- rm -f "$migrationConfigOutput"
- echo "# Failed to update the descriptor wallet configuration" >&2
- return 1
- fi
- getRPC
- if [ "$rpc_wallet" != "watch-only-descriptor-wallet" ]; then
- echo "# Failed to select the descriptor wallet configuration" >&2
- return 1
- fi
-}
-
# checkRPCwallet
function checkRPCwallet {
getRPC
- migrateLegacyRPCWalletConfig || return 1
if [ $# -eq 0 ]; then
rpc_wallet=$rpc_wallet
else
rpc_wallet=$1
fi
+ echo "# Check 'deprecatedrpc=create_bdb' in bitcoin.conf"
+ source ${joininConfPath}
+ if [ $runningEnv = standalone ]; then
+ bitcoinConfPath="/home/bitcoin/.bitcoin/bitcoin.conf"
+ elif [ $runningEnv = raspiblitz ]; then
+ if [ -f "/mnt/hdd/raspiblitz.conf" ]; then
+ bitcoinConfPath="/mnt/hdd/bitcoin/bitcoin.conf"
+ else
+ bitcoinConfPath="/mnt/hdd/app-data/bitcoin/bitcoin.conf"
+ fi
+ fi
+ if ! sudo grep -c "deprecatedrpc=create_bdb" "$bitcoinConfPath"; then
+ echo "# Place 'deprecatedrpc=create_bdb' in bitcoin.conf"
+ echo "deprecatedrpc=create_bdb" | sudo tee -a "$bitcoinConfPath"
+ echo "# Restarting bitcoind"
+ sudo systemctl restart bitcoind
+ fi
echo "# Making sure the set $rpc_wallet wallet is present in bitcoind"
trap 'rm -f "$connectionOutput"' EXIT
connectionOutput=$(mktemp -p /dev/shm/)
walletFound=$(customRPC "# Check wallet" "listwallets" 2>$connectionOutput | grep -c "$rpc_wallet")
if [ $walletFound -eq 0 ]; then
- echo "# Setting a watch-only-descriptor-wallet in Bitcoin Core named $rpc_wallet"
+ echo "# Setting a watch only wallet in Bitcoin Core named $rpc_wallet"
tor=""
if [ $(echo $rpc_host | grep -c .onion) -gt 0 ]; then
tor="torsocks"
@@ -402,8 +361,8 @@ function checkRPCwallet {
fi
#TODO rewrite customRPC to support multiple params
$tor curl -sS --data-binary \
- '{"jsonrpc": "1.0", "id":"# Create the bitcoind wallet", "method": "createwallet", "params": {"wallet_name":"'"$rpc_wallet"'","descriptors":true,"disable_private_keys":true}}' \
- http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/ | jq .
+ '{"jsonrpc": "1.0", "id":"# Create the bitcoind wallet", "method": "createwallet", "params": {"wallet_name":"'"$rpc_wallet"'","descriptors":false}}' \
+ http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/wallet/$rpc_wallet | jq .
echo
walletFound=$(customRPC "# Check wallet" "listwallets" 2>$connectionOutput | grep -c "$rpc_wallet")
if [ $walletFound -eq 0 ]; then
@@ -415,75 +374,6 @@ function checkRPCwallet {
echo
fi
echo "# The wallet: $rpc_wallet is present and loaded in the connected bitcoind"
-
- # Check for wallet migration from legacy wallet.dat
- checkWalletMigration
-}
-
-# checkWalletMigration - detects legacy wallet.dat and guides user through migration
-# This function checks if:
-# 1. The old wallet.dat exists in Bitcoin Core
-# 2. The new watch-only-descriptor-wallet is being used
-# 3. Migration has not been completed yet
-# If migration is needed, it prompts the user to rescan after opening their JM wallets
-function checkWalletMigration {
- # Skip if migration was already completed
- if grep -q "walletMigrationDone=true" "${joininConfPath}" 2>/dev/null; then
- return 0
- fi
-
- # Skip if we're not using the new descriptor wallet
- if [ "$rpc_wallet" != "watch-only-descriptor-wallet" ]; then
- return 0
- fi
-
- # RPC settings are already available from parent checkRPCwallet function
- tor=""
- if [ "$(echo "$rpc_host" | grep -c .onion)" -gt 0 ]; then
- tor="torsocks"
- fi
-
- # Check if old wallet.dat exists in bitcoind (try to load it to see if it exists)
- # First check listwalletdir for wallet.dat
- oldWalletExists=$($tor curl -sS --data-binary \
- '{"jsonrpc": "1.0", "id":"check_old_wallet", "method": "listwalletdir", "params": []}' \
- "http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/" 2>/dev/null | jq -r '.result.wallets[].name' 2>/dev/null | grep -c "^wallet.dat$")
-
- if [ "$oldWalletExists" -gt 0 ]; then
- echo
- echo "########################################################################"
- echo "# WALLET MIGRATION NOTICE"
- echo "########################################################################"
- echo
- echo "# A legacy wallet.dat was detected in Bitcoin Core."
- echo "# JoininBox now uses descriptor wallets (watch-only-descriptor-wallet)"
- echo "# for better compatibility with modern Bitcoin Core versions."
- echo
- echo "# To complete the migration and see your transaction history:"
- echo
- echo "# 1. Open each of your JoinMarket wallets once using:"
- echo "# WALLET -> DISPLAY"
- echo "# This imports the addresses into the new descriptor wallet."
- echo
- echo "# 2. After opening all wallets, run a blockchain rescan:"
- echo "# WALLET -> RESCAN"
- echo "# Use blockheight 481824 (first SegWit block) or later if you know when your wallet had its first deposit."
- echo
- echo "# The rescan may take several hours depending on wallet age."
- echo "# You can monitor progress in the Bitcoin Core debug.log"
- echo
- echo "########################################################################"
- echo
- echo "# Press ENTER to continue..."
- read -r
-
- # Mark migration notice as shown (user can still run rescan manually)
- if ! grep -q "walletMigrationDone=" "${joininConfPath}" 2>/dev/null; then
- echo "walletMigrationDone=true" >>"${joininConfPath}"
- else
- sed -i "s/^walletMigrationDone=.*/walletMigrationDone=true/g" "${joininConfPath}"
- fi
- fi
}
# customRPC - sends a custom RPC command
@@ -545,7 +435,7 @@ function connectLocalNode() {
elif [ "${network}" = testnet ]; then
rpc_port="18332"
fi
- rpc_wallet="watch-only-descriptor-wallet"
+ rpc_wallet="wallet.dat"
if [ $runningEnv = raspiblitz ]; then
if [ -f "/mnt/hdd/raspiblitz.conf" ]; then
rpc_user=$(sudo cat /mnt/hdd/bitcoin/bitcoin.conf | grep rpcuser | cut -c 9-)
diff --git a/scripts/_functions.sh b/scripts/_functions.sh
index 318634c..4c69bce 100755
--- a/scripts/_functions.sh
+++ b/scripts/_functions.sh
@@ -14,14 +14,6 @@ walletPath="/home/joinmarket/.joinmarket/wallets/"
JMcfgPath="/home/joinmarket/.joinmarket/joinmarket.cfg"
joininConfPath="/home/joinmarket/joinin.conf"
-## dialog fixes
-# fallback for unknown terminal types (e.g., xterm-ghostty)
-if ! infocmp "$TERM" &>/dev/null; then
- export TERM=xterm-256color
-fi
-# fix dialog box drawing characters
-export NCURSES_NO_UTF8_ACS=1
-
# functions
source /home/joinmarket/_functions.menu.sh
source /home/joinmarket/_functions.bitcoincore.sh
@@ -170,16 +162,16 @@ function stopYG() {
function YGnickname() {
# Retrieves nickname from the latest NickServ message in the newest logfile
- newest_log=$(ls -td /home/joinmarket/.joinmarket/logs/*J5* 2>/dev/null | head -n 1)
- if [ -n "$newest_log" ] && [ -f "$newest_log" ]; then
- name=$(grep NickServ "$newest_log" 2>/dev/null | tail -1 | awk '{print $9}')
- if [ ${#name} -eq 0 ]; then
+ if ls -td /home/joinmarket/.joinmarket/logs/* 1>&2>/dev/null ; then
+ newest_log=$(ls -td /home/joinmarket/.joinmarket/logs/* | grep J5 | head -n 1)
+ name=$(grep NickServ $newest_log | tail -1 | awk '{print $9}')
+ if [ ${#name} -eq 0 ];then
name="no_Nick_see_LOGS"
fi
else
name="waiting__to__run"
fi
- echo "$name"
+ echo $name
}
# copyJoininboxScripts
@@ -282,8 +274,8 @@ function generateJMconfig() {
fi
sed -i "s/^rpc_port =.*/rpc_port = $RPCPORT/g" $JMcfgPath
echo "# rpc_port = $RPCPORT"
- sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath
- echo "# using the bitcoind watch-only-descriptor-wallet"
+ sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/g" $JMcfgPath
+ echo "# using the bitcoind wallet: wallet.dat"
# set joinin.conf value
/home/joinmarket/set.value.sh set network mainnet ${joininConfPath}
fi
diff --git a/scripts/install.bitcoincore.sh b/scripts/install.bitcoincore.sh
index 170f058..b29da0c 100755
--- a/scripts/install.bitcoincore.sh
+++ b/scripts/install.bitcoincore.sh
@@ -5,13 +5,13 @@ source /home/joinmarket/_functions.sh
# check connectedRemoteNode var in joinin.conf
if ! grep -Eq "^connectedRemoteNode=" $joininConfPath; then
- echo "connectedRemoteNode=off" >>$joininConfPath
+ echo "connectedRemoteNode=off" >> $joininConfPath
fi
if [ "$1" = "signetOn" ]; then
installBitcoinCore
installSignet
- if [ "$connectedRemoteNode" = "on" ]; then
+ if [ "$connectedRemoteNode" = "on" ];then
backupJMconf
fi
generateJMconfig
@@ -24,16 +24,16 @@ if [ "$1" = "signetOn" ]; then
bitcoinUser="joinmarket"
cliPath="/home/joinmarket/bitcoin/"
fi
- if [ ! -d /home/${bitcoinUser}/.bitcoin/signet/wallets/watch-only-descriptor-wallet ]; then
- echo "# Create watch-only-descriptor-wallet for signet ..."
+ if [ ! -f /home/${bitcoinUser}/.bitcoin/signet/wallets/wallet.dat/wallet.dat ];then
+ echo "# Create wallet.dat for signet ..."
sleep 10
- sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true
+ sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=wallet.dat descriptors=false
fi
elif [ "$1" = "signetOff" ]; then
removeSignetdService
- isSignet=$(grep -c "network = signet" <$JMcfgPath)
- if [ $isSignet -gt 0 ]; then
+ isSignet=$(grep -c "network = signet" < $JMcfgPath)
+ if [ $isSignet -gt 0 ];then
echo "# Removing the joinmarket.cfg with signet settings"
rm -f $JMcfgPath
else
diff --git a/scripts/install.joinmarket.sh b/scripts/install.joinmarket.sh
index 6cb3e81..928848e 100755
--- a/scripts/install.joinmarket.sh
+++ b/scripts/install.joinmarket.sh
@@ -1,21 +1,15 @@
#!/bin/bash
# https://github.com/JoinMarket-Org/joinmarket-clientserver/releases
-# Use tag for verification when available, otherwise use commit hash
-testedJMversion="v0.9.12"
+testedJMversion="v0.9.11"
-# https://github.com/JoinMarket-Org/joinmarket-clientserver/commits/master/
-# Only used if testedJMversion is empty or not set
-#testedJMcommit="ce32bafbb5d716bde61830f71266410249d43dbc"
+PGPsigner="kristapsk"
+PGPpkeys="https://github.com/kristapsk.gpg"
+PGPcheck="33E472FE870C7E5D"
-PGPsigner="AdamISZ"
-PGPpkeys="https://github.com/AdamISZ.gpg"
-# AdamISZ current primary code-signing key used for v0.9.12
-PGPcheck="0F1C7345D9193D1C8E3F21810C44134F93234873"
-
-#PGPsigner="kristapsk"
-#PGPpkeys="https://github.com/kristapsk.gpg"
-#PGPcheck="33E472FE870C7E5D"
+#PGPsigner="waxwing"
+#PGPpkeys="https://raw.githubusercontent.com/JoinMarket-Org/joinmarket-clientserver/master/pubkeys/AdamGibson.asc"
+#PGPcheck="2B6FC204D9BF332D062B461A141001A1AF77F20B"
me="${0##/*}"
@@ -27,7 +21,7 @@ usage() {
printf %s"${me} [--option ]
a script to install, update or configure JoinMarket
-the latest tested version: ${testedJMversion:-$testedJMcommit} is installed by default with the QT GUI
+the latest tested version: $testedJMversion is installed by default with the QT GUI
Options:
-h, --help this help info
@@ -116,12 +110,9 @@ done
: "${install:=install}"
range_argument install "install" "config" "update" "testPR" "commit"
-# Use tag if set, otherwise use commit hash
-: "${version:=${testedJMversion:-$testedJMcommit}}"
-# Only check GitHub releases if version looks like a tag (starts with 'v')
-if [[ "${version}" == v* ]]; then
- curl -s "https://github.com/JoinMarket-Org/joinmarket-clientserver/releases/tag/${version}" | grep -q "\"message\": \"Version not found\"" && error_msg "'There is no: https://github.com/JoinMarket-Org/joinmarket-clientserver/releases/tag/${version}'"
-fi
+: "${version:=${testedJMversion}}"
+curl -s "https://github.com/JoinMarket-Org/joinmarket-clientserver/release/tag/${version}" | grep -q "\"message\": \"Version not found\"" && error_msg "'There is no: https://github.com/JoinMarket-Org/joinmarket-clientserver/release/tag/${version}'"
+
: "${qtgui:=false}"
range_argument qtgui "0" "1" "false" "true"
@@ -192,29 +183,37 @@ function installJoinMarket() {
elif [ "$install" = "update" ] && [ ${#2} -gt 0 ]; then
updateVersion="$2"
sudo -u ${user} git reset --hard $updateVersion
- echo "# Verifying signature for version: $updateVersion"
- # Determine if it's a tag (starts with 'v') or commit hash
- if [[ "$updateVersion" == v* ]]; then
- sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \
- "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" "$updateVersion" || exit 1
- else
- sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \
- "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" || exit 1
- fi
else
- # Decide whether to use tag or commit
- if [ -n "${testedJMversion}" ]; then
- echo "# Installing tested version: ${testedJMversion}"
- sudo -u ${user} git reset --hard $testedJMversion
- echo "# Verifying tag signature: ${testedJMversion}"
- sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \
- "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" "${testedJMversion}" || exit 1
+ sudo -u ${user} git reset --hard $testedJMversion
+
+ sudo -u ${user} wget --prefer-family=ipv4 -O "pgp_keys.asc" ${PGPpkeys}
+ sudo -u ${user} gpg --import --import-options show-only ./pgp_keys.asc
+ fingerprint=$(sudo -u ${user} gpg "pgp_keys.asc" 2>/dev/null | grep "${PGPcheck}" -c)
+ if [ ${fingerprint} -lt 1 ]; then
+ echo
+ echo "# WARNING --> the PGP fingerprint is not as expected for ${PGPsigner}"
+ echo "# Should contain PGP: ${PGPcheck}"
+ echo "# PRESS ENTER to TAKE THE RISK if you think all is OK"
+ read -r
+ fi
+ sudo -u ${user} gpg --import ./pgp_keys.asc
+
+ verifyResult=$(sudo -u ${user} git verify-tag $testedJMversion 2>&1)
+
+ goodSignature=$(echo ${verifyResult} | grep 'Good signature' -c)
+ echo "# goodSignature(${goodSignature})"
+ correctKey=$(echo ${verifyResult} | tr -d " \t\n\r" | grep "${PGPcheck}" -c)
+ echo "# correctKey(${correctKey})"
+ if [ ${correctKey} -lt 1 ] || [ ${goodSignature} -lt 1 ]; then
+ echo
+ echo "# BUILD FAILED --> PGP verification not OK / signature(${goodSignature}) verify(${correctKey})"
+ exit 1
else
- echo "# Installing tested commit: ${testedJMcommit}"
- sudo -u ${user} git reset --hard $testedJMcommit
- echo "# Verifying commit signature: ${testedJMcommit}"
- sudo -u ${user} bash /home/joinmarket/joininbox/scripts/verify.git.sh \
- "${PGPsigner}" "${PGPpkeys}" "${PGPcheck}" || exit 1
+ echo
+ echo "#########################################################"
+ echo "# OK --> the PGP signature of the $testedJMversion tag is correct"
+ echo "#########################################################"
+ echo
fi
fi
diff --git a/scripts/jam-remote/install.jam.sh b/scripts/jam-remote/install.jam.sh
index 9d5af12..8b015f1 100644
--- a/scripts/jam-remote/install.jam.sh
+++ b/scripts/jam-remote/install.jam.sh
@@ -3,7 +3,7 @@
# https://github.com/joinmarket-webui/jam
USERNAME=jam
-WEBUI_VERSION="v0.4.0"
+WEBUI_VERSION="v0.3.0"
REPO=joinmarket-webui/jam
HOME_DIR=/home/${USERNAME}
APP_DIR=webui
diff --git a/scripts/menu.update.sh b/scripts/menu.update.sh
index c1321bf..e854304 100755
--- a/scripts/menu.update.sh
+++ b/scripts/menu.update.sh
@@ -16,15 +16,9 @@ OPTIONS=()
BACKTITLE="JoininBox GUI"
# Basic Options
-# Determine if using tag or commit for display
-testedVersion=$(grep 'testedJMversion=' < ~/install.joinmarket.sh | grep -v '^#' | cut -d '"' -f 2)
-if [ -z "$testedVersion" ]; then
- testedVersion=$(grep 'testedJMcommit=' < ~/install.joinmarket.sh | cut -d '"' -f 2 | cut -c 1-12)
- testedVersion="${testedVersion} (commit)"
-fi
OPTIONS+=(
JOININBOX "Update the JoininBox scripts and menu"
- JOINMARKET "Update/reinstall JoinMarket to ${testedVersion}")
+ JOINMARKET "Update/reinstall JoinMarket to $(grep testedJMversion= < ~/install.joinmarket.sh | cut -d '"' -f 2)")
if [ "$runningEnv" = "standalone" ]; then
OPTIONS+=(\
diff --git a/scripts/menu.wallet.sh b/scripts/menu.wallet.sh
index ea2801f..08e919f 100755
--- a/scripts/menu.wallet.sh
+++ b/scripts/menu.wallet.sh
@@ -194,7 +194,7 @@ Enter the new gap limit to be used" 16 60 2> "$gaplimit"
echo
/home/joinmarket/start.script.sh wallet-tool "$(cat $wallet)"|grep mixdepth|sed -n '1~2p'|awk '{print $3}'
echo
- echo "Import the master public keys to Specter Desktop or Electrum to create watch-only wallets."
+ echo "Import the master public keys to Specter Desktop or Electrum to create watch only wallets."
echo
echo "Press ENTER to return to the menu..."
read key
diff --git a/scripts/standalone/_functions.standalone.sh b/scripts/standalone/_functions.standalone.sh
index d03ed66..a4108cb 100755
--- a/scripts/standalone/_functions.standalone.sh
+++ b/scripts/standalone/_functions.standalone.sh
@@ -290,9 +290,9 @@ WantedBy=multi-user.target
echo "# Monitor the bitcoind with: sudo tail -f /home/bitcoin/.bitcoin/mainnet/debug.log"
echo
- if [ ! -d /home/bitcoin/.bitcoin/wallets/watch-only-descriptor-wallet ]; then
- echo "# Create watch-only-descriptor-wallet ..."
+ if [ ! -f /home/bitcoin/.bitcoin/mainnet/wallets/wallet.dat/wallet.dat ]; then
+ echo "# Create wallet.dat ..."
sleep 10
- sudo -u bitcoin /usr/local/bin/bitcoin-cli -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true
+ sudo -u bitcoin /usr/local/bin/bitcoin-cli -named createwallet wallet_name=wallet.dat descriptors=false
fi
}
diff --git a/scripts/start.service.sh b/scripts/start.service.sh
index a1b4c61..1156475 100755
--- a/scripts/start.service.sh
+++ b/scripts/start.service.sh
@@ -43,18 +43,6 @@ Type=simple
TimeoutSec=infinity
Restart=no
-# Memory limits (DoS / OOM protection)
-MemoryHigh=300M
-MemoryMax=512M
-MemorySwapMax=0
-
-# Reduce OOM kill priority (lower = less likely to be killed)
-OOMScoreAdjust=-500
-OOMPolicy=stop
-
-# CPU limit
-CPUQuota=80%
-
# Hardening measures
PrivateTmp=true
ProtectSystem=full
diff --git a/scripts/verify.git.sh b/scripts/verify.git.sh
index 6360073..89ded16 100644
--- a/scripts/verify.git.sh
+++ b/scripts/verify.git.sh
@@ -30,18 +30,9 @@ PGPsigner="$1"
PGPpubkeyLink="$2"
PGPpubkeyFingerprint="$3"
-_temp_dir="$(mktemp -d -p /dev/shm/ 2>/dev/null || mktemp -d)"
-trap 'rm -rf "$_temp_dir"' EXIT
-
-keyFile="${_temp_dir}/pgp_keys_${PGPsigner}.asc"
-rawKeyFile="${keyFile}.raw"
-
-wget --prefer-family=ipv4 -O "${rawKeyFile}" "${PGPpubkeyLink}"
-# GitHub can add a Note: armor header when an account key cannot be exported.
-# GPG imports the key anyway, but prints a misleading "unknown armor header".
-grep -v '^Note: ' "${rawKeyFile}" >"${keyFile}"
-gpg --quiet --import --import-options show-only "${keyFile}"
-fingerprint=$(gpg --show-keys --with-subkey-fingerprint "${keyFile}" 2>/dev/null | tr -d " \t\n\r" | grep "${PGPpubkeyFingerprint}" -c)
+wget --prefer-family=ipv4 -O /dev/shm/pgp_keys_${PGPsigner}.asc "${PGPpubkeyLink}"
+gpg --import --import-options show-only /dev/shm/pgp_keys_${PGPsigner}.asc
+fingerprint=$(gpg --show-keys /dev/shm/pgp_keys_${PGPsigner}.asc 2>/dev/null | grep "${PGPpubkeyFingerprint}" -c)
if [ "${fingerprint}" -lt 1 ]; then
echo
echo "# WARNING --> the PGP fingerprint is not as expected for ${PGPsigner}" >&2
@@ -49,9 +40,11 @@ if [ "${fingerprint}" -lt 1 ]; then
echo "# Exiting" >&2
exit 7
fi
-gpg --quiet --import "${keyFile}"
+gpg --import /dev/shm/pgp_keys_${PGPsigner}.asc
+rm /dev/shm/pgp_keys_${PGPsigner}.asc
-_temp="${_temp_dir}/git-verify.out"
+trap 'rm -f "$_temp"' EXIT
+_temp="$(mktemp -p /dev/shm/)"
if [ $# -eq 3 ] || [ -z "$4" ]; then
commitHash="$(git log --oneline | head -1 | awk '{print $1}')"
diff --git a/test/README.md b/test/README.md
deleted file mode 100644
index 7196ac1..0000000
--- a/test/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# JoininBox integration tests
-
-Run the local Bats suite with:
-
-```bash
-test/run-bats-local.sh
-```
-
-The descriptor wallet tests require:
-
-- `bats`
-- `bitcoind`
-- `bitcoin-cli`
-- `curl`
-- `jq`
-
-The suite starts its own temporary `bitcoind -regtest` datadir and does not use
-mainnet, signet, or any existing Bitcoin Core state.
-
-The `amd64-image-test` workflow downloads a previously built
-`joininbox-amd64-image-*` artifact, verifies the compressed and raw checksums,
-decompresses a runner-local qcow2 copy, boots it with QEMU in snapshot mode,
-copies a pinned `bats-core` checkout into that temporary VM session, and runs
-the same suite from the JoininBox checkout inside the image. This avoids
-depending on the guest's configured APT repositories just to install test
-tooling.
-
-The test workflow has two entry points:
-
-- `workflow_run`: runs after a successful `amd64-image-build` once this workflow
- exists on the repository default branch.
-- `workflow_dispatch`: reruns against a specific build artifact by providing the
- `amd64-image-build` workflow run ID, as long as the artifact is still retained
- by GitHub Actions.
diff --git a/test/bats/descriptor-wallet.bats b/test/bats/descriptor-wallet.bats
deleted file mode 100644
index 8cb1d9b..0000000
--- a/test/bats/descriptor-wallet.bats
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env bats
-
-root_dir="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
-PATH="/home/joinmarket/bitcoin:/usr/local/bin:$PATH"
-
-require_command() {
- if ! command -v "$1" >/dev/null 2>&1; then
- skip "$1 is required"
- fi
-}
-
-setup() {
- require_command bitcoind
- require_command bitcoin-cli
- require_command curl
- require_command jq
-
- rpc_user="joininbox"
- rpc_pass="joininbox"
- rpc_port="$((20000 + (RANDOM % 20000)))"
- p2p_port="$((40000 + (RANDOM % 20000)))"
- bitcoin_datadir="${BATS_TEST_TMPDIR}/bitcoin"
- joinmarket_cfg="${BATS_TEST_TMPDIR}/joinmarket.cfg"
- joinin_conf="${BATS_TEST_TMPDIR}/joinin.conf"
-
- mkdir -p "$bitcoin_datadir"
-
- bitcoind \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -server \
- -daemonwait \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- -port="$p2p_port" \
- -fallbackfee=0.0001
-
- cat >"$joinmarket_cfg" <"$joinin_conf"
-}
-
-teardown() {
- if [ -n "${bitcoin_datadir:-}" ] && [ -d "$bitcoin_datadir" ]; then
- bitcoin-cli \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- stop >/dev/null 2>&1 || true
- fi
-}
-
-load_joininbox_bitcoin_functions() {
- # shellcheck source=scripts/_functions.bitcoincore.sh
- # shellcheck disable=SC1091
- source "$root_dir/scripts/_functions.bitcoincore.sh"
- # shellcheck disable=SC2034
- JMcfgPath="$joinmarket_cfg"
- # shellcheck disable=SC2034
- joininConfPath="$joinin_conf"
-
- mktemp() {
- if [ "${1:-}" = "-p" ] && [ "${2:-}" = "/dev/shm/" ]; then
- command mktemp "${BATS_TEST_TMPDIR}/joininbox.XXXXXX"
- else
- command mktemp "$@"
- fi
- }
-}
-
-wallet_info() {
- bitcoin-cli \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- -rpcwallet=watch-only-descriptor-wallet \
- getwalletinfo
-}
-
-check_wallet_migration_with_enter() {
- printf "\n" | checkWalletMigration
-}
-
-check_rpc_wallet_with_enter() {
- printf "\n" | checkRPCwallet
-}
-
-@test "checkRPCwallet creates the configured descriptor watch-only wallet" {
- load_joininbox_bitcoin_functions
-
- run checkRPCwallet
-
- [ "$status" -eq 0 ]
- [[ "$output" == *"The wallet: watch-only-descriptor-wallet is present and loaded"* ]]
-
- run wallet_info
- [ "$status" -eq 0 ]
- [ "$(jq -r '.descriptors' <<<"$output")" = "true" ]
- [ "$(jq -r '.private_keys_enabled' <<<"$output")" = "false" ]
- run grep -q "walletMigrationDone" "$joinin_conf"
- [ "$status" -ne 0 ]
-}
-
-@test "customRPC uses the descriptor wallet RPC endpoint" {
- bitcoin-cli \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- -named createwallet \
- wallet_name=watch-only-descriptor-wallet \
- descriptors=true \
- disable_private_keys=true >/dev/null
-
- load_joininbox_bitcoin_functions
-
- run customRPC "# Wallet info" "getwalletinfo" ""
-
- [ "$status" -eq 0 ]
- [[ "$output" == *'"walletname": "watch-only-descriptor-wallet"'* ]]
- [[ "$output" == *'"descriptors": true'* ]]
- [[ "$output" == *'"private_keys_enabled": false'* ]]
-}
-
-@test "checkRPCwallet migrates a persisted wallet.dat configuration on Bitcoin Core v30 or later" {
- bitcoin-cli \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- -named createwallet \
- wallet_name=wallet.dat \
- descriptors=true \
- disable_private_keys=true >/dev/null
- sed \
- "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/" \
- "$joinmarket_cfg" >"${joinmarket_cfg}.legacy"
- mv "${joinmarket_cfg}.legacy" "$joinmarket_cfg"
-
- load_joininbox_bitcoin_functions
-
- run check_rpc_wallet_with_enter
-
- [ "$status" -eq 0 ]
- [[ "$output" == *"Migrating the configured Bitcoin Core wallet"* ]]
- [[ "$output" == *"WALLET MIGRATION NOTICE"* ]]
- grep -q "^rpc_wallet_file = watch-only-descriptor-wallet$" "$joinmarket_cfg"
- grep -q "^walletMigrationDone=true$" "$joinin_conf"
-
- run wallet_info
- [ "$status" -eq 0 ]
- [ "$(jq -r '.descriptors' <<<"$output")" = "true" ]
- [ "$(jq -r '.private_keys_enabled' <<<"$output")" = "false" ]
-}
-
-@test "migrateLegacyRPCWalletConfig keeps wallet.dat on Bitcoin Core v29.2" {
- sed \
- "s/^rpc_wallet_file =.*/rpc_wallet_file = wallet.dat/" \
- "$joinmarket_cfg" >"${joinmarket_cfg}.legacy"
- mv "${joinmarket_cfg}.legacy" "$joinmarket_cfg"
-
- load_joininbox_bitcoin_functions
- getConnectedBitcoinCoreVersion() {
- echo 290200
- }
- getRPC >/dev/null
-
- run migrateLegacyRPCWalletConfig
-
- [ "$status" -eq 0 ]
- [[ "$output" == *"v29.x or earlier; keeping wallet.dat"* ]]
- grep -q "^rpc_wallet_file = wallet.dat$" "$joinmarket_cfg"
-}
-
-@test "checkWalletMigration shows the notice once when wallet.dat exists" {
- bitcoin-cli \
- -regtest \
- -datadir="$bitcoin_datadir" \
- -rpcuser="$rpc_user" \
- -rpcpassword="$rpc_pass" \
- -rpcport="$rpc_port" \
- -named createwallet \
- wallet_name=wallet.dat \
- descriptors=true \
- disable_private_keys=true >/dev/null
-
- load_joininbox_bitcoin_functions
- # shellcheck disable=SC2034
- rpc_host="127.0.0.1"
- # shellcheck disable=SC2034
- rpc_wallet="watch-only-descriptor-wallet"
-
- run check_wallet_migration_with_enter
-
- [ "$status" -eq 0 ]
- [[ "$output" == *"WALLET MIGRATION NOTICE"* ]]
- grep -q "^walletMigrationDone=true$" "$joinin_conf"
-
- run checkWalletMigration
- [ "$status" -eq 0 ]
- [ "$output" = "" ]
-}
diff --git a/test/run-bats-local.sh b/test/run-bats-local.sh
deleted file mode 100755
index ee7320b..0000000
--- a/test/run-bats-local.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-cd "$(dirname "$0")/.."
-
-if ! command -v bats >/dev/null 2>&1; then
- echo "bats is required. Install bats-core, then rerun this script." >&2
- exit 127
-fi
-
-bats test/bats
diff --git a/typos.toml b/typos.toml
index b2ca07e..46ea55e 100644
--- a/typos.toml
+++ b/typos.toml
@@ -7,5 +7,4 @@
[default.extend-words]
# don't correct these false positives
ba = "ba"
-ned = "ned"
-fpr = "fpr"
+ned = "ned"
\ No newline at end of file