mirror of
https://github.com/openoms/joininbox.git
synced 2026-08-13 12:33:14 +02:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16fc83f47d | ||
|
|
54473190c8 | ||
|
|
dfb33c8ab0 | ||
|
|
aa8d79c97d | ||
|
|
efdf660969 | ||
|
|
554a20a297 | ||
|
|
7a61e3b357 | ||
|
|
f92be4e5b3 | ||
|
|
ea675689c5 |
28 changed files with 1176 additions and 261 deletions
15
.editorconfig
Normal file
15
.editorconfig
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# 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
|
||||
65
.github/workflows/amd64-image-test.yml
vendored
Normal file
65
.github/workflows/amd64-image-test.yml
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
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"
|
||||
60
.github/workflows/packer-syntax-check.yml
vendored
Normal file
60
.github/workflows/packer-syntax-check.yml
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
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
|
||||
70
FAQ.md
70
FAQ.md
|
|
@ -30,6 +30,7 @@
|
|||
- [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)
|
||||
|
|
@ -195,7 +196,7 @@ Use `ssh` with `torsocks` on the desktop (needs Tor installed):
|
|||
server=1
|
||||
daemon=1
|
||||
disablewallet=0
|
||||
main.wallet=wallet.dat
|
||||
main.wallet=watch-only-descriptor-wallet
|
||||
|
||||
# Connection settings
|
||||
rpcuser=REDACTED
|
||||
|
|
@ -428,7 +429,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 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-descriptor-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`
|
||||
|
|
@ -437,7 +438,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 watch only in the remote bitcoind.
|
||||
in the joinmarket.cfg is the wallet which is used as a watch-only-descriptor-wallet 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`
|
||||
|
|
@ -449,6 +450,65 @@ 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.
|
||||
|
|
@ -519,7 +579,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 wallet.dat
|
||||
# drwx------ 2 bitcoin bitcoin 4096 Mar 21 10:38 watch-only-descriptor-wallet
|
||||
installMainnet
|
||||
...
|
||||
# # OK - the bitcoind.service is now enabled
|
||||
|
|
@ -528,7 +588,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 wallet.dat ...
|
||||
# # Create watch-only-descriptor-wallet ...
|
||||
# error code: -28
|
||||
# error message:
|
||||
# Loading block index...
|
||||
|
|
|
|||
16
README.md
16
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 4 or 3](#raspberrypi-4-or-3)
|
||||
- [RaspberryPi 5 or 4](#raspberrypi-5-or-4)
|
||||
- [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,7 +32,6 @@ A minimalistic, security focused linux environment for JoinMarket with a termina
|
|||
- [More info](#more-info)
|
||||
- [About JoinMarket](#about-joinmarket)
|
||||
- [Forums](#forums)
|
||||
- [Donations](#donations)
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -44,19 +43,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 the RaspiBlitz SERVICES
|
||||
* JoininBox is part of the RaspiBlitz SERVICES
|
||||
|
||||
**The addresses, transactions and balances of JoinMarket can be seen in the watch-only wallet of the connected node.**
|
||||
**The addresses, transactions and balances of JoinMarket can be seen in the watch-only-descriptor-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 4 or 3
|
||||
### RaspberryPi 5 or 4
|
||||
* Power supply (5V 3A and above recommended)
|
||||
* Heatsink case
|
||||
* 32 GB Endurence type SDcard
|
||||
* 32 GB Endurance 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:
|
||||
|
|
@ -162,8 +161,3 @@ 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: <https://www.reddit.com/r/joinmarket/>
|
||||
* Keybase: <https://keybase.io/team/raspiblitz#joinmarket>
|
||||
|
||||
## Donations
|
||||
* For JoinMarket (general): https://bitcoinprivacy.me/joinmarket-donations
|
||||
* To waxwing for JoinMarket: <https://joinmarket.me/donations/>
|
||||
* To openoms for JoininBox (LN + payjoin enabled - open in the [Tor Browser](https://www.torproject.org/)): <http://7tpv3ynajkv6cdocmzitcd4z3xrstp3ic6xtv5om3dc2ned3fffll5qd.onion/apps/4FePMm7m818oppkTYNZRwbDnL6HP/pos>
|
||||
|
|
|
|||
|
|
@ -276,22 +276,30 @@ 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.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.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.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"
|
||||
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"
|
||||
else
|
||||
echo "# FAIL- there is no tested version of python present"
|
||||
exit 1
|
||||
|
|
@ -391,11 +399,11 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
command="sudo -u joinmarket bash /home/joinmarket/joininbox/scripts/verify.git.sh \
|
||||
command="bash /home/joinmarket/joininbox/scripts/verify.git.sh \
|
||||
${PGPsigner} ${PGPpubkeyLink} ${PGPpubkeyFingerprint}"
|
||||
echo "running: ${command}"
|
||||
chmod 777 /dev/shm
|
||||
${command} || exit 1
|
||||
sudo -u joinmarket ${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"
|
||||
|
|
|
|||
120
ci/amd64/debian/build.amd64-debian.pkr.hcl
Normal file
120
ci/amd64/debian/build.amd64-debian.pkr.hcl
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# 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" ? [
|
||||
"<wait><wait><wait>c<wait><wait><wait>",
|
||||
"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 --<enter>",
|
||||
"initrd /install.amd/initrd.gz<enter>",
|
||||
"boot<enter>"
|
||||
] : [
|
||||
"<esc><wait>install <wait>",
|
||||
"<wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait><wait> preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/${var.preseed_file} <wait>",
|
||||
"debian-installer=en_US.UTF-8 <wait>",
|
||||
"auto <wait>",
|
||||
"locale=en_US.UTF-8 <wait>",
|
||||
"kbd-chooser/method=us <wait>",
|
||||
"keyboard-configuration/xkb-keymap=us <wait>",
|
||||
"netcfg/get_hostname=${var.hostname} <wait>",
|
||||
"netcfg/get_domain=${var.hostname}.local <wait>",
|
||||
"fb=false <wait>",
|
||||
"debconf/frontend=noninteractive <wait>",
|
||||
"console-setup/ask_detect=false <wait>",
|
||||
"console-keymaps-at/keymap=us <wait>",
|
||||
"grub-installer/bootdev=default <wait>",
|
||||
"<enter><wait>"
|
||||
]
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
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
|
||||
72
ci/amd64/debian/http/preseed.cfg
Normal file
72
ci/amd64/debian/http/preseed.cfg
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# 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
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
{
|
||||
"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": "<esc><wait>install <wait> preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/{{user `preseed_path`}} <wait>debian-installer=en_US.UTF-8 <wait>auto <wait>locale=en_US.UTF-8 <wait>kbd-chooser/method=us <wait>keyboard-configuration/xkb-keymap=us <wait>netcfg/get_hostname={{ .Name }} <wait>netcfg/get_domain=vagrantup.com <wait>fb=false <wait>debconf/frontend=noninteractive <wait>console-setup/ask_detect=false <wait>console-keymaps-at/keymap=us <wait>grub-installer/bootdev=default <wait><enter><wait>",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,39 +1,135 @@
|
|||
#!/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
|
||||
# install qemu and UEFI firmware
|
||||
echo "# Install qemu ..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y qemu-system
|
||||
|
||||
# install qemu plugin
|
||||
packer plugins install github.com/hashicorp/qemu
|
||||
sudo apt-get install -y qemu-system ovmf
|
||||
|
||||
# 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 "# Building image ..."
|
||||
echo "# Build the image with: github_user=${github_user} branch=${branch}"
|
||||
cd debian
|
||||
PACKER_LOG=1 packer build \
|
||||
-var github_user=${github_user} -var branch=${branch} \
|
||||
-only=qemu joininbox-amd64-debian.json
|
||||
packer init -upgrade .
|
||||
PACKER_LOG=1 packer build ${vars} -only=qemu.debian build.amd64-debian.pkr.hcl || exit 1
|
||||
|
|
|
|||
138
ci/amd64/test.amd64-image-bats.sh
Executable file
138
ci/amd64/test.amd64-image-bats.sh
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
#!/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"
|
||||
|
|
@ -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 numbes 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 numbers 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`
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ dialog_color = (CYAN,BLACK,OFF)
|
|||
title_color = (CYAN,BLACK,ON)
|
||||
|
||||
# Dialog box border color
|
||||
border_color = (BLACK,BLACK,ON)
|
||||
border_color = (CYAN,BLACK,ON)
|
||||
|
||||
# Active button color
|
||||
button_active_color = (BLACK,CYAN,ON)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ joininConfPath="/home/joinmarket/joinin.conf"
|
|||
function downloadBitcoinCore() {
|
||||
# set version
|
||||
# https://bitcoincore.org/en/download/
|
||||
bitcoinVersion="26.1"
|
||||
bitcoinVersion="29.2"
|
||||
|
||||
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 = wallet.dat/g" $JMcfgPath
|
||||
echo "# using the bitcoind wallet: wallet.dat"
|
||||
sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath
|
||||
echo "# using the bitcoind watch-only-descriptor-wallet"
|
||||
# rpc_host
|
||||
sed -i "s/^rpc_host =.*/rpc_host = 127.0.0.1/g" $JMcfgPath
|
||||
echo "# rpc_host = 127.0.0.1"
|
||||
|
|
@ -321,38 +321,79 @@ 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 <wallet>
|
||||
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 wallet in Bitcoin Core named $rpc_wallet"
|
||||
echo "# Setting a watch-only-descriptor-wallet in Bitcoin Core named $rpc_wallet"
|
||||
tor=""
|
||||
if [ $(echo $rpc_host | grep -c .onion) -gt 0 ]; then
|
||||
tor="torsocks"
|
||||
|
|
@ -361,8 +402,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":false}}' \
|
||||
http://$rpc_user:$rpc_pass@$rpc_host:$rpc_port/wallet/$rpc_wallet | jq .
|
||||
'{"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 .
|
||||
echo
|
||||
walletFound=$(customRPC "# Check wallet" "listwallets" 2>$connectionOutput | grep -c "$rpc_wallet")
|
||||
if [ $walletFound -eq 0 ]; then
|
||||
|
|
@ -374,6 +415,75 @@ 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
|
||||
|
|
@ -435,7 +545,7 @@ function connectLocalNode() {
|
|||
elif [ "${network}" = testnet ]; then
|
||||
rpc_port="18332"
|
||||
fi
|
||||
rpc_wallet="wallet.dat"
|
||||
rpc_wallet="watch-only-descriptor-wallet"
|
||||
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-)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ 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
|
||||
|
|
@ -162,16 +170,16 @@ function stopYG() {
|
|||
|
||||
function YGnickname() {
|
||||
# Retrieves nickname from the latest NickServ message in the newest logfile
|
||||
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
|
||||
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
|
||||
name="no_Nick_see_LOGS"
|
||||
fi
|
||||
else
|
||||
name="waiting__to__run"
|
||||
fi
|
||||
echo $name
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
# copyJoininboxScripts
|
||||
|
|
@ -274,8 +282,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 = wallet.dat/g" $JMcfgPath
|
||||
echo "# using the bitcoind wallet: wallet.dat"
|
||||
sed -i "s/^rpc_wallet_file =.*/rpc_wallet_file = watch-only-descriptor-wallet/g" $JMcfgPath
|
||||
echo "# using the bitcoind watch-only-descriptor-wallet"
|
||||
# set joinin.conf value
|
||||
/home/joinmarket/set.value.sh set network mainnet ${joininConfPath}
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -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 [ ! -f /home/${bitcoinUser}/.bitcoin/signet/wallets/wallet.dat/wallet.dat ];then
|
||||
echo "# Create wallet.dat for signet ..."
|
||||
if [ ! -d /home/${bitcoinUser}/.bitcoin/signet/wallets/watch-only-descriptor-wallet ]; then
|
||||
echo "# Create watch-only-descriptor-wallet for signet ..."
|
||||
sleep 10
|
||||
sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=wallet.dat descriptors=false
|
||||
sudo -u ${bitcoinUser} ${cliPath}/bitcoin-cli -signet -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
# https://github.com/JoinMarket-Org/joinmarket-clientserver/releases
|
||||
testedJMversion="v0.9.11"
|
||||
# Use tag for verification when available, otherwise use commit hash
|
||||
testedJMversion="v0.9.12"
|
||||
|
||||
PGPsigner="kristapsk"
|
||||
PGPpkeys="https://github.com/kristapsk.gpg"
|
||||
PGPcheck="33E472FE870C7E5D"
|
||||
# https://github.com/JoinMarket-Org/joinmarket-clientserver/commits/master/
|
||||
# Only used if testedJMversion is empty or not set
|
||||
#testedJMcommit="ce32bafbb5d716bde61830f71266410249d43dbc"
|
||||
|
||||
#PGPsigner="waxwing"
|
||||
#PGPpkeys="https://raw.githubusercontent.com/JoinMarket-Org/joinmarket-clientserver/master/pubkeys/AdamGibson.asc"
|
||||
#PGPcheck="2B6FC204D9BF332D062B461A141001A1AF77F20B"
|
||||
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"
|
||||
|
||||
me="${0##/*}"
|
||||
|
||||
|
|
@ -21,7 +27,7 @@ usage() {
|
|||
printf %s"${me} [--option <argument>]
|
||||
|
||||
a script to install, update or configure JoinMarket
|
||||
the latest tested version: $testedJMversion is installed by default with the QT GUI
|
||||
the latest tested version: ${testedJMversion:-$testedJMcommit} is installed by default with the QT GUI
|
||||
|
||||
Options:
|
||||
-h, --help this help info
|
||||
|
|
@ -110,9 +116,12 @@ done
|
|||
: "${install:=install}"
|
||||
range_argument install "install" "config" "update" "testPR" "commit"
|
||||
|
||||
: "${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}'"
|
||||
|
||||
# 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
|
||||
: "${qtgui:=false}"
|
||||
range_argument qtgui "0" "1" "false" "true"
|
||||
|
||||
|
|
@ -183,37 +192,29 @@ function installJoinMarket() {
|
|||
elif [ "$install" = "update" ] && [ ${#2} -gt 0 ]; then
|
||||
updateVersion="$2"
|
||||
sudo -u ${user} git reset --hard $updateVersion
|
||||
else
|
||||
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
|
||||
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
|
||||
echo
|
||||
echo "#########################################################"
|
||||
echo "# OK --> the PGP signature of the $testedJMversion tag is correct"
|
||||
echo "#########################################################"
|
||||
echo
|
||||
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
|
||||
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
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# https://github.com/joinmarket-webui/jam
|
||||
|
||||
USERNAME=jam
|
||||
WEBUI_VERSION="v0.3.0"
|
||||
WEBUI_VERSION="v0.4.0"
|
||||
REPO=joinmarket-webui/jam
|
||||
HOME_DIR=/home/${USERNAME}
|
||||
APP_DIR=webui
|
||||
|
|
|
|||
|
|
@ -16,9 +16,15 @@ 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 $(grep testedJMversion= < ~/install.joinmarket.sh | cut -d '"' -f 2)")
|
||||
JOINMARKET "Update/reinstall JoinMarket to ${testedVersion}")
|
||||
|
||||
if [ "$runningEnv" = "standalone" ]; then
|
||||
OPTIONS+=(\
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -290,9 +290,9 @@ WantedBy=multi-user.target
|
|||
echo "# Monitor the bitcoind with: sudo tail -f /home/bitcoin/.bitcoin/mainnet/debug.log"
|
||||
echo
|
||||
|
||||
if [ ! -f /home/bitcoin/.bitcoin/mainnet/wallets/wallet.dat/wallet.dat ]; then
|
||||
echo "# Create wallet.dat ..."
|
||||
if [ ! -d /home/bitcoin/.bitcoin/wallets/watch-only-descriptor-wallet ]; then
|
||||
echo "# Create watch-only-descriptor-wallet ..."
|
||||
sleep 10
|
||||
sudo -u bitcoin /usr/local/bin/bitcoin-cli -named createwallet wallet_name=wallet.dat descriptors=false
|
||||
sudo -u bitcoin /usr/local/bin/bitcoin-cli -named createwallet wallet_name=watch-only-descriptor-wallet descriptors=true disable_private_keys=true
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ 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
|
||||
|
|
|
|||
|
|
@ -30,9 +30,18 @@ PGPsigner="$1"
|
|||
PGPpubkeyLink="$2"
|
||||
PGPpubkeyFingerprint="$3"
|
||||
|
||||
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)
|
||||
_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)
|
||||
if [ "${fingerprint}" -lt 1 ]; then
|
||||
echo
|
||||
echo "# WARNING --> the PGP fingerprint is not as expected for ${PGPsigner}" >&2
|
||||
|
|
@ -40,11 +49,9 @@ if [ "${fingerprint}" -lt 1 ]; then
|
|||
echo "# Exiting" >&2
|
||||
exit 7
|
||||
fi
|
||||
gpg --import /dev/shm/pgp_keys_${PGPsigner}.asc
|
||||
rm /dev/shm/pgp_keys_${PGPsigner}.asc
|
||||
gpg --quiet --import "${keyFile}"
|
||||
|
||||
trap 'rm -f "$_temp"' EXIT
|
||||
_temp="$(mktemp -p /dev/shm/)"
|
||||
_temp="${_temp_dir}/git-verify.out"
|
||||
|
||||
if [ $# -eq 3 ] || [ -z "$4" ]; then
|
||||
commitHash="$(git log --oneline | head -1 | awk '{print $1}')"
|
||||
|
|
|
|||
34
test/README.md
Normal file
34
test/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# 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.
|
||||
214
test/bats/descriptor-wallet.bats
Normal file
214
test/bats/descriptor-wallet.bats
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
#!/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" <<EOF
|
||||
rpc_user = $rpc_user
|
||||
rpc_password = $rpc_pass
|
||||
rpc_host = 127.0.0.1
|
||||
rpc_port = $rpc_port
|
||||
rpc_wallet_file = watch-only-descriptor-wallet
|
||||
EOF
|
||||
: >"$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" = "" ]
|
||||
}
|
||||
11
test/run-bats-local.sh
Executable file
11
test/run-bats-local.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/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
|
||||
|
|
@ -7,4 +7,5 @@
|
|||
[default.extend-words]
|
||||
# don't correct these false positives
|
||||
ba = "ba"
|
||||
ned = "ned"
|
||||
ned = "ned"
|
||||
fpr = "fpr"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue