This repository has been archived by the owner on May 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
38e271d
commit 8567431
Showing
4 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.git/ | ||
env/ | ||
rocker/ | ||
joinmarket.cfg | ||
wallets/ | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# | ||
# Quick and easy joinmarket | ||
# | ||
# docker build -t "bwstitt/joinmarket:latest" . | ||
# | ||
# Copying of the code is delayed as long as possible so that rebuilding the container while developing is faster | ||
# This also means some of the install steps aren't in the most obvious order and the virtualenv is outside the code | ||
# | ||
|
||
FROM bwstitt/library-debian:jessie | ||
|
||
# Install packages for joinmarket | ||
RUN docker-apt-install \ | ||
gcc \ | ||
libsodium13 \ | ||
python-dev \ | ||
virtualenv | ||
|
||
# i needed these when compiling myself, but new versions of pip with wheels save us | ||
#libatlas-dev \ | ||
#libblas-dev \ | ||
#libfreetype6-dev \ | ||
#libpng12-dev \ | ||
#libsodium-dev \ | ||
#pkg-config \ | ||
#python-dev \ | ||
|
||
# create a user | ||
RUN useradd -ms /bin/bash joinmarket | ||
|
||
# install deps that don't depend on the code as the user | ||
USER joinmarket | ||
ENV HOME=/home/joinmarket | ||
WORKDIR /home/joinmarket | ||
# todo: will python3 work? | ||
RUN virtualenv -p python2 ~/pyenv \ | ||
&& . ~/pyenv/bin/activate \ | ||
&& pip install -U setuptools pip \ | ||
&& pip install matplotlib numpy | ||
# todo: do something to calculate font cache with matplotlib | ||
# /home/joinmarket/pyenv/local/lib/python2.7/site-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment. | ||
|
||
# install the code | ||
COPY . /home/joinmarket/src/joinmarket | ||
WORKDIR /home/joinmarket/src/joinmarket | ||
COPY docker/entrypoint.py /entrypoint.py | ||
# todo: i wish copy would keep the user... | ||
USER root | ||
RUN chmod 500 /entrypoint.py \ | ||
&& chown -R joinmarket:joinmarket \ | ||
/entrypoint.py \ | ||
/home/joinmarket/src | ||
USER joinmarket | ||
|
||
# install deps from the code as the user | ||
RUN . ~/pyenv/bin/activate \ | ||
&& pip install -r requirements.txt | ||
|
||
# setup data volumes for logs and wallets | ||
# todo: handle the blacklist and commitments | ||
VOLUME ["/home/joinmarket/src/joinmarket/logs", "/home/joinmarket/src/joinmarket/wallets"] | ||
|
||
ENTRYPOINT /entrypoint.py | ||
CMD ob_watcher |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
todo: | ||
- explain how to setup Tor | ||
- explain how to setup bitcoind | ||
- explain how to setup the config (and figure out how to keep sensitive things out of git) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
#!/home/joinmarket/pyenv/bin/python | ||
"""Entrypoints for Docker containers to run joinmarket. | ||
todo: wait_for_file should probably be a decorator | ||
""" | ||
import argparse | ||
import logging | ||
import os | ||
import os.path | ||
import subprocess | ||
import sys | ||
import time | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
# | ||
# Helpers | ||
# | ||
|
||
DEBUG_LOG_FORMAT = ( | ||
'-' * 80 + '\n' + | ||
'%(asctime)s %(levelname)s in %(name)s @ %(threadName)s:\n' + | ||
'%(pathname)s:%(lineno)d\n' + | ||
'%(message)s\n' + | ||
'-' * 80 | ||
) | ||
DEFAULT_LOG_FORMAT = '%(asctime)s %(levelname)s: %(threadName)s: %(name)s: %(message)s' # noqa | ||
|
||
|
||
def run(*args): | ||
"""Run a python command inside the joinmarket virtualenv. | ||
Raises subprocess.CalledProcessError if the command fails. | ||
""" | ||
if not args: | ||
raise ValueError("run needs at least one arg") | ||
|
||
command_list = [sys.executable] + map(str, args) | ||
|
||
log.info("Running %s...", command_list[1]) | ||
log.debug("Full command: %s", command_list) | ||
return subprocess.check_call(command_list, env=os.environ) | ||
|
||
|
||
def wait_for_file(filename, sleep=10): | ||
"""Sleep until a given file exists.""" | ||
if os.path.exists(filename): | ||
return | ||
|
||
log.info("'%s' does not exist. Check the README", filename) | ||
|
||
while not os.path.exists(filename): | ||
time.sleep(sleep) | ||
|
||
log.info("Found '%s'", filename) | ||
return | ||
|
||
|
||
# | ||
# Commands | ||
# | ||
|
||
def get_parser(): | ||
"""Create an argument parser that routes to the command functions.""" | ||
# create the top-level parser | ||
parser = argparse.ArgumentParser() | ||
# todo: configurable log level | ||
subparsers = parser.add_subparsers() | ||
|
||
# create the parser for the "maker" command | ||
parser_maker = subparsers.add_parser('maker') | ||
parser_maker.set_defaults(func=maker) | ||
|
||
# create the parser for the "ob_watcher" command | ||
parser_ob_watcher = subparsers.add_parser('ob_watcher') | ||
parser_ob_watcher.set_defaults(func=ob_watcher) | ||
|
||
# create the parser for the "sendpayment" command | ||
parser_sendpayment = subparsers.add_parser('sendpayment') | ||
parser_sendpayment.set_defaults(func=sendpayment) | ||
|
||
# create the parser for the "taker" command | ||
parser_tumbler = subparsers.add_parser('tumbler') | ||
parser_tumbler.set_defaults(func=tumbler) | ||
|
||
# create the parser for the "wallet_tool" command | ||
parser_wallet_tool = subparsers.add_parser('wallet_tool') | ||
parser_wallet_tool.set_defaults(func=wallet_tool) | ||
|
||
return parser | ||
|
||
|
||
def maker(args): | ||
"""Earn Bitcoins and privacy.""" | ||
wallet_filename = 'wallets/wallet.json' | ||
|
||
wait_for_file(wallet_filename) | ||
|
||
# todo: wait for bitcoind to respond | ||
|
||
run('yg-pe.py', wallet_filename, *args) | ||
|
||
|
||
def ob_watcher(args): | ||
"""Watch the orderbook.""" | ||
# todo: wait for bitcoind to respond | ||
# todo: although, why does the orderbook need bitcoind? | ||
|
||
log.debug("Starting ob-watcher...") | ||
run('ob-watcher.py', *args) | ||
|
||
|
||
def sendpayment(args): | ||
""""Send Bitcoins with privacy. | ||
todo: make sure we only sendpayment with coins that have already been | ||
joined at least once. | ||
""" | ||
wallet_filename = 'wallets/wallet.json' | ||
|
||
wait_for_file(wallet_filename) | ||
|
||
# todo: wait for bitcoind to respond | ||
|
||
run('sendpayment.py', *args) | ||
|
||
|
||
def tumbler(args): | ||
""""Send Bitcoins with layers of privacy.""" | ||
wallet_filename = 'wallets/wallet.json' | ||
|
||
wait_for_file(wallet_filename) | ||
|
||
# todo: wait for bitcoind to respond | ||
|
||
run('tumbler.py', *args) | ||
|
||
|
||
def wallet_tool(args): | ||
"""Inspect and manage your Bitcoin wallet.""" | ||
run('wallet-tool.py', *args) | ||
|
||
|
||
def main(): | ||
"""Manage joinmarket.""" | ||
parser = get_parser() | ||
args, passthrough_args = parser.parse_known_args() | ||
|
||
log_level = logging.DEBUG # todo: get log_level from args | ||
|
||
if log_level == logging.DEBUG: | ||
log_format = DEBUG_LOG_FORMAT | ||
else: | ||
log_format = DEFAULT_LOG_FORMAT | ||
|
||
logging.basicConfig( | ||
format=log_format, | ||
level=log_level, | ||
stream=sys.stdout, | ||
) | ||
log.debug("Hello!") | ||
|
||
args.func(passthrough_args) | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main()) |