Skip to content

Commit

Permalink
Merge pull request #1542 from CounterpartyXCP/develop
Browse files Browse the repository at this point in the history
v10.0.0-beta.1
  • Loading branch information
adamkrellenstein authored Mar 20, 2024
2 parents fb958ea + 8fa5d8d commit 6f5e4e4
Show file tree
Hide file tree
Showing 26 changed files with 557 additions and 388 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/build_docker_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Build Docker Image

on:
push:
branches: "**"

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Docker
run: |
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
- name: Build image
run: |
docker build -t counterparty .
- name: Test image
run: |
docker run --rm counterparty counterparty-server -h
28 changes: 28 additions & 0 deletions .github/workflows/publish_docker_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish Docker Image

on:
release:
types: [published]

env:
DOCKER_REPO: counterparty/counterparty
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Docker
run: |
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
- name: Build, tag, login and push image
run: |
export VERSION=v$(cat counterparty-lib/counterpartylib/lib/config.py | grep '__version__ =' | awk -F '"' '{print $2}')
docker build -t $DOCKER_REPO:$VERSION .
docker tag $DOCKER_REPO:$VERSION $DOCKER_REPO:latest
docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"
docker push $DOCKER_REPO:$VERSION
docker push $DOCKER_REPO:latest
40 changes: 40 additions & 0 deletions .github/workflows/test_book.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Testnet Test Book

on:
push:
branches: "**"

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y libgirepository1.0-dev libleveldb-dev
python -m pip install --upgrade pip
pip install pylint maturin pytest
cd counterparty-rs && pip install -e . && cd ..
cd counterparty-lib && pip install -e . && cd ..
cd counterparty-cli && pip install -e . && cd ..
- name: Bootstrap testnet database
run: |
counterparty-server --testnet bootstrap --no-confirm
- name: Run tests
run: |
cd counterparty-lib
pytest counterpartylib/test/book_test.py --testbook -s
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ RUN pip3 install .
# install counterparty-cli
WORKDIR /counterparty-cli
RUN pip3 install .

ENTRYPOINT [ "counterparty-server", "start" ]
CMD [ "-h" ]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Then wait for your node to catch up with the network. Note: this process current

# Manual Installation

Counterparty Core can be installed on most platforms but, for now, manual installation is being tested and is only officially supported on Ubuntu 22.04 and MacOS.

Dependencies:

- Bitcoin Core
Expand Down
3 changes: 2 additions & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Codebase
- [ ] Update `VERSION_` variables in `lib/config.py`
- [ ] Update `protocol_changes.json` (as necessary)
- [ ] Update Counterparty packages version in `requirement.txt` files
- [ ] Update Counterparty package versions in the `requirements.txt` files
- [ ] Review all open pull requests
- [ ] Write release notes
- [ ] Create pull request against `master`
Expand All @@ -12,6 +12,7 @@
- [ ] Upload (signed) package to PyPi
* `sudo python3 setup.py sdist build`
* `sudo python3 setup.py sdist upload -r pypi`
- [ ] Publish bootstrap files
- [ ] Publish Docker images
- [ ] Update documentation

Expand Down
2 changes: 1 addition & 1 deletion counterparty-cli/counterpartycli/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
[('--wallet-name',), {'default': 'bitcoincore', 'help': 'the wallet name to connect to'}],
[('--wallet-connect',), {'default': 'localhost', 'help': 'the hostname or IP of the wallet server'}],
[('--wallet-port',), {'type': int, 'help': 'the wallet port to connect to'}],
[('--wallet-user',), {'default': 'bitcoinrpc', 'help': 'the username used to communicate with wallet'}],
[('--wallet-user',), {'default': 'rpc', 'help': 'the username used to communicate with wallet'}],
[('--wallet-password',), {'help': 'the password used to communicate with wallet'}],
[('--wallet-ssl',), {'action': 'store_true', 'default': False, 'help': 'use SSL to connect to wallet (default: false)'}],
[('--wallet-ssl-verify',), {'action': 'store_true', 'default': False, 'help': 'verify SSL certificate of wallet; disallow use of self‐signed certificates (default: false)'}],
Expand Down
2 changes: 1 addition & 1 deletion counterparty-cli/counterpartycli/clientapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
raise ConfigurationError("Please specific a valid port number wallet-port configuration parameter")

# BTC Wallet user
config.WALLET_USER = wallet_user or 'bitcoinrpc'
config.WALLET_USER = wallet_user or 'rpc'

# BTC Wallet password
if wallet_password:
Expand Down
119 changes: 82 additions & 37 deletions counterparty-cli/counterpartycli/server.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#! /usr/bin/env python3

import os
import sys
import argparse
import logging

from urllib.parse import quote_plus as urlencode

from termcolor import cprint

from counterpartylib.lib import log
from counterpartylib import server
from counterpartylib.lib import config
from counterpartycli.util import add_config_arguments, bootstrap
from counterpartycli.util import add_config_arguments, read_config_file
from counterpartycli.setup import generate_config_files
from counterpartycli import APP_VERSION

Expand All @@ -31,8 +30,8 @@
[('--backend-name',), {'default': 'addrindex', 'help': 'the backend name to connect to'}],
[('--backend-connect',), {'default': 'localhost', 'help': 'the hostname or IP of the backend server'}],
[('--backend-port',), {'type': int, 'help': 'the backend port to connect to'}],
[('--backend-user',), {'default': 'bitcoinrpc', 'help': 'the username used to communicate with backend'}],
[('--backend-password',), {'help': 'the password used to communicate with backend'}],
[('--backend-user',), {'default': 'rpc', 'help': 'the username used to communicate with backend'}],
[('--backend-password',), {'default': 'rpc', 'help': 'the password used to communicate with backend'}],
[('--backend-ssl',), {'action': 'store_true', 'default': False, 'help': 'use SSL to connect to backend (default: false)'}],
[('--backend-ssl-no-verify',), {'action': 'store_true', 'default': False, 'help': 'verify SSL certificate of backend; disallow use of self‐signed certificates (default: true)'}],
[('--backend-poll-interval',), {'type': float, 'default': 0.5, 'help': 'poll interval, in seconds (default: 0.5)'}],
Expand All @@ -45,12 +44,13 @@
[('--rpc-host',), {'default': 'localhost', 'help': 'the IP of the interface to bind to for providing JSON-RPC API access (0.0.0.0 for all interfaces)'}],
[('--rpc-port',), {'type': int, 'help': f'port on which to provide the {config.APP_NAME} JSON-RPC API'}],
[('--rpc-user',), {'default': 'rpc', 'help': f'required username to use the {config.APP_NAME} JSON-RPC API (via HTTP basic auth)'}],
[('--rpc-password',), {'help':f'required password (for rpc-user) to use the {config.APP_NAME} JSON-RPC API (via HTTP basic auth)'}],
[('--rpc-password',), {'default': 'rpc', 'help':f'required password (for rpc-user) to use the {config.APP_NAME} JSON-RPC API (via HTTP basic auth)'}],
[('--rpc-no-allow-cors',), {'action': 'store_true', 'default': False, 'help': 'allow ajax cross domain request'}],
[('--rpc-batch-size',), {'type': int, 'default': config.DEFAULT_RPC_BATCH_SIZE, 'help': f'number of RPC queries by batch (default: {config.DEFAULT_RPC_BATCH_SIZE})'}],
[('--requests-timeout',), {'type': int, 'default': config.DEFAULT_REQUESTS_TIMEOUT, 'help': 'timeout value (in seconds) used for all HTTP requests (default: 5)'}],

[('--force',), {'action': 'store_true', 'default': False, 'help': 'skip backend check, version check, process lock (NOT FOR USE ON PRODUCTION SYSTEMS)'}],
[('--no-confirm',), {'action': 'store_true', 'default': False, 'help': 'don\'t ask for confirmation'}],
[('--database-file',), {'default': None, 'help': 'the path to the SQLite3 database file'}],
[('--log-file',), {'nargs': '?', 'const': None, 'default': False, 'help': 'log to the specified file'}],
[('--api-log-file',), {'nargs': '?', 'const': None, 'default': False, 'help': 'log API requests to the specified file'}],
Expand All @@ -60,51 +60,100 @@
[('--utxo-locks-max-age',), {'type': int, 'default': config.DEFAULT_UTXO_LOCKS_MAX_AGE, 'help': 'how long to keep a lock on a UTXO being tracked'}],
]

COMMANDS_WITH_DB = ['reparse', 'rollback', 'start', 'vacuum', 'check-db']
def welcome_message(action, server_configfile):
cprint(f'Running v{config.__version__} of {config.FULL_APP_NAME}.', 'magenta')

# print some info
cprint(f"Configuration file: {server_configfile}", 'light_grey')
cprint(f"Counterparty database: {config.DATABASE}", 'light_grey')
if config.LOG:
cprint(f'Writing log to file: `{config.LOG}`', 'light_grey')
else:
cprint('Warning: log disabled', 'yellow')
if config.API_LOG:
cprint(f'Writing API accesses log to file: `{config.API_LOG}`', 'light_grey')
else:
cprint('Warning: API log disabled', 'yellow')

if config.VERBOSE:
if config.TESTNET:
cprint('NETWORK: Testnet', 'light_grey')
elif config.REGTEST:
cprint('NETWORK: Regtest', 'light_grey')
else:
cprint('NETWORK: Mainnet', 'light_grey')

pass_str = f":{urlencode(config.BACKEND_PASSWORD)}@"
cleaned_backend_url = config.BACKEND_URL.replace(pass_str, ":*****@")
cprint(f'BACKEND_URL: {cleaned_backend_url}', 'light_grey')
cprint(f'INDEXD_URL: {config.INDEXD_URL}', 'light_grey')
pass_str = f":{urlencode(config.RPC_PASSWORD)}@"
cleaned_rpc_url = config.RPC.replace(pass_str, ":*****@")
cprint(f'RPC: {cleaned_rpc_url}', 'light_grey')

cprint(f"{'-' * 30} {action} {'-' * 30}\n", 'green')


class VersionError(Exception):
pass
def main():
cprint(f'Running v{config.__version__} of {config.FULL_APP_NAME}.', 'magenta')

if os.name == 'nt':
from counterpartylib.lib import util_windows
#patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
util_windows.fix_win32_unicode()

# Post installation tasks
generate_config_files()
server_configfile = generate_config_files()

# Parse command-line arguments.
parser = argparse.ArgumentParser(prog=APP_NAME, description=f'Server for the {config.XCP_NAME} protocol', add_help=False)
parser = argparse.ArgumentParser(
prog=APP_NAME,
description=f'Server for the {config.XCP_NAME} protocol',
add_help=False,
exit_on_error=False
)
parser.add_argument('-h', '--help', dest='help', action='store_true', help='show this help message and exit')
parser.add_argument('-V', '--version', action='version', version=f"{APP_NAME} v{APP_VERSION}; counterparty-lib v{config.VERSION_STRING}")
parser.add_argument('--config-file', help='the path to the configuration file')

add_config_arguments(parser, CONFIG_ARGS, 'server.conf')
cmd_args = parser.parse_known_args()[0]
config_file_path = getattr(cmd_args, 'config_file', None)
configfile = read_config_file('server.conf', config_file_path)

add_config_arguments(parser, CONFIG_ARGS, configfile, add_default=True)

subparsers = parser.add_subparsers(dest='action', help='the action to be taken')

parser_server = subparsers.add_parser('start', help='run the server')
parser_server.add_argument('--config-file', help='the path to the configuration file')
parser_server.add_argument('--catch-up', choices=['normal', 'bootstrap'], default='normal', help='Catch up mode (default: normal)')
add_config_arguments(parser_server, CONFIG_ARGS, configfile)

parser_reparse = subparsers.add_parser('reparse', help='reparse all transactions in the database')
parser_reparse.add_argument('block_index', type=int, help='the index of the last known good block')
add_config_arguments(parser_reparse, CONFIG_ARGS, configfile)

parser_vacuum = subparsers.add_parser('vacuum', help='VACUUM the database (to improve performance)')
add_config_arguments(parser_vacuum, CONFIG_ARGS, configfile)

parser_rollback = subparsers.add_parser('rollback', help='rollback database')
parser_rollback.add_argument('block_index', type=int, help='the index of the last known good block')
add_config_arguments(parser_rollback, CONFIG_ARGS, configfile)

parser_kickstart = subparsers.add_parser('kickstart', help='rapidly build database by reading from Bitcoin Core blockchain')
parser_kickstart.add_argument('--bitcoind-dir', help='Bitcoin Core data directory')
parser_kickstart.add_argument('--max-queue-size', type=int, help='Size of the multiprocessing.Queue for parsing blocks')
parser_kickstart.add_argument('--debug-block', type=int, help='Rollback and run kickstart for a single block;')
add_config_arguments(parser_kickstart, CONFIG_ARGS, configfile)

subparsers.add_parser('bootstrap', help='bootstrap database with hosted snapshot')
parser_bootstrap = subparsers.add_parser('bootstrap', help='bootstrap database with hosted snapshot')
add_config_arguments(parser_bootstrap, CONFIG_ARGS, configfile)

subparsers.add_parser('check-db', help='do an integrity check on the database')
parser_checkdb = subparsers.add_parser('check-db', help='do an integrity check on the database')
add_config_arguments(parser_checkdb, CONFIG_ARGS, configfile)

subparsers.add_parser('show-config', help='Show counterparty-server configuration')
parser_show_config = subparsers.add_parser('show-params', help='Show counterparty-server configuration')
add_config_arguments(parser_show_config, CONFIG_ARGS, configfile)

args = parser.parse_args()

Expand All @@ -115,11 +164,9 @@ def main():

# Configuration
init_args = dict(database_file=args.database_file,
log_file=args.log_file, api_log_file=args.api_log_file, no_log_files=args.no_log_files,
testnet=args.testnet, testcoin=args.testcoin, regtest=args.regtest,
customnet=args.customnet,
api_limit_rows=args.api_limit_rows,
backend_name=args.backend_name,
backend_connect=args.backend_connect,
backend_port=args.backend_port,
backend_user=args.backend_user,
Expand All @@ -133,16 +180,16 @@ def main():
requests_timeout=args.requests_timeout,
rpc_batch_size=args.rpc_batch_size,
check_asset_conservation=not args.no_check_asset_conservation,
force=args.force, verbose=args.verbose, quiet=args.quiet,
force=args.force,
p2sh_dust_return_pubkey=args.p2sh_dust_return_pubkey,
utxo_locks_max_addresses=args.utxo_locks_max_addresses,
utxo_locks_max_age=args.utxo_locks_max_age)

if args.action in COMMANDS_WITH_DB:
# server.initialise_config() is called in server.initialise()
db = server.initialise(**init_args)
else:
server.initialise_config(**init_args)
server.initialise_log_config(
verbose=args.verbose, quiet=args.quiet,
log_file=args.log_file, api_log_file=args.api_log_file, no_log_files=args.no_log_files,
testnet=args.testnet, testcoin=args.testcoin, regtest=args.regtest,
)

# set up logging
log.set_up(
Expand All @@ -151,25 +198,23 @@ def main():
log_file=config.LOG,
log_in_console=args.action == 'start'
)

server.initialise_config(**init_args)

logger.info(f'Running v{APP_VERSION} of {APP_NAME}.')

# print some info
if config.LOG:
cprint(f'Writing log to file: `{config.LOG}`', 'light_grey')
if args.action == 'start' and config.API_LOG:
cprint(f'Writing API accesses log to file: `{config.API_LOG}`', 'light_grey')
cprint(f"{'-' * 30} {args.action} {'-' * 30}\n", 'green')
welcome_message(args.action, server_configfile)

# Bootstrapping
if args.action == 'bootstrap':
bootstrap(testnet=args.testnet)
server.bootstrap(no_confirm=args.no_confirm)

# PARSING
elif args.action == 'reparse':
server.reparse(db, block_index=args.block_index)
server.reparse(block_index=args.block_index)

elif args.action == 'rollback':
server.rollback(db, block_index=args.block_index)
server.rollback(block_index=args.block_index)

elif args.action == 'kickstart':
server.kickstart(
Expand All @@ -179,16 +224,16 @@ def main():
debug_block=args.debug_block)

elif args.action == 'start':
server.start_all(db)
server.start_all(catch_up=args.catch_up)

elif args.action == 'show-config':
server.show_config()
elif args.action == 'show-params':
server.show_params()

elif args.action == 'vacuum':
server.vacuum(db)
server.vacuum()

elif args.action == 'check-db':
server.check_database(db)
server.check_database()
else:
parser.print_help()

Expand Down
1 change: 1 addition & 0 deletions counterparty-cli/counterpartycli/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def generate_config_files():
if not os.path.exists(client_configfile):
client_known_config = server_to_client_config(server_known_config)
generate_config_file(client_configfile, CLIENT_CONFIG_ARGS, client_known_config)
return server_configfile

def zip_folder(folder_path, zip_path):
zip_file = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
Expand Down
Loading

0 comments on commit 6f5e4e4

Please sign in to comment.