Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.git
*.egg-info
deps
jmvenv
jmvenv
compose.yml
Dockerfile
46 changes: 35 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
FROM debian:bookworm-slim

RUN mkdir -p /jm/clientserver
ARG BITCOIN_VERSION=29.2
ARG PYTHON_IMAGE_TAG=3.12-slim-trixie
FROM bitcoin/bitcoin:${BITCOIN_VERSION} AS bitcoin
FROM python:${PYTHON_IMAGE_TAG} AS python
WORKDIR /jm/clientserver
COPY ./pubkeys ./pubkeys
COPY ./install.sh ./install.sh

COPY . .

RUN apt-get update && apt-get install -y --no-install-recommends gnupg ca-certificates=* curl=* \
python3-pip=* python3=* \
&& pip3 config set global.break-system-packages true \
&& pip3 install 'wheel>=0.35.1' \
&& ./install.sh --docker-install \
&& apt-get purge -y --autoremove python3-pip \
FROM python AS base-deps
RUN DEBIAN_FRONTEND=noninteractive \
apt-get update \
&& apt-get install -y --no-install-recommends \
libsecp256k1-2 \
libsodium23 \
openssl \
tor \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

FROM base-deps AS builder
COPY . .
RUN python -m venv jmvenv \
&& . ./jmvenv/bin/activate \
&& pip install .[services]

FROM base-deps AS base
COPY --from=builder /jm/clientserver /jm/clientserver
ENTRYPOINT ["./scripts/docker-entrypoint.sh"]

FROM base AS test
ARG BITCOIN_VERSION
COPY --from=bitcoin /opt/bitcoin-${BITCOIN_VERSION}/bin /usr/local/bin/
RUN . ./jmvenv/bin/activate \
&& pip install .[test]

FROM base AS obwatcher
RUN . ./jmvenv/bin/activate && pip install matplotlib
CMD ["python", "./scripts/obwatch/ob-watcher.py"]

FROM base AS final
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ Alternative to this "quickstart": follow the [install guide](docs/INSTALL.md).
* [Installation guide for Qubes+Whonix](https://github.com/qubenix/qubes-whonix-bitcoin/blob/master/1_joinmarket.md).
* [Youtube video installation tutorial for Ubuntu](https://www.youtube.com/watch?v=zTCC86IUzWo).

### Docker

JoinMarket can be built and run using Docker. To build the Docker image:

docker build -t joinmarket .

To run tests using Docker Compose:

docker compose up test

This will run the full test suite in an isolated environment with all necessary dependencies including Bitcoin Core.

### Usage

If you are new, follow and read the links in the [usage guide](docs/USAGE.md).
Expand Down
21 changes: 21 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
test:
image: joinmarket:test
build:
context: .
target: test
args: &build_args
BITCOIN_VERSION: 29.2
PYTHON_IMAGE_TAG: 3.12-slim-trixie
volumes:
- ./src:/jm/clientserver/src
- ./test:/jm/clientserver/test
shm_size: '2gb'
command: ["./test/run_tests.sh", "-v"]
obwatcher:
image: joinmarket:obwatcher
build:
context: .
target: obwatcher
args: *build_args
command: ["python", "./scripts/obwatch/ob-watcher.py"]
45 changes: 39 additions & 6 deletions docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,47 @@ There, you need to install the client code (without Joinmarket's bitcoin):

#### Docker Installation

The [Dockerfile](../Dockerfile) provided builds a minimal Docker image which can help in getting started with a custom Docker setup. An example of building and running the [wallet-tool.py](../scripts/wallet-tool.py) script:
The [Dockerfile](../Dockerfile) provided builds an optimized multi-stage Docker image for JoinMarket. The build process is optimized for layer caching and includes all necessary dependencies.

```
docker build -t joinmarket-test ./
docker run --rm -it joinmarket-test bash -c "cd scripts && python3 wallet-tool.py --help"
```
##### Building the Docker image

To build the production image:

docker build -t joinmarket .

This creates a minimal production image with JoinMarket installed.

##### Running JoinMarket scripts in Docker

Example of running the [wallet-tool.py](../scripts/wallet-tool.py) script:

docker run --rm -it joinmarket bash -c "source jmvenv/bin/activate && cd scripts && python wallet-tool.py --help"

##### Running tests with Docker Compose

The repository includes a `compose.yml` file for easy testing:

docker compose up test

This will:

* Build a test image that includes Bitcoin Core 29.2
* Mount the `src` and `test` directories for development
* Run the full test suite with all dependencies configured automatically
* Use shared memory for improved test performance

##### Building custom images

The Dockerfile uses multi-stage builds with the following targets:

* `joinmarket` (default) - Production image with JoinMarket installed
* `test` - Testing image that includes Bitcoin Core binaries

You can build a specific target:

docker build --target test -t joinmarket:test .

A new Docker image can be built using `joinmarket-test` as a base using `FROM joinmarket-test`. See [Docker documentation](https://docs.docker.com/engine/reference/builder/) for more details.
See [Docker documentation](https://docs.docker.com/engine/reference/builder/) for more details on multi-stage builds.

#### Development (or making other changes to the code)

Expand Down
17 changes: 17 additions & 0 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
### Test instructions (for developers):

#### Quick start: Running tests with Docker

The easiest way to run the full test suite is using Docker Compose, which handles all dependencies automatically:

docker compose run --rm test

This will:

* Build a Docker image with all dependencies (Python, Bitcoin Core 29.2, miniircd)
* Run the complete test suite in an isolated environment
* Automatically download and set up miniircd
* No need to install bitcoind or other dependencies on your host machine

For development, the Docker setup mounts the `src` and `test` directories, so you can make changes locally and re-run tests without rebuilding the image.

#### Manual setup

Work in your `jmvenv` virtual environment as for all Joinmarket work. Make sure to have [bitcoind](https://bitcoin.org/en/full-node) 28.1 or newer installed. Also need miniircd installed to the root (i.e. in your `joinmarket-clientserver` directory):

(jmvenv)$ cd /path/to/joinmarket-clientserver
Expand Down
53 changes: 24 additions & 29 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ CookieAuthentication 1

joinmarket_install ()
{
if [[ ${without_jm} == 1 ]]; then
return 0
fi
reqs='services'

if [[ ${with_qt} == "1" ]]; then
Expand All @@ -426,8 +429,7 @@ joinmarket_install ()
reqs+=',test'
fi

if [ "$with_jmvenv" == 1 ]; then pip_command=pip; else pip_command=pip3; fi
$pip_command install -e ".[${reqs}]" || return 1
pip install -e ".[${reqs}]" || return 1

if [[ ${with_qt} == "1" ]]; then
if [[ -d ~/.local/share/icons ]] && [[ -d ~/.local/share/applications ]]; then
Expand Down Expand Up @@ -486,7 +488,9 @@ parse_flags ()
;;
--docker-install)
with_sudo='0'
with_jmvenv='0'
;;
--deps)
without_jm='1'
;;
"")
break
Expand All @@ -509,6 +513,7 @@ Options:
--with-local-tor build Tor locally and autostart when needed
--with-qt build the Qt GUI
--without-qt don't build the Qt GUI
--deps install dependencies only, do not build or install Joinmarket
"
return 1
;;
Expand Down Expand Up @@ -570,22 +575,18 @@ main ()
use_os_deps_check='1'
use_secp_check='1'
with_qt=''
with_jmvenv='1'
with_sudo='1'
without_jm='0'
reinstall='false'
if ! parse_flags "${@}"; then
return 1
fi

jm_source="$PWD"
if [ "$with_jmvenv" == 1 ]; then
jm_root="${jm_source}/jmvenv"
export PKG_CONFIG_PATH="${jm_root}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export LD_LIBRARY_PATH="${jm_root}/lib:${LD_LIBRARY_PATH}"
export C_INCLUDE_PATH="${jm_root}/include:${C_INCLUDE_PATH}"
else
jm_root=""
fi
jm_root="${jm_source}/jmvenv"
export PKG_CONFIG_PATH="${jm_root}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export LD_LIBRARY_PATH="${jm_root}/lib:${LD_LIBRARY_PATH}"
export C_INCLUDE_PATH="${jm_root}/include:${C_INCLUDE_PATH}"

# os check
install_os="$( install_get_os )"
Expand All @@ -597,16 +598,12 @@ main ()

MAKEFLAGS="-j $(num_cores)" && export MAKEFLAGS

if [ "$with_jmvenv" == 1 ]; then
if ! venv_setup; then
echo "Joinmarket Python virtual environment could not be setup. Exiting."
return 1
fi
# shellcheck source=/dev/null
source "${jm_root}/bin/activate"
else
upgrade_setuptools
if ! venv_setup; then
echo "Joinmarket Python virtual environment could not be setup. Exiting."
return 1
fi
# shellcheck source=/dev/null
source "${jm_root}/bin/activate"
if [[ ${build_local_tor} == "1" ]]; then
if ! tor_deps_install; then
echo "Tor dependencies could not be installed. Exiting."
Expand Down Expand Up @@ -638,17 +635,15 @@ main ()
popd || return 1
if ! joinmarket_install; then
echo "Joinmarket was not installed. Exiting."
if [ "$with_jmvenv" == 1 ]; then deactivate; fi
deactivate
return 1
fi
if [ "$with_jmvenv" == 1 ]; then
deactivate
echo "Joinmarket successfully installed
Before executing scripts or tests, run:
deactivate
echo "Joinmarket successfully installed
Before executing scripts or tests, run:

\`source jmvenv/bin/activate\`
\`source jmvenv/bin/activate\`

from this directory, to activate the virtual environment."
fi
from this directory, to activate the virtual environment."
}
main "${@}"
5 changes: 5 additions & 0 deletions scripts/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

# shellcheck disable=SC1091
source jmvenv/bin/activate
exec "$@"
Loading