joininbox/scripts/install.joinmarket.sh
openoms 16fc83f47d
Some checks are pending
amd64-image-build / amd64-image-build (push) Waiting to run
arm64-rpi-image-build / arm64-rpi-image-build (push) Waiting to run
Test Shellcheck / Run Shellcheck (push) Waiting to run
chore: migrate the watch-only Bitcoin Core wallet to use descriptors (#177)
* chore: update wallet creation to use watch-only-descriptor-wallet

* remove duplicate version check

* fix: update release URL in install script and correct typo in wallet import message

* ci: test amd64 image descriptor wallet migration with Bats

* ci: boot amd64 image tests with OVMF pflash

* fix: gate descriptor wallet migration on Bitcoin Core v30

Detect the connected Bitcoin Core version over RPC before migrating.
Keep wallet.dat for v29.x or when the version cannot be determined.

Add regression coverage for both migration and compatibility paths.

* ci: make amd64 image tests independent of guest apt

Inject a pinned bats-core checkout into the temporary VM instead of
installing Bats through the guest package repositories.

Remove the duplicate pull request trigger and simplify artifact lookup.

* ci: harden image build run

* docs(FAQ): how automatic migration works
2026-08-13 11:57:42 +02:00

314 lines
9.9 KiB
Bash
Executable file

#!/bin/bash
# https://github.com/JoinMarket-Org/joinmarket-clientserver/releases
# Use tag for verification when available, otherwise use commit hash
testedJMversion="v0.9.12"
# https://github.com/JoinMarket-Org/joinmarket-clientserver/commits/master/
# Only used if testedJMversion is empty or not set
#testedJMcommit="ce32bafbb5d716bde61830f71266410249d43dbc"
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##/*}"
nocolor="\033[0m"
red="\033[31m"
## see https://github.com/rootzoll/raspiblitz/blob/v1.7/build_sdcard.sh for code comments
usage() {
printf %s"${me} [--option <argument>]
a script to install, update or configure JoinMarket
the latest tested version: ${testedJMversion:-$testedJMcommit} is installed by default with the QT GUI
Options:
-h, --help this help info
-i, --install [install|config|update|testPR|commit] install options, use 'commit' for the latest master
-v, --version [version|number-of-PR] the version to install or PR to test (default: ${testedJMversion})
-q, --qtgui [0|1] install the QT GUI and dependencies (default: 0)
-u, --user [user] the linux user to install with (default: joinmarket)
Notes:
all options, long and short accept --opt=value mode also
[0|1] can also be referenced as [false|true]
"
exit 1
}
if [ $# -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
usage
fi
error_msg() {
printf %s"${red}${me}: ${1}${nocolor}\n"
exit 1
}
assign_value() {
case "${2}" in
--*) value="${2#--}" ;;
-*) value="${2#-}" ;;
*) value="${2}" ;;
esac
case "${value}" in
0) value="false" ;;
1) value="true" ;;
esac
eval "${1}"="\"${value}\""
}
get_arg() {
case "${3}" in
"" | -*) error_msg "Option '${2}' requires an argument." ;;
esac
assign_value "${1}" "${3}"
}
range_argument() {
name="${1}"
eval var='$'"${1}"
shift
if [ -n "${var:-}" ]; then
success=0
for tests in "${@}"; do
[ "${var}" = "${tests}" ] && success=1
done
[ ${success} -ne 1 ] && error_msg "Option '--${name}' cannot be '${var}'! It can only be: ${*}."
fi
}
while :; do
case "${1}" in
-*=*)
opt="${1%=*}"
arg="${1#*=}"
shift_n=1
;;
-*)
opt="${1}"
arg="${2}"
shift_n=2
;;
*)
opt="${1}"
arg="${2}"
shift_n=1
;;
esac
case "${opt}" in
-i | -i=* | --install | --install=*) get_arg install "${opt}" "${arg}" ;;
-v | -v=* | --version | --version=*) get_arg version "${opt}" "${arg}" ;;
-q | -q=* | --qtgui | --qtgui=*) get_arg qtgui "${opt}" "${arg}" ;;
-u | -u=* | --user | --user=*) get_arg user "${opt}" "${arg}" ;;
"") break ;;
*) error_msg "Invalid option: ${opt}" ;;
esac
shift "${shift_n}"
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
: "${qtgui:=false}"
range_argument qtgui "0" "1" "false" "true"
: "${user:=joinmarket}"
source /home/joinmarket/_functions.sh
source /home/joinmarket/joinin.conf
# create user if not default
if [ "${user}" != "joinmarket" ]; then
echo "# add the '${user}' user"
sudo adduser --system --group --shell /bin/bash --home /home/${user} ${user}
echo "Copy the skeleton files for login"
sudo -u ${user} cp -r /etc/skel/. /home/${user}/
sudo adduser ${user} sudo
# add user to Tor group
sudo usermod -a -G debian-tor ${user}
# configure for usage without password entry
checkEntry=$(sudo cat /etc/sudoers | grep -c "${user} ALL=(ALL) NOPASSWD:ALL")
if [ ${checkEntry} -eq 0 ]; then
echo "${user} ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers
fi
# Autostart
checkEntry=$(sudo -u ${user} cat /home/${user}/.bashrc | grep -c "jmvenv/bin/activate")
if [ ${checkEntry} -eq 0 ]; then
echo "
if [ -f \"/home/${user}/joinmarket-clientserver/jmvenv/bin/activate\" ]; then
. /home/${user}/joinmarket-clientserver/jmvenv/bin/activate
cd /home/${user}/joinmarket-clientserver/scripts/
fi
" | sudo -u ${user} tee -a /home/${user}/.bashrc
fi
fi
# qtgui entry in joinin.conf
checkEntry=$(sudo -u ${user} cat /home/${user}/joinin.conf | grep -c "qtgui")
if [ ${checkEntry} -eq 0 ]; then
echo "qtgui=true" | sudo -u ${user} tee -a /home/${user}/joinin.conf
fi
sudo -u ${user} sed -i "s/^qtgui=.*/qtgui=${qtgui}/g" /home/${user}/joinin.conf
# installJoinMarket [update|testPR <PRnumber>|commit]
function installJoinMarket() {
cd /home/${user} || exit 1
# https://github.com/JoinMarket-Org/joinmarket-clientserver/issues/668#issuecomment-717815719
sudo apt-get install -y build-essential automake pkg-config libffi-dev python3-dev
sudo -u ${user} pip config set global.break-system-packages true
sudo -u ${user} pip install libtool asn1crypto cffi pycparser
echo "# Installing JoinMarket"
if [ "$install" = "update" ] || [ "$install" = "testPR" ] || [ "$install" = "commit" ]; then
echo "# Deleting the old source code (joinmarket-clientserver directory)"
sudo rm -rf /home/${user}/joinmarket-clientserver
fi
sudo -u ${user} git clone https://github.com/Joinmarket-Org/joinmarket-clientserver
cd joinmarket-clientserver || exit 1
if [ "$install" = "testPR" ]; then
PRnumber=$2
echo "# Using the PR:"
echo "# https://github.com/JoinMarket-Org/joinmarket-clientserver/release/tag/$PRnumber"
sudo -u ${user} git fetch origin pull/$PRnumber/head:pr$PRnumber
sudo -u ${user} git checkout pr$PRnumber
elif [ "$install" = "commit" ]; then
echo "# Updating to the latest commit in:"
echo "# https://github.com/JoinMarket-Org/joinmarket-clientserver"
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
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
# Use specific python version, if set
python_args=""
if [[ -n "${JM_PYTHON}" ]]; then
python_args="--python=${JM_PYTHON}"
fi
# do not clear screen during installation
sudo -u ${user} sed -i 's/clear//g' install.sh
if [ "${qtgui}" = "false" ]; then
GUIchoice="--without-qt"
else
GUIchoice="--with-qt"
fi
if [ "$install" = "update" ] || [ "$install" = "testPR" ] || [ "$install" = "commit" ]; then
# do not run libsecp256k1 test
sudo -u ${user} ./install.sh "${GUIchoice}" --disable-secp-check "$python_args" || exit 1
else
sudo -u ${user} ./install.sh "${GUIchoice}" "$python_args" || exit 1
fi
currentJMversion=$(
cd /home/${user}/joinmarket-clientserver 2>/dev/null
git describe --tags 2>/dev/null
)
echo
echo "# installed JoinMarket $currentJMversion"
echo
echo "# Type: 'exit' to leave the terminal and log in again"
echo
}
if [ "$install" = "config" ]; then
if [ ! -f "$JMcfgPath" ]; then
generateJMconfig
fi
# show info
dialog \
--title "Configure JoinMarket" \
--exit-label "Continue to edit the joinmarket.cfg" \
--textbox "/home/joinmarket/info.conf.txt" 43 108
# edit joinmarket.cfg
/home/${user}/set.conf.sh $JMcfgPath
exit 0
fi
if [ "$install" = "install" ]; then
# install joinmarket
if [ ! -f "/home/${user}/joinmarket-clientserver/jmvenv/bin/activate" ]; then
echo
echo "# JoinMarket is not yet installed - proceeding now"
echo
installJoinMarket
errorOnInstall $?
echo "# Check for optional dependencies: matplotlib and scipy"
activateJMvenv
if [ "$(pip list | grep -c matplotlib)" -eq 0 ]; then
pip install matplotlib
fi
if [ "$(pip list | grep -c scipy)" -eq 0 ]; then
# https://stackoverflow.com/questions/7496547/does-python-scipy-need-blas
sudo apt-get install -y gfortran libopenblas-dev liblapack-dev
# fix 'No space left on device' with 2GB RAM
export TMPDIR='/var/tmp'
pip install scipy
export TMPDIR='/tmp'
fi
else
echo
echo "# JoinMarket $currentJMversion is installed"
echo
fi
exit 0
fi
if [ "$install" = "update" ]; then
stopYG
installJoinMarket "update" "$2"
errorOnInstall $?
exit 0
fi
if [ "$install" = "testPR" ]; then
stopYG
installJoinMarket testPR $2
errorOnInstall $?
exit 0
fi
if [ "$install" = "commit" ]; then
stopYG
installJoinMarket commit
errorOnInstall $?
exit 0
fi