Skip to content

PR: Add Joinmarket Tumbler Support with Logging and Scenarios#6

Open
DavidRajnoha wants to merge 8 commits into
crocs-muni:mainfrom
DavidRajnoha:tubmler-and-scenarios
Open

PR: Add Joinmarket Tumbler Support with Logging and Scenarios#6
DavidRajnoha wants to merge 8 commits into
crocs-muni:mainfrom
DavidRajnoha:tubmler-and-scenarios

Conversation

@DavidRajnoha

Copy link
Copy Markdown

This PR introduces Joinmarket tumbler functionality along with improved logging and scenario generation:

  • Adds tumbler script support via RPC with configurable delays between CoinJoins
  • Implements standardized logging format matching Wasabi wallet for coins and keys
  • Adds scenario generation capabilities for tumbler and other Joinmarket operations
  • Includes documentation for Joinmarket logging and scenario configurations
  • Refactors JM Client into separate maker/taker/tumbler classes for better organization

Added the support to start tumbler script via RPC
Refactored JM Client to separate maker/taker/tumbler subclasses
Modified takers to be able to wait between coinjoin attempts
The logs from joinmarket now follow the format of wasabi wallet
listcoins, listunspentcoins and listkeys method, supporting the fields
that are possible to gather or derive.
Added the option to generate tumbler scenarios and created few default
scenarios.
Contains information about running joinmarket specific scenarios
@ManasComp

Copy link
Copy Markdown

Hi, I’m continuing to extend this repository as part of my thesis. Could you please let me know whether this will be merged, or if it is expected to be closed?

Thank you.

cc: @jirigav

@DavidRajnoha

Copy link
Copy Markdown
Author

In which direction are you extending the repository? I have other work extending this repository in my fork that I did as part of my master thesis that I did not get to merge due to low priority of it. I was planning to revisit it in September / October as I will officially start my PhD.

It might be beneficial to check it out, I can provide you a quick overview of the work I did if interested. One of the major updates is the possibility to run the emulations manager within the same cluster as the emulations do.

The options are then IMO merge this and also the other work I have done as soon as possible / not include my changes at all. My (of course opinionated :)) preference is to get my changes in, but I would need to know more context from your side to get the full picture.

@jirigav

jirigav commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Hi, as @DavidRajnoha said, this PR had a very low priority (generally WW2 had a bigger priority than JM), but it would be nice to have it merged. I think that we could merge also the other changes from David, but that can be a separate PR.

@DavidRajnoha: There were some changes in the repo since this PR was opened, so please merge them first into this branch. Then I would test it - if you can provide me with some instructions on how to run JM that would be great - and then we can merge it.

Doing it in september/october is fine for me, but I don't know if @ManasComp needs these changes sooner or not.

@ManasComp

Copy link
Copy Markdown

Hello, and thank you both for the context.

I was not aware of David’s additional work when I started extending the repository, so there may already be some overlap between our implementations. In my fork, I have worked on broader Kubernetes support, additional JoinMarket functionality, container orchestration, refactoring, diagnostics, and logging:

https://github.com/OndrejMan/coinjoin-emulator

The emulator is being used as part of a larger pipeline for my thesis:

https://github.com/OndrejMan/coinjoin-pipeline

The main goal of the thesis is to automate the emulation and analysis of Bitcoin transactions and compare the results produced by coinjoin-analysis and BlockSci. I have also been experimenting with running the complete workflow on MetaCentrum using Kubernetes and PBS.

So far, my priority has been to build a working proof of concept and verify the overall architecture. The current implementation should therefore not yet be considered production-ready. I am now planning to review and redesign parts of it more systematically.

I do not currently need PR #6 or David’s other changes to be merged immediately, so September or October would not block my current work. However, it would be very useful to see David’s branch earlier, before I begin the redesign, so that I do not unnecessarily reimplement the same functionality.

David, could you please share the relevant branch or fork and, if possible, provide the brief overview you mentioned? I can then compare the two approaches and identify which parts should be reused, adapted, or implemented differently. Where appropriate, I would of course preserve the original commit authorship or add co-authorship when incorporating changes.

I believe we are meeting on 28 July, so we can also discuss the architecture and possible integration strategy in more detail then.

@DavidRajnoha

Copy link
Copy Markdown
Author

https://github.com/DavidRajnoha/coinjoin-simulator/tree/kubernetes-openshift-with-shadowsocks
This is the most recent branch I have on my fork. Bellow is the description of the changes.

Shared improvements (usable by any coinjoin implementation)

  1. Remote deployment and orchestration on Kubernetes

The simulator originally ran locally using Docker. This group of changes adds the ability to deploy and
manage simulations on remote Kubernetes and OpenShift clusters.

What was added:

  • Kubernetes and OpenShift drivers (manager/driver/kubernetes.py, manager/driver/openshift.py) — new
    container drivers that create and manage simulation pods on a cluster instead of local Docker
    containers.
  • In-cluster mode (manager.py, --in-cluster flag) — allows the manager itself to run as a pod inside
    the cluster, using Kubernetes service accounts for authentication and service DNS for pod-to-pod
    communication. This is the production deployment mode.
  • KubernetesLocalProxy (manager/kubernetes_local_proxy.py) — a local-to-cluster bridge that lets you
    run simulations on a remote cluster from your laptop. It communicates with an orchestrator pod deployed
    in the cluster via kubectl, handling command forwarding, file transfers, and connection management.
  • Remote management CLIs (manager/manager_remote.py, manager/manager_remote_batch.py) — command-line
    tools for deploying the manager, starting simulations, checking status, and downloading results from a
    remote cluster. The batch variant runs multiple simulations sequentially with cleanup between them.
  • Scenario runner (scenario_runner.py) — processes a folder of scenario definition files, running each
    simulation in order with progress tracking, error handling, and cleanup. Supports skipping and stopping
    mid-run via signals.
  • RBAC and deployment manifests (containers/emulator-manager/) — Kubernetes YAML files (Deployment,
    Role, RoleBinding, ServiceAccount) that give the manager pod the permissions it needs to create and
    manage simulation pods in the cluster.
  • Containerization (Dockerfile, .dockerignore, requirements.txt) — packages the manager as a container
    image for cluster deployment.
  • Shadowsocks proxy (shadowsocks/) — configuration for a SOCKS5 proxy to route traffic through
    restricted network environments (e.g., university or corporate clusters that block outbound
    connections).
  1. Observability and resilience

These changes make long-running remote simulations more robust and easier to debug when something goes
wrong.

What was added:

  • Graceful shutdown (803ac6e) — SIGTERM and SIGINT signal handlers that clean up all simulation pods
    and services before exiting, preventing orphaned resources in the cluster when a simulation is
    interrupted.
  • Resource monitoring — the manager tracks its own memory usage via /proc/self/status and logs it
    periodically, helping identify out-of-memory issues on constrained cluster nodes.
  • Health checks (020998f) — the Kubernetes proxy monitors pod health and reports failures, rather than
    silently hanging when a pod crashes.
  • Increased resource limits — Kubernetes CPU and memory requests/limits are set to 1.5x the baseline to
    reduce pod evictions under load.
  • Remote log downloads (abdbf99, d311434) — improved retrieval of simulation logs from cluster pods,
    with a -n flag to download logs from the last N runs. Handles large log files by chunked transfer with
    retries.
  • Real-time log visibility — JoinMarket client logs now use tee instead of plain file redirection, so
    logs appear both in the pod's stdout (visible via kubectl logs) and in log files simultaneously.

JoinMarket-specific improvements

  1. JoinMarket engine scalability

The JoinMarket engine orchestrates many simulated JoinMarket clients (makers and takers). These changes
address bottlenecks and add features needed to run realistic large-scale simulations (100+ clients).

What was added:

  • Async RPC calls (82aa458) — client communication switched from synchronous requests to async httpx.
    Previously, wallet unlock calls (~30 seconds each) blocked serially — with 100+ clients, this meant
    waiting 50+ minutes just for unlocks. Async calls run them concurrently.
  • RPC overload prevention (4219b70) — when many wallets start simultaneously, they flood the Bitcoin
    node with RPC requests. The engine now batches wallet startups by type (fidelity bond wallets first,
    then regular wallets) and staggers them with delays. The Bitcoin node config was also tuned
    (rpcthreads: 16, rpcworkqueue: 256) to handle higher concurrent load.
  • Fidelity bonds (42c4a38) — support for JoinMarket's fidelity bond mechanism, where makers lock
    bitcoin in timelocked addresses to prove commitment. The engine can create bonds with configurable
    amounts and locktimes, fund them through the distributor, and scale bond UTXOs per wallet.
  • Obwatcher client (096487d) — integration with JoinMarket's orderbook watcher, which provides a web UI
    showing the current state of the orderbook (available makers, their fees, bond values). Useful for
    monitoring simulation state.
  • Client refactor — the monolithic joinmarket_client.py was split into joinmarket_client_base.py
    (low-level RPC communication, wallet operations, error handling) and joinmarket_clients.py (high-level
    client management, startup sequencing, health checks). This improved reliability and made the code
    easier to extend.
  • Increased distributor capacity — the distributor (the component that funds all simulated wallets) now
    creates 200 UTXOs instead of 20, and the blockchain is initialized with 1001 blocks instead of 201,
    both necessary for simulations with many clients and fidelity bonds.
  1. JoinMarket scenario generation

Scenarios define the parameters of a simulation: how many makers and takers, their wallet sizes, fee
structures, bond configurations, and timing. This group adds tooling to generate and manage these
scenario definitions.

What was added:

  • Scenario generator (bf34809, 64cf384) — scripts that produce scenario JSON files from parameterized
    templates. Supports configuring the number of makers/takers, fee distributions (including
    quantile-based for realistic spread), wallet funding amounts, fidelity bond parameters, and taker
    delays.
  • Validation and balancing (64cf384) — the generator validates that total funding doesn't exceed
    available bitcoin, that fee ranges are sensible, and that bond locktimes are in the future.
  • Experiment library (scenarios/joinmarket/generator_commands/) — a collection of pre-built experiment
    scripts covering specific research questions:
    • experiments_2_maker_count_increase.sh / experiments_3_* — how does increasing the number of makers
      affect coinjoin behavior?
    • final_2_utxos.sh — effect of UTXO count per wallet
    • final_3_fees.sh — effect of fee structure variation
    • final_4_injected_takers.sh — effect of adding additional takers to the mix
    • production_bonds_*.sh — fidelity bond configurations mimicking real-world parameters
    • batch_test.sh — large batch runs for statistical significance

@ManasComp

Copy link
Copy Markdown

Thank you very much for the comprehensive overview and for sharing the branch.

There is clearly some overlap between our implementations, particularly in the Kubernetes-related functionality. I also noticed that you have made several changes to coinjoin-analysis; however, our work in that repository appears to have followed substantially different directions, so those changes may be largely complementary.

Given the scope of the changes in your branch, I plan to use it as the new baseline and gradually reapply and adapt my changes on top of it. This should be considerably more practical than attempting to merge the two implementations directly.

Since you will soon be starting your PhD and may continue working on these projects, it would be useful for us to discuss any substantial planned changes to coinjoin-emulator, coinjoin-mappings, coinjoin-analysis, or BlockSci. I am currently actively developing these repositories, and my ongoing work is available in my public branches: https://github.com/orgs/OndrejMan/repositories. I will likewise keep you informed about changes on my side that could overlap with your work. Aligning our plans in advance should help us avoid further duplication and incompatible implementations.

I would also like to ask our supervisors to let us know if they are aware of any other relevant forks, branches, ongoing work, or unpublished changes that may eventually need to be integrated. Having this information early would make it easier to coordinate the development and avoid similar duplication in the future.

Thank you all.

@jirigav @petrs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants