Merge pull request #102 from sr-gi/renaming

Renaming
This commit is contained in:
Sergi Delgado Segura
2020-03-17 17:04:37 +01:00
committed by GitHub
56 changed files with 374 additions and 373 deletions

View File

@@ -21,46 +21,46 @@ jobs:
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "pisa/requirements.txt" }}-{{ checksum "pisa/requirements-dev.txt" }}-{{ checksum "apps/cli/requirements-dev.txt" }}-{{ checksum "test/pisa/e2e/bitcoind_snap.sh" }}
- v1-dependencies-{{ checksum "teos/requirements.txt" }}-{{ checksum "teos/requirements-dev.txt" }}-{{ checksum "apps/cli/requirements-dev.txt" }}-{{ checksum "test/teos/e2e/bitcoind_snap.sh" }}
- run:
name: Install dependencies
command: |
sudo snap install `cat test/pisa/e2e/bitcoind_snap.sh`
sudo snap install `cat test/teos/e2e/bitcoind_snap.sh`
pyenv local 3.7.0
python3 -m venv venv
. venv/bin/activate
sudo pip install --upgrade pip
pip install -r pisa/requirements.txt
pip install -r pisa/requirements-dev.txt
pip install -r teos/requirements.txt
pip install -r teos/requirements-dev.txt
pip install -r apps/cli/requirements-dev.txt
- save_cache:
paths:
- ./venv
- /snap
key: v1-dependencies-{{ checksum "pisa/requirements.txt" }}-{{ checksum "pisa/requirements-dev.txt" }}-{{ checksum "apps/cli/requirements-dev.txt" }}-{{ checksum "test/pisa/e2e/bitcoind_snap.sh" }}
key: v1-dependencies-{{ checksum "teos/requirements.txt" }}-{{ checksum "teos/requirements-dev.txt" }}-{{ checksum "apps/cli/requirements-dev.txt" }}-{{ checksum "test/teos/e2e/bitcoind_snap.sh" }}
# Run bitcoind for E2E testing (running it early so it has time to bootstrap)
- run:
name: Run bitcoind
command: |
mkdir -p /home/circleci/snap/bitcoin-core/common/.bitcoin/
cp test/pisa/e2e/bitcoin.conf /home/circleci/snap/bitcoin-core/common/.bitcoin/
cp test/teos/e2e/bitcoin.conf /home/circleci/snap/bitcoin-core/common/.bitcoin/
/snap/bin/bitcoin-core.daemon
# Run unit tests
- run:
name: Creates config files
command: |
cp pisa/sample_conf.py pisa/conf.py
cp teos/sample_conf.py teos/conf.py
cp apps/cli/sample_conf.py apps/cli/conf.py
- run:
name: Run pisa unit tests
name: Run teos unit tests
command: |
. venv/bin/activate
pytest test/pisa/unit/
pytest test/teos/unit/
- run:
name: Run common unit tests
@@ -74,14 +74,14 @@ jobs:
. venv/bin/activate
pytest test/apps/cli/unit
# Setup pisa for E2E testing
# Setup teos for E2E testing
- run:
name: Setup pisa
name: Setup teos
command: |
. venv/bin/activate
cp test/pisa/e2e/pisa-conf.py pisa/conf.py
python3 -m apps.generate_key -d ~/.pisa_btc/
python3 -m apps.generate_key -n cli -d ~/.pisa_btc/
cp test/teos/e2e/teos-conf.py teos/conf.py
python3 -m apps.generate_key -d ~/.teos/
python3 -m apps.generate_key -n cli -d ~/.teos/
# Run E2E tests
@@ -89,7 +89,7 @@ jobs:
name: Run e2e tests
command: |
. venv/bin/activate
pytest test/pisa/e2e/
pytest test/teos/e2e/
# - store_artifacts:
# path: test-reports

View File

@@ -1,7 +1,7 @@
[run]
omit =
*__init__.py
pisa/pisad.py
pisa/logger.py
pisa/sample_conf.py
pisa/utils/auth_proxy.py
teos/teosd.py
teos/logger.py
teos/sample_conf.py
teos/utils/auth_proxy.py

3
.gitignore vendored
View File

@@ -17,4 +17,5 @@ test.py
.coverage
htmlcov
docs/
.pisa_btc
.teos
.teos_cli

View File

@@ -1,6 +1,6 @@
# Contributing to PISA
# Contributing to The Eye of Satoshi
The following is a set of guidelines for contributing to PISA.
The following is a set of guidelines for contributing to TEOS.
## Code Style Guidelines
We use [black](https://github.com/psf/black) as our base code formatter with a line length of 120 chars. Before submitting a PR make sure you have properly formatted your code by running:
@@ -36,7 +36,7 @@ An exception to the rule are nested `if` statements that placed right after each
for opt, arg in opts:
if opt in ["-s", "server"]:
if arg:
pisa_api_server = arg
teos_api_server = arg
```
```python

View File

@@ -1,10 +1,10 @@
# Dependencies
`wt_cli` has both system-wide and Python dependencies. This document walks you through how to satisfy them.
`teos_cli` has both system-wide and Python dependencies. This document walks you through how to satisfy them.
## System-wide dependencies
`wt_cli` has the following system-wide dependencies:
`teos_cli` has the following system-wide dependencies:
- `python3`
- `pip3`
@@ -27,7 +27,7 @@ It is also likely that, if `python3` is installed in our system, the `python` al
python3 --version
If `python3` is installed but the `python` alias is not set to it, we should either set it, or use `python3` to run `wt_cli`.
If `python3` is installed but the `python` alias is not set to it, we should either set it, or use `python3` to run `teos_cli`.
Regarding `pip`, we can check what version is installed in our system (if any) by running:
@@ -74,7 +74,7 @@ and for `pip3`:
## Python dependencies
`wt_cli` has the following dependencies (which can be satisfied by using `pip install -r requirements.txt`):
`teos_cli` has the following dependencies (which can be satisfied by using `pip install -r requirements.txt`):
- `cryptography`
- `requests`

View File

@@ -1,11 +1,11 @@
# Install
`wt_cli` has some dependencies that can be satisfied by following [DEPENDENCIES.md](DEPENDENCIES.md). If your system already satisfies the dependencies, you can skip that part.
`teos_cli` has some dependencies that can be satisfied by following [DEPENDENCIES.md](DEPENDENCIES.md). If your system already satisfies the dependencies, you can skip that part.
There are two ways of running `wt_cli`: adding the library to the `PYTHONPATH` env variable, or running it as a module.
There are two ways of running `teos_cli`: adding the library to the `PYTHONPATH` env variable, or running it as a module.
## Modifying `PYTHONPATH`
In order to run `wt_cli`, you should set your `PYTHONPATH` env variable to include the folder that contains the `apps` folder. You can do so by running:
In order to run `teos_cli`, you should set your `PYTHONPATH` env variable to include the folder that contains the `apps` folder. You can do so by running:
export PYTHONPATH=$PYTHONPATH:<absolute_path_to_apps>
@@ -17,17 +17,17 @@ You should also include the command in your `.bashrc` to avoid having to run it
echo 'export PYTHONPATH=$PYTHONPATH:<absolute_path_to_apps>' >> ~/.bashrc
Once the `PYTHONPATH` is set, you should be able to run `wt_cli` straightaway. Try it by running:
Once the `PYTHONPATH` is set, you should be able to run `teos_cli` straightaway. Try it by running:
cd <absolute_path_to_apps>/apps/cli
python wt_cli.py -h
python teos_cli.py -h
## Running `wt_cli` as a module
## Running `teos_cli` as a module
Python code can be also run as a module, to do so you need to use `python -m`. From `apps` **parent** directory run:
python -m apps.cli.wt_cli -h
python -m apps.cli.teos_cli -h
Notice that if you run `wt_cli` as a module, you'll need to replace all the calls from `python wt_cli.py <argument>` to `python -m apps.cli.wt_cli <argument>`
Notice that if you run `teos_cli` as a module, you'll need to replace all the calls from `python teos_cli.py <argument>` to `python -m apps.cli.teos_cli <argument>`
## Modify configuration parameters
If you'd like to modify some of the configuration defaults (such as the user directory, where the logs and appointment receipts will be stored) you can do so in the config file located at:

View File

@@ -1,6 +1,6 @@
# wt_cli
# teos_cli
`wt_cli` is a command line interface to interact with the Eye of Satoshi watchtower server, written in Python3.
`teos_cli` is a command line interface to interact with the Eye of Satoshi watchtower server, written in Python3.
## Dependencies
Refer to [DEPENDENCIES.md](DEPENDENCIES.md)
@@ -11,7 +11,7 @@ Refer to [INSTALL.md](INSTALL.md)
## Usage
python wt_cli.py [global options] command [command options] [arguments]
python teos_cli.py [global options] command [command options] [arguments]
#### Global options
@@ -59,7 +59,7 @@ The alpha release does not have authentication, payments nor rate limiting, ther
#### Usage
python wt_cli.py add_appointment [command options] <appointment>/<path_to_appointment_file>
python teos_cli.py add_appointment [command options] <appointment>/<path_to_appointment_file>
if `-f, --file` **is** specified, then the command expects a path to a json file instead of a json encoded string as parameter.
@@ -103,7 +103,7 @@ if `-f, --file` **is** specified, then the command expects a path to a json file
#### Usage
python wt_cli.py get_appointment <appointment_locator>
python teos_cli.py get_appointment <appointment_locator>
@@ -112,11 +112,11 @@ if `-f, --file` **is** specified, then the command expects a path to a json file
Shows the list of commands or help about how to run a specific command.
#### Usage
python wt_cli.py help
python teos_cli.py help
or
python wt_cli.py help command
python teos_cli.py help command
## Example
@@ -131,7 +131,7 @@ or
2. Send the appointment to the tower API. Which will then start monitoring for matching transactions.
```
python wt_cli.py add_appointment -f dummy_appointment_data.json
python teos_cli.py add_appointment -f dummy_appointment_data.json
```
This returns a appointment locator that can be used to get updates about this appointment from the tower.
@@ -139,20 +139,20 @@ or
3. Test that the tower is still watching the appointment by replacing the appointment locator received into the following command:
```
python wt_cli.py get_appointment <appointment_locator>
python teos_cli.py get_appointment <appointment_locator>
```
## the Eye of Satoshi's API
If you wish to read about the underlying API, and how to write your own tool to interact with it, refer to [tEOS-API.md](tEOS-API.md).
If you wish to read about the underlying API, and how to write your own tool to interact with it, refer to [tEOS-API.md](TEOS-API.md).
## Are you reckless? Try me on mainnet
Would you like to try me on `mainnet` instead of `testnet`? Add `-s https://mainnet.teos.pisa.watch` to your calls, for example:
```
python wt_cli.py -s https://teosmainnet.pisa.watch add_appointment -f dummy_appointment_data.json
python teos_cli.py -s https://teosmainnet.pisa.watch add_appointment -f dummy_appointment_data.json
```
You can also change the config file to avoid specifying the server every time:
`DEFAULT_PISA_API_SERVER = "https://teosmainnet.pisa.watch"`
`DEFAULT_TEOS_API_SERVER = "https://teosmainnet.pisa.watch"`

View File

@@ -6,14 +6,14 @@ LOG_PREFIX = "cli"
# Load config fields
conf_fields = {
"DEFAULT_PISA_API_SERVER": {"value": conf.DEFAULT_PISA_API_SERVER, "type": str},
"DEFAULT_PISA_API_PORT": {"value": conf.DEFAULT_PISA_API_PORT, "type": int},
"DEFAULT_TEOS_API_SERVER": {"value": conf.DEFAULT_TEOS_API_SERVER, "type": str},
"DEFAULT_TEOS_API_PORT": {"value": conf.DEFAULT_TEOS_API_PORT, "type": int},
"DATA_FOLDER": {"value": conf.DATA_FOLDER, "type": str},
"CLIENT_LOG_FILE": {"value": conf.CLIENT_LOG_FILE, "type": str, "path": True},
"APPOINTMENTS_FOLDER_NAME": {"value": conf.APPOINTMENTS_FOLDER_NAME, "type": str, "path": True},
# "CLI_PUBLIC_KEY": {"value": conf.CLI_PUBLIC_KEY, "type": str, "path": True},
# "CLI_PRIVATE_KEY": {"value": conf.CLI_PRIVATE_KEY, "type": str, "path": True},
# "PISA_PUBLIC_KEY": {"value": conf.PISA_PUBLIC_KEY, "type": str, "path": True},
# "TEOS_PUBLIC_KEY": {"value": conf.TEOS_PUBLIC_KEY, "type": str, "path": True},
}
# Expand user (~) if found and check fields are correct

View File

@@ -1,9 +1,9 @@
def help_add_appointment():
return (
"NAME:"
"\tpython wt_cli add_appointment - Registers a json formatted appointment to the tower."
"\tpython teos_cli add_appointment - Registers a json formatted appointment to the tower."
"\n\nUSAGE:"
"\tpython wt_cli add_appointment [command options] appointment/path_to_appointment_file"
"\tpython teos_cli add_appointment [command options] appointment/path_to_appointment_file"
"\n\nDESCRIPTION:"
"\n\n\tRegisters a json formatted appointment to the tower."
"\n\tif -f, --file *is* specified, then the command expects a path to a json file instead of a json encoded "
@@ -17,9 +17,9 @@ def help_add_appointment():
def help_get_appointment():
return (
"NAME:"
"\tpython wt_cli get_appointment - Gets json formatted data about an appointment from the tower."
"\tpython teos_cli get_appointment - Gets json formatted data about an appointment from the tower."
"\n\nUSAGE:"
"\tpython wt_cli get_appointment appointment_locator"
"\tpython teos_cli get_appointment appointment_locator"
"\n\nDESCRIPTION:"
"\n\n\tGets json formatted data about an appointment from the tower.\n"
)

View File

@@ -1,9 +1,9 @@
# PISA-WT-SERVER
DEFAULT_PISA_API_SERVER = "https://teos.pisa.watch"
DEFAULT_PISA_API_PORT = 443
# TEOS-SERVER
DEFAULT_TEOS_API_SERVER = "https://teos.pisa.watch"
DEFAULT_TEOS_API_PORT = 443
# WT-CLI
DATA_FOLDER = "~/.wt_cli/"
DATA_FOLDER = "~/.teos_cli/"
CLIENT_LOG_FILE = "cli.log"
APPOINTMENTS_FOLDER_NAME = "appointment_receipts"

View File

@@ -1,4 +1,4 @@
## tEOS-API
## TEOS-API
### Disclaimer: Everything in here is experimental and subject to change.

View File

@@ -24,26 +24,26 @@ from common.tools import check_sha256_hex_format, check_locator_format, compute_
logger = Logger(actor="Client", log_name_prefix=LOG_PREFIX)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
# FIXME: creating a simpler load_keys for the alpha. Client keys will not be necessary. PISA key is hardcoded.
# def load_keys(pisa_pk_path, cli_sk_path, cli_pk_path):
# FIXME: creating a simpler load_keys for the alpha. Client keys will not be necessary. TEOS key is hardcoded.
# def load_keys(teos_pk_path, cli_sk_path, cli_pk_path):
# """
# Loads all the keys required so sign, send, and verify the appointment.
#
# Args:
# pisa_pk_path (:obj:`str`): path to the PISA public key file.
# teos_pk_path (:obj:`str`): path to the TEOS public key file.
# cli_sk_path (:obj:`str`): path to the client private key file.
# cli_pk_path (:obj:`str`): path to the client public key file.
#
# Returns:
# :obj:`tuple` or ``None``: a three item tuple containing a pisa_pk object, cli_sk object and the cli_sk_der
# :obj:`tuple` or ``None``: a three item tuple containing a teos_pk object, cli_sk object and the cli_sk_der
# encoded key if all keys can be loaded. ``None`` otherwise.
# """
#
# pisa_pk_der = Cryptographer.load_key_file(pisa_pk_path)
# pisa_pk = Cryptographer.load_public_key_der(pisa_pk_der)
# teos_pk_der = Cryptographer.load_key_file(teos_pk_path)
# teos_pk = Cryptographer.load_public_key_der(teos_pk_der)
#
# if pisa_pk is None:
# logger.error("PISA's public key file not found. Please check your settings")
# if teos_pk is None:
# logger.error("TEOS's public key file not found. Please check your settings")
# return None
#
# cli_sk_der = Cryptographer.load_key_file(cli_sk_path)
@@ -59,14 +59,14 @@ common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_
# logger.error("Client's public key file not found. Please check your settings")
# return None
#
# return pisa_pk, cli_sk, cli_pk_der
# return teos_pk, cli_sk, cli_pk_der
def load_keys():
PISA_PUBLIC_KEY = "0230053e39c53b8bcb43354a4ed886b8082af1d1e8fc14956e60ad0592bfdfab51"
pisa_pk = PublicKey(binascii.unhexlify(PISA_PUBLIC_KEY))
TEOS_PUBLIC_KEY = "0230053e39c53b8bcb43354a4ed886b8082af1d1e8fc14956e60ad0592bfdfab51"
teos_pk = PublicKey(binascii.unhexlify(TEOS_PUBLIC_KEY))
return pisa_pk
return teos_pk
def add_appointment(args):
@@ -95,9 +95,9 @@ def add_appointment(args):
:obj:`bool`: True if the appointment is accepted by the tower and the receipt is properly stored, false if any
error occurs during the process.
"""
# FIXME: creating a simpler load_keys for the alpha. Client keys will not be necessary. PISA key is hardcoded.
# pisa_pk, cli_sk, cli_pk_der = load_keys(
# config.get("PISA_PUBLIC_KEY"), config.get("CLI_PRIVATE_KEY"), config.get("CLI_PUBLIC_KEY")
# FIXME: creating a simpler load_keys for the alpha. Client keys will not be necessary. TEOS key is hardcoded.
# teos_pk, cli_sk, cli_pk_der = load_keys(
# config.get("TEOS_PUBLIC_KEY"), config.get("CLI_PRIVATE_KEY"), config.get("CLI_PUBLIC_KEY")
# )
#
# try:
@@ -106,9 +106,9 @@ def add_appointment(args):
# except binascii.Error as e:
# logger.error("Could not successfully encode public key as hex", error=str(e))
# return False
pisa_pk = load_keys()
teos_pk = load_keys()
if pisa_pk is None:
if teos_pk is None:
return False
# Get appointment data from user.
@@ -163,7 +163,7 @@ def add_appointment(args):
return False
rpk = Cryptographer.recover_pk(appointment.serialize(), signature)
if not Cryptographer.verify_rpk(pisa_pk, rpk):
if not Cryptographer.verify_rpk(teos_pk, rpk):
logger.error("The returned appointment's signature is invalid")
return False
@@ -237,7 +237,7 @@ def post_appointment(data):
logger.info("Sending appointment to the Eye of Satoshi")
try:
add_appointment_endpoint = "{}:{}".format(pisa_api_server, pisa_api_port)
add_appointment_endpoint = "{}:{}".format(teos_api_server, teos_api_port)
return requests.post(url=add_appointment_endpoint, json=json.dumps(data), timeout=5)
except ConnectTimeout:
@@ -347,7 +347,7 @@ def get_appointment(locator):
logger.error("The provided locator is not valid", locator=locator)
return None
get_appointment_endpoint = "{}:{}/get_appointment".format(pisa_api_server, pisa_api_port)
get_appointment_endpoint = "{}:{}/get_appointment".format(teos_api_server, teos_api_port)
parameters = "?locator={}".format(locator)
try:
@@ -372,7 +372,7 @@ def get_appointment(locator):
def show_usage():
return (
"USAGE: "
"\n\tpython wt_cli.py [global options] command [command options] [arguments]"
"\n\tpython teos_cli.py [global options] command [command options] [arguments]"
"\n\nCOMMANDS:"
"\n\tadd_appointment \tRegisters a json formatted appointment with the tower."
"\n\tget_appointment \tGets json formatted data about an appointment from the tower."
@@ -381,14 +381,14 @@ def show_usage():
"\n\t-s, --server \tAPI server where to send the requests. Defaults to https://teos.pisa.watch (modifiable in "
"config.py)"
"\n\t-p, --port \tAPI port where to send the requests. Defaults to 443 (modifiable in conf.py)"
"\n\t-d, --debug \tshows debug information and stores it in wt_cli.log"
"\n\t-d, --debug \tshows debug information and stores it in teos_cli.log"
"\n\t-h --help \tshows this message."
)
if __name__ == "__main__":
pisa_api_server = config.get("DEFAULT_PISA_API_SERVER")
pisa_api_port = config.get("DEFAULT_PISA_API_PORT")
teos_api_server = config.get("DEFAULT_TEOS_API_SERVER")
teos_api_port = config.get("DEFAULT_TEOS_API_PORT")
commands = ["add_appointment", "get_appointment", "help"]
try:
@@ -397,11 +397,11 @@ if __name__ == "__main__":
for opt, arg in opts:
if opt in ["-s", "server"]:
if arg:
pisa_api_server = arg
teos_api_server = arg
if opt in ["-p", "--port"]:
if arg:
pisa_api_port = int(arg)
teos_api_port = int(arg)
if opt in ["-h", "--help"]:
sys.exit(show_usage())

View File

@@ -8,7 +8,7 @@ from cryptography.hazmat.primitives.asymmetric import ec
# Simple tool to generate an ECDSA private key using the secp256k1 curve and save private and public keys
# as 'pisa_sk.der' 'and pisa_pk.der', respectively.
# as 'teos_sk.der' 'and teos_pk.der', respectively.
def save_sk(sk, filename):
@@ -23,13 +23,13 @@ def save_sk(sk, filename):
def save_pk(pk, filename):
der = pk.public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo)
der = pk.public_bytes(encoding=serialization.Encoding.X962, format=serialization.PublicFormat.CompressedPoint)
with open(filename, "wb") as der_out:
der_out.write(der)
if __name__ == "__main__":
name = "pisa"
name = "teos"
output_dir = "."
opts, _ = getopt(argv[1:], "n:d:", ["name", "dir"])

View File

@@ -41,7 +41,7 @@ class Appointment:
``{locator, start_time, end_time, to_self_delay, encrypted_blob}``
Returns:
:obj:`Appointment <pisa.appointment.Appointment>`: An appointment initialized using the provided data.
:obj:`Appointment <teos.appointment.Appointment>`: An appointment initialized using the provided data.
Raises:
ValueError: If one of the mandatory keys is missing in ``appointment_data``.

View File

@@ -1,11 +1,11 @@
import os
import pisa.conf as conf
import teos.conf as conf
from common.tools import check_conf_fields, setup_logging, extend_paths, setup_data_folder
from pisa.utils.auth_proxy import AuthServiceProxy
from teos.utils.auth_proxy import AuthServiceProxy
HOST = "localhost"
PORT = 9814
LOG_PREFIX = "pisa"
LOG_PREFIX = "teos"
# Load config fields
conf_fields = {
@@ -22,7 +22,7 @@ conf_fields = {
"EXPIRY_DELTA": {"value": conf.EXPIRY_DELTA, "type": int},
"MIN_TO_SELF_DELAY": {"value": conf.MIN_TO_SELF_DELAY, "type": int},
"SERVER_LOG_FILE": {"value": conf.SERVER_LOG_FILE, "type": str, "path": True},
"PISA_SECRET_KEY": {"value": conf.PISA_SECRET_KEY, "type": str, "path": True},
"TEOS_SECRET_KEY": {"value": conf.TEOS_SECRET_KEY, "type": str, "path": True},
"DB_PATH": {"value": conf.DB_PATH, "type": str, "path": True},
}

View File

@@ -3,9 +3,9 @@ import json
import logging
from flask import Flask, request, abort, jsonify
from pisa import HOST, PORT, LOG_PREFIX
from teos import HOST, PORT, LOG_PREFIX
from common.logger import Logger
from pisa.inspector import Inspector
from teos.inspector import Inspector
from common.appointment import Appointment
from common.constants import HTTP_OK, HTTP_BAD_REQUEST, HTTP_SERVICE_UNAVAILABLE, LOCATOR_LEN_HEX
@@ -32,7 +32,7 @@ class API:
:obj:`tuple`: A tuple containing the response (``json``) and response code (``int``). For accepted
appointments, the ``rcode`` is always 0 and the response contains the signed receipt. For rejected
appointments, the ``rcode`` is a negative value and the response contains the error message. Error messages
can be found at :mod:`Errors <pisa.errors>`.
can be found at :mod:`Errors <teos.errors>`.
"""
# Getting the real IP if the server is behind a reverse proxy
@@ -101,11 +101,11 @@ class API:
Returns:
:obj:`dict`: A json formatted dictionary containing information about the requested appointment.
A ``status`` flag is added to the data provided by either the :obj:`Watcher <pisa.watcher.Watcher>` or the
:obj:`Responder <pisa.responder.Responder>` that signals the status of the appointment.
A ``status`` flag is added to the data provided by either the :obj:`Watcher <teos.watcher.Watcher>` or the
:obj:`Responder <teos.responder.Responder>` that signals the status of the appointment.
- Appointments hold by the :obj:`Watcher <pisa.watcher.Watcher>` are flagged as ``being_watched``.
- Appointments hold by the :obj:`Responder <pisa.responder.Responder>` are flagged as ``dispute_triggered``.
- Appointments hold by the :obj:`Watcher <teos.watcher.Watcher>` are flagged as ``being_watched``.
- Appointments hold by the :obj:`Responder <teos.responder.Responder>` are flagged as ``dispute_triggered``.
- Unknown appointments are flagged as ``not_found``.
"""
@@ -157,8 +157,8 @@ class API:
Returns:
:obj:`dict`: A json formatted dictionary containing all the appointments hold by the
:obj:`Watcher <pisa.watcher.Watcher>` (``watcher_appointments``) and by the
:obj:`Responder <pisa.responder.Responder>` (``responder_trackers``).
:obj:`Watcher <teos.watcher.Watcher>` (``watcher_appointments``) and by the
:obj:`Responder <teos.responder.Responder>` (``responder_trackers``).
"""

View File

@@ -1,8 +1,8 @@
from common.logger import Logger
from pisa import LOG_PREFIX
from pisa.tools import bitcoin_cli
from pisa.utils.auth_proxy import JSONRPCException
from teos import LOG_PREFIX
from teos.tools import bitcoin_cli
from teos.utils.auth_proxy import JSONRPCException
logger = Logger(actor="BlockProcessor", log_name_prefix=LOG_PREFIX)

View File

@@ -1,7 +1,7 @@
class Builder:
"""
The :class:`Builder` class is in charge or reconstructing data loaded from the database and build the data
structures of the :obj:`Watcher <pisa.watcher.Watcher>` and the :obj:`Responder <pisa.responder.Responder>`.
structures of the :obj:`Watcher <teos.watcher.Watcher>` and the :obj:`Responder <teos.responder.Responder>`.
"""
@staticmethod
@@ -12,13 +12,13 @@ class Builder:
Args:
appointments_data (:obj:`dict`): a dictionary of dictionaries representing all the
:obj:`Watcher <pisa.watcher.Watcher>` appointments stored in the database. The structure is as follows:
:obj:`Watcher <teos.watcher.Watcher>` appointments stored in the database. The structure is as follows:
``{uuid: {locator: str, start_time: int, ...}, uuid: {locator:...}}``
Returns:
:obj:`tuple`: A tuple with two dictionaries. ``appointments`` containing the appointment information in
:obj:`Appointment <pisa.appointment.Appointment>` objects and ``locator_uuid_map`` containing a map of
:obj:`Appointment <teos.appointment.Appointment>` objects and ``locator_uuid_map`` containing a map of
appointment (``uuid:locator``).
"""
@@ -44,14 +44,14 @@ class Builder:
Args:
tracker_data (:obj:`dict`): a dictionary of dictionaries representing all the
:mod:`Responder <pisa.responder.Responder>` trackers stored in the database.
:mod:`Responder <teos.responder.Responder>` trackers stored in the database.
The structure is as follows:
``{uuid: {locator: str, dispute_txid: str, ...}, uuid: {locator:...}}``
Returns:
:obj:`tuple`: A tuple with two dictionaries. ``trackers`` containing the trackers' information in
:obj:`TransactionTracker <pisa.responder.TransactionTracker>` objects and a ``tx_tracker_map`` containing
:obj:`TransactionTracker <teos.responder.TransactionTracker>` objects and a ``tx_tracker_map`` containing
the map of trackers (``penalty_txid: uuid``).
"""
@@ -77,8 +77,8 @@ class Builder:
@staticmethod
def populate_block_queue(block_queue, missed_blocks):
"""
Populates a ``Queue`` of block hashes to initialize the :mod:`Watcher <pisa.watcher.Watcher>` or the
:mod:`Responder <pisa.responder.Responder>` using backed up data.
Populates a ``Queue`` of block hashes to initialize the :mod:`Watcher <teos.watcher.Watcher>` or the
:mod:`Responder <teos.responder.Responder>` using backed up data.
Args:
block_queue (:obj:`Queue`): a ``Queue``
@@ -94,13 +94,13 @@ class Builder:
@staticmethod
def update_states(watcher, missed_blocks_watcher, missed_blocks_responder):
"""
Updates the states of both the :mod:`Watcher <pisa.watcher.Watcher>` and the :mod:`Responder <pisa.responder.Responder>`.
Updates the states of both the :mod:`Watcher <teos.watcher.Watcher>` and the :mod:`Responder <teos.responder.Responder>`.
If both have pending blocks to process they need to be updates at the same time, block by block.
If only one instance has to be updated, ``populate_block_queue`` should be used.
Args:
watcher (:obj:`Watcher <pisa.watcher.Watcher>`): a ``Watcher`` instance (including a ``Responder``).
watcher (:obj:`Watcher <teos.watcher.Watcher>`): a ``Watcher`` instance (including a ``Responder``).
missed_blocks_watcher (:obj:`list`): the list of block missed by the ``Watcher``.
missed_blocks_responder (:obj:`list`): the list of block missed by the ``Responder``.

View File

@@ -1,9 +1,9 @@
from pisa import LOG_PREFIX
from pisa.rpc_errors import *
from teos import LOG_PREFIX
from teos.rpc_errors import *
from common.logger import Logger
from pisa.tools import bitcoin_cli
from pisa.utils.auth_proxy import JSONRPCException
from pisa.errors import UNKNOWN_JSON_RPC_EXCEPTION, RPC_TX_REORGED_AFTER_BROADCAST
from teos.tools import bitcoin_cli
from teos.utils.auth_proxy import JSONRPCException
from teos.errors import UNKNOWN_JSON_RPC_EXCEPTION, RPC_TX_REORGED_AFTER_BROADCAST
logger = Logger(actor="Carrier", log_name_prefix=LOG_PREFIX)

View File

@@ -2,10 +2,10 @@ import zmq
import binascii
from threading import Thread, Event, Condition
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
from common.logger import Logger
from pisa.conf import FEED_PROTOCOL, FEED_ADDR, FEED_PORT, POLLING_DELTA, BLOCK_WINDOW_SIZE
from pisa.block_processor import BlockProcessor
from teos.conf import FEED_PROTOCOL, FEED_ADDR, FEED_PORT, POLLING_DELTA, BLOCK_WINDOW_SIZE
from teos.block_processor import BlockProcessor
logger = Logger(actor="ChainMonitor", log_name_prefix=LOG_PREFIX)
@@ -14,7 +14,7 @@ class ChainMonitor:
"""
The :class:`ChainMonitor` is the class in charge of monitoring the blockchain (via ``bitcoind``) to detect new
blocks on top of the best chain. If a new best block is spotted, the chain monitor will notify the
:obj:`Watcher <pisa.watcher.Watcher>` and the :obj:`Responder <pisa.responder.Responder>` using ``Queues``.
:obj:`Watcher <teos.watcher.Watcher>` and the :obj:`Responder <teos.responder.Responder>` using ``Queues``.
The :class:`ChainMonitor` monitors the chain using two methods: ``zmq`` and ``polling``. Blocks are only notified
once per queue and the notification is triggered by the method that detects the block faster.
@@ -31,9 +31,9 @@ class ChainMonitor:
lock (:obj:`Condition`): a lock used to protect concurrent access to the queues and ``best_tip`` by the zmq and
polling threads.
zmqSubSocket (:obj:`socket`): a socket to connect to ``bitcoind`` via ``zmq``.
watcher_queue (:obj:`Queue`): a queue to send new best tips to the :obj:`Watcher <pisa.watcher.Watcher>`.
watcher_queue (:obj:`Queue`): a queue to send new best tips to the :obj:`Watcher <teos.watcher.Watcher>`.
responder_queue (:obj:`Queue`): a queue to send new best tips to the
:obj:`Responder <pisa.responder.Responder>`.
:obj:`Responder <teos.responder.Responder>`.
"""
def __init__(self, watcher_queue, responder_queue):
@@ -141,7 +141,7 @@ class ChainMonitor:
def monitor_chain(self, polling_delta=POLLING_DELTA):
"""
Main :class:`ChainMonitor` method. It initializes the ``best_tip`` to the current one (by querying the
:obj:`BlockProcessor <pisa.block_processor.BlockProcessor>`) and creates two threads, one per each monitoring
:obj:`BlockProcessor <teos.block_processor.BlockProcessor>`) and creates two threads, one per each monitoring
approach (``zmq`` and ``polling``).
Args:

View File

@@ -1,4 +1,4 @@
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
from common.logger import Logger
@@ -43,7 +43,7 @@ class Cleaner:
Args:
uuid (:obj:`str`): the identifier of the appointment to be deleted.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""
@@ -61,7 +61,7 @@ class Cleaner:
Args:
uuids (:obj:`list`): a list of identifiers to be removed from the map.
locator (:obj:`str`): the identifier of the map to be either updated or deleted.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""
@@ -87,15 +87,15 @@ class Cleaner:
def delete_expired_appointments(expired_appointments, appointments, locator_uuid_map, db_manager):
"""
Deletes appointments which ``end_time`` has been reached (with no trigger) both from memory
(:obj:`Watcher <pisa.watcher.Watcher>`) and disk.
(:obj:`Watcher <teos.watcher.Watcher>`) and disk.
Args:
expired_appointments (:obj:`list`): a list of appointments to be deleted.
appointments (:obj:`dict`): a dictionary containing all the :mod:`Watcher <pisa.watcher.Watcher>`
appointments (:obj:`dict`): a dictionary containing all the :mod:`Watcher <teos.watcher.Watcher>`
appointments.
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <pisa.watcher.Watcher>`
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <teos.watcher.Watcher>`
appointments.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""
@@ -121,18 +121,18 @@ class Cleaner:
@staticmethod
def delete_completed_appointments(completed_appointments, appointments, locator_uuid_map, db_manager):
"""
Deletes a completed appointment from memory (:obj:`Watcher <pisa.watcher.Watcher>`) and disk.
Deletes a completed appointment from memory (:obj:`Watcher <teos.watcher.Watcher>`) and disk.
Currently, an appointment is only completed if it cannot make it to the (:obj:`Responder <pisa.responder.Responder>`),
Currently, an appointment is only completed if it cannot make it to the (:obj:`Responder <teos.responder.Responder>`),
otherwise, it will be flagged as triggered and removed once the tracker is completed.
Args:
completed_appointments (:obj:`list`): a list of appointments to be deleted.
appointments (:obj:`dict`): a dictionary containing all the :obj:`Watcher <pisa.watcher.Watcher>`
appointments (:obj:`dict`): a dictionary containing all the :obj:`Watcher <teos.watcher.Watcher>`
appointments.
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <pisa.watcher.Watcher>`
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <teos.watcher.Watcher>`
appointments.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""
locator_maps_to_update = {}
@@ -160,16 +160,16 @@ class Cleaner:
@staticmethod
def flag_triggered_appointments(triggered_appointments, appointments, locator_uuid_map, db_manager):
"""
Deletes a list of triggered appointment from memory (:obj:`Watcher <pisa.watcher.Watcher>`) and flags them as
Deletes a list of triggered appointment from memory (:obj:`Watcher <teos.watcher.Watcher>`) and flags them as
triggered on disk.
Args:
triggered_appointments (:obj:`list`): a list of appointments to be flagged as triggered on the database.
appointments (:obj:`dict`): a dictionary containing all the :obj:`Watcher <pisa.watcher.Watcher>`
appointments (:obj:`dict`): a dictionary containing all the :obj:`Watcher <teos.watcher.Watcher>`
appointments.
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <pisa.watcher.Watcher>`
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map for the :obj:`Watcher <teos.watcher.Watcher>`
appointments.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""
@@ -180,17 +180,17 @@ class Cleaner:
@staticmethod
def delete_completed_trackers(completed_trackers, height, trackers, tx_tracker_map, db_manager):
"""
Deletes a completed tracker both from memory (:obj:`Responder <pisa.responder.Responder>`) and disk (from the
Deletes a completed tracker both from memory (:obj:`Responder <teos.responder.Responder>`) and disk (from the
Responder's and Watcher's databases).
Args:
trackers (:obj:`dict`): a dictionary containing all the :obj:`Responder <pisa.responder.Responder>`
trackers (:obj:`dict`): a dictionary containing all the :obj:`Responder <teos.responder.Responder>`
trackers.
tx_tracker_map (:obj:`dict`): a ``penalty_txid:uuid`` map for the :obj:`Responder
<pisa.responder.Responder>` trackers.
<teos.responder.Responder>` trackers.
completed_trackers (:obj:`dict`): a dict of completed trackers to be deleted (uuid:confirmations).
height (:obj:`int`): the block height at which the trackers were completed.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
"""

View File

@@ -1,7 +1,7 @@
import json
import plyvel
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
from common.logger import Logger
@@ -22,12 +22,12 @@ class DBManager:
The database is split in six prefixes:
- ``WATCHER_PREFIX``, defined as ``b'w``, is used to store :obj:`Watcher <pisa.watcher.Watcher>` appointments.
- ``RESPONDER_PREFIX``, defines as ``b'r``, is used to store :obj:`Responder <pisa.responder.Responder>` trackers.
- ``WATCHER_LAST_BLOCK_KEY``, defined as ``b'bw``, is used to store the last block hash known by the :obj:`Watcher <pisa.watcher.Watcher>`.
- ``RESPONDER_LAST_BLOCK_KEY``, defined as ``b'br``, is used to store the last block hash known by the :obj:`Responder <pisa.responder.Responder>`.
- ``WATCHER_PREFIX``, defined as ``b'w``, is used to store :obj:`Watcher <teos.watcher.Watcher>` appointments.
- ``RESPONDER_PREFIX``, defines as ``b'r``, is used to store :obj:`Responder <teos.responder.Responder>` trackers.
- ``WATCHER_LAST_BLOCK_KEY``, defined as ``b'bw``, is used to store the last block hash known by the :obj:`Watcher <teos.watcher.Watcher>`.
- ``RESPONDER_LAST_BLOCK_KEY``, defined as ``b'br``, is used to store the last block hash known by the :obj:`Responder <teos.responder.Responder>`.
- ``LOCATOR_MAP_PREFIX``, defined as ``b'm``, is used to store the ``locator:uuid`` maps.
- ``TRIGGERED_APPOINTMENTS_PREFIX``, defined as ``b'ta``, is used to stored triggered appointments (appointments that have been handed to the :obj:`Responder <pisa.responder.Responder>`.)
- ``TRIGGERED_APPOINTMENTS_PREFIX``, defined as ``b'ta``, is used to stored triggered appointments (appointments that have been handed to the :obj:`Responder <teos.responder.Responder>`.)
Args:
db_path (:obj:`str`): the path (relative or absolute) to the system folder containing the database. A fresh
@@ -357,7 +357,7 @@ class DBManager:
def load_last_block_hash_watcher(self):
"""
Loads the last known block hash of the :obj:`Watcher <pisa.watcher.Watcher>` from the database.
Loads the last known block hash of the :obj:`Watcher <teos.watcher.Watcher>` from the database.
Returns:
:obj:`str` or :obj:`None`: A 32-byte hex-encoded string representing the last known block hash if found.
@@ -368,7 +368,7 @@ class DBManager:
def load_last_block_hash_responder(self):
"""
Loads the last known block hash of the :obj:`Responder <pisa.responder.Responder>` from the database.
Loads the last known block hash of the :obj:`Responder <teos.responder.Responder>` from the database.
Returns:
:obj:`str` or :obj:`None`: A 32-byte hex-encoded string representing the last known block hash if found.
@@ -379,7 +379,7 @@ class DBManager:
def store_last_block_hash_watcher(self, block_hash):
"""
Stores a block hash as the last known block of the :obj:`Watcher <pisa.watcher.Watcher>`.
Stores a block hash as the last known block of the :obj:`Watcher <teos.watcher.Watcher>`.
Args:
block_hash (:obj:`str`): the block hash to be stored (32-byte hex-encoded)
@@ -389,7 +389,7 @@ class DBManager:
def store_last_block_hash_responder(self, block_hash):
"""
Stores a block hash as the last known block of the :obj:`Responder <pisa.responder.Responder>`.
Stores a block hash as the last known block of the :obj:`Responder <teos.responder.Responder>`.
Args:
block_hash (:obj:`str`): the block hash to be stored (32-byte hex-encoded)

View File

@@ -5,17 +5,17 @@ import common.cryptographer
from common.constants import LOCATOR_LEN_HEX
from common.cryptographer import Cryptographer, PublicKey
from pisa import errors, LOG_PREFIX
from teos import errors, LOG_PREFIX
from common.logger import Logger
from common.appointment import Appointment
from pisa.block_processor import BlockProcessor
from teos.block_processor import BlockProcessor
logger = Logger(actor="Inspector", log_name_prefix=LOG_PREFIX)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
# FIXME: The inspector logs the wrong messages sent form the users. A possible attack surface would be to send a really
# long field that, even if not accepted by PISA, would be stored in the logs. This is a possible DoS surface
# since pisa would store any kind of message (no matter the length). Solution: truncate the length of the fields
# long field that, even if not accepted by TEOS, would be stored in the logs. This is a possible DoS surface
# since teos would store any kind of message (no matter the length). Solution: truncate the length of the fields
# stored + blacklist if multiple wrong requests are received.
@@ -41,12 +41,12 @@ class Inspector:
public_key (:obj:`str`): the user's public key (hex encoded).
Returns:
:obj:`Appointment <pisa.appointment.Appointment>` or :obj:`tuple`: An appointment initialized with the
:obj:`Appointment <teos.appointment.Appointment>` or :obj:`tuple`: An appointment initialized with the
provided data if it is correct.
Returns a tuple ``(return code, message)`` describing the error otherwise.
Errors are defined in :mod:`Errors <pisa.errors>`.
Errors are defined in :mod:`Errors <teos.errors>`.
"""
block_height = BlockProcessor.get_block_count()

View File

@@ -2,11 +2,11 @@ import json
from queue import Queue
from threading import Thread
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
from common.logger import Logger
from pisa.cleaner import Cleaner
from pisa.carrier import Carrier
from pisa.block_processor import BlockProcessor
from teos.cleaner import Cleaner
from teos.carrier import Carrier
from teos.block_processor import BlockProcessor
CONFIRMATIONS_BEFORE_RETRY = 6
MIN_CONFIRMATIONS = 6
@@ -17,7 +17,7 @@ logger = Logger(actor="Responder", log_name_prefix=LOG_PREFIX)
class TransactionTracker:
"""
A :class:`TransactionTracker` is used to monitor a ``penalty_tx``. Once the dispute is seen by the
:obj:`Watcher <pisa.watcher.Watcher>` the penalty transaction is decrypted and the relevant appointment data is
:obj:`Watcher <teos.watcher.Watcher>` the penalty transaction is decrypted and the relevant appointment data is
passed along to the :obj:`Responder`.
Once the :obj:`Responder` has succeeded on broadcasting the penalty transaction it will create a
@@ -105,11 +105,11 @@ class TransactionTracker:
class Responder:
"""
The :class:`Responder` is the class in charge of ensuring that channel breaches are dealt with. It does so handling
the decrypted ``penalty_txs`` handed by the :obj:`Watcher <pisa.watcher.Watcher>` and ensuring the they make it to
the decrypted ``penalty_txs`` handed by the :obj:`Watcher <teos.watcher.Watcher>` and ensuring the they make it to
the blockchain.
Args:
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): a ``DBManager`` instance to interact with the
database.
Attributes:
@@ -122,8 +122,8 @@ class Responder:
missed_confirmations (:obj:`dict`): A dictionary that keeps count of how many confirmations each ``penalty_tx``
has missed. Used to trigger rebroadcast if needed.
block_queue (:obj:`Queue`): A queue used by the :obj:`Responder` to receive block hashes from ``bitcoind``. It
is populated by the :obj:`ChainMonitor <pisa.chain_monitor.ChainMonitor>`.
db_manager (:obj:`DBManager <pisa.db_manager.DBManager>`): A ``DBManager`` instance to interact with the
is populated by the :obj:`ChainMonitor <teos.chain_monitor.ChainMonitor>`.
db_manager (:obj:`DBManager <teos.db_manager.DBManager>`): A ``DBManager`` instance to interact with the
database.
"""
@@ -150,7 +150,7 @@ class Responder:
Whether the :obj:`Responder` is on sync with ``bitcoind`` or not. Used when recovering from a crash.
The Watchtower can be instantiated with fresh or with backed up data. In the later, some triggers may have been
missed. In order to go back on sync both the :obj:`Watcher <pisa.watcher.Watcher>` and the :obj:`Responder`
missed. In order to go back on sync both the :obj:`Watcher <teos.watcher.Watcher>` and the :obj:`Responder`
need to perform the state transitions until they catch up.
If a transaction is broadcast by the :obj:`Responder` and it is rejected (due to a double-spending for example)
@@ -191,7 +191,7 @@ class Responder:
block_hash (:obj:`str`): the block hash at which the breach was seen (used to see if we are on sync).
Returns:
:obj:`Receipt <pisa.carrier.Receipt>`: A ``Receipt`` indicating whether or not the ``penalty_tx`` made it
:obj:`Receipt <teos.carrier.Receipt>`: A ``Receipt`` indicating whether or not the ``penalty_tx`` made it
into the blockchain.
"""
@@ -403,7 +403,7 @@ class Responder:
txs_to_rebroadcast (:obj:`list`): a list of transactions to be rebroadcast.
Returns:
:obj:`list`: A list of :obj:`Receipts <pisa.carrier.Receipt>` with information about whether or not every
:obj:`list`: A list of :obj:`Receipts <teos.carrier.Receipt>` with information about whether or not every
transaction made it trough the network.
"""

View File

@@ -10,13 +10,13 @@ FEED_PROTOCOL = "tcp"
FEED_ADDR = "127.0.0.1"
FEED_PORT = 28332
# PISA
DATA_FOLDER = "~/.pisa_btc/"
# TEOS
DATA_FOLDER = "~/.teos/"
MAX_APPOINTMENTS = 100
EXPIRY_DELTA = 6
MIN_TO_SELF_DELAY = 20
SERVER_LOG_FILE = "pisa.log"
PISA_SECRET_KEY = "pisa_sk.der"
SERVER_LOG_FILE = "teos.log"
TEOS_SECRET_KEY = "teos_sk.der"
# CHAIN MONITOR
POLLING_DELTA = 60

View File

@@ -6,15 +6,15 @@ import common.cryptographer
from common.logger import Logger
from common.cryptographer import Cryptographer
from pisa import config, LOG_PREFIX
from pisa.api import API
from pisa.watcher import Watcher
from pisa.builder import Builder
from pisa.responder import Responder
from pisa.db_manager import DBManager
from pisa.chain_monitor import ChainMonitor
from pisa.block_processor import BlockProcessor
from pisa.tools import can_connect_to_bitcoind, in_correct_network
from teos import config, LOG_PREFIX
from teos.api import API
from teos.watcher import Watcher
from teos.builder import Builder
from teos.responder import Responder
from teos.db_manager import DBManager
from teos.chain_monitor import ChainMonitor
from teos.block_processor import BlockProcessor
from teos.tools import can_connect_to_bitcoind, in_correct_network
logger = Logger(actor="Daemon", log_name_prefix=LOG_PREFIX)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
@@ -25,7 +25,7 @@ def handle_signals(signal_received, frame):
db_manager.db.close()
chain_monitor.terminate = True
logger.info("Shutting down PISA")
logger.info("Shutting down TEOS")
exit(0)
@@ -36,7 +36,7 @@ def main():
signal(SIGTERM, handle_signals)
signal(SIGQUIT, handle_signals)
logger.info("Starting PISA")
logger.info("Starting TEOS")
db_manager = DBManager(config.get("DB_PATH"))
if not can_connect_to_bitcoind():
@@ -47,9 +47,9 @@ def main():
else:
try:
secret_key_der = Cryptographer.load_key_file(config.get("PISA_SECRET_KEY"))
secret_key_der = Cryptographer.load_key_file(config.get("TEOS_SECRET_KEY"))
if not secret_key_der:
raise IOError("PISA private key can't be loaded")
raise IOError("TEOS private key can't be loaded")
watcher = Watcher(db_manager, Responder(db_manager), secret_key_der, config)

View File

@@ -1,8 +1,8 @@
from http.client import HTTPException
from socket import timeout
import pisa.conf as conf
from pisa.utils.auth_proxy import AuthServiceProxy, JSONRPCException
import teos.conf as conf
from teos.utils.auth_proxy import AuthServiceProxy, JSONRPCException
"""
Tools is a module with general methods that can used by different entities in the codebase.
@@ -15,7 +15,7 @@ def bitcoin_cli():
An ``http`` connection with ``bitcoind`` using the ``json-rpc`` interface.
Returns:
:obj:`AuthServiceProxy <pisa.utils.auth_proxy.AuthServiceProxy>`: An authenticated service proxy to ``bitcoind``
:obj:`AuthServiceProxy <teos.utils.auth_proxy.AuthServiceProxy>`: An authenticated service proxy to ``bitcoind``
that can be used to send ``json-rpc`` commands.
"""

View File

@@ -9,9 +9,9 @@ from common.tools import compute_locator
from common.logger import Logger
from pisa import LOG_PREFIX
from pisa.cleaner import Cleaner
from pisa.block_processor import BlockProcessor
from teos import LOG_PREFIX
from teos.cleaner import Cleaner
from teos.block_processor import BlockProcessor
logger = Logger(actor="Watcher", log_name_prefix=LOG_PREFIX)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
@@ -25,36 +25,36 @@ class Watcher:
The :class:`Watcher` keeps track of the accepted appointments in ``appointments`` and, for new received block,
checks if any breach has happened by comparing the txids with the appointment locators. If a breach is seen, the
:obj:`EncryptedBlob <common.encrypted_blob.EncryptedBlob>` of the corresponding appointment is decrypted and the data
is passed to the :obj:`Responder <pisa.responder.Responder>`.
is passed to the :obj:`Responder <teos.responder.Responder>`.
If an appointment reaches its end with no breach, the data is simply deleted.
The :class:`Watcher` receives information about new received blocks via the ``block_queue`` that is populated by the
:obj:`ChainMonitor <pisa.chain_monitor.ChainMonitor>`.
:obj:`ChainMonitor <teos.chain_monitor.ChainMonitor>`.
Args:
db_manager (:obj:`DBManager <pisa.db_manager>`): a ``DBManager`` instance to interact with the database.
db_manager (:obj:`DBManager <teos.db_manager>`): a ``DBManager`` instance to interact with the database.
sk_der (:obj:`bytes`): a DER encoded private key used to sign appointment receipts (signaling acceptance).
config (:obj:`dict`): a dictionary containing all the configuration parameters. Used locally to retrieve
``MAX_APPOINTMENTS`` and ``EXPIRY_DELTA``.
responder (:obj:`Responder <pisa.responder.Responder>`): a ``Responder`` instance.
responder (:obj:`Responder <teos.responder.Responder>`): a ``Responder`` instance.
Attributes:
appointments (:obj:`dict`): a dictionary containing a simplification of the appointments (:obj:`Appointment
<pisa.appointment.Appointment>` instances) accepted by the tower (``locator`` and ``end_time``).
<teos.appointment.Appointment>` instances) accepted by the tower (``locator`` and ``end_time``).
It's populated trough ``add_appointment``.
locator_uuid_map (:obj:`dict`): a ``locator:uuid`` map used to allow the :obj:`Watcher` to deal with several
appointments with the same ``locator``.
block_queue (:obj:`Queue`): A queue used by the :obj:`Watcher` to receive block hashes from ``bitcoind``. It is
populated by the :obj:`ChainMonitor <pisa.chain_monitor.ChainMonitor>`.
populated by the :obj:`ChainMonitor <teos.chain_monitor.ChainMonitor>`.
config (:obj:`dict`): a dictionary containing all the configuration parameters. Used locally to retrieve
``MAX_APPOINTMENTS`` and ``EXPIRY_DELTA``.
db_manager (:obj:`DBManager <pisa.db_manager>`): A db manager instance to interact with the database.
db_manager (:obj:`DBManager <teos.db_manager>`): A db manager instance to interact with the database.
signing_key (:mod:`PrivateKey`): a private key used to sign accepted appointments.
Raises:
ValueError: if `pisa_sk_file` is not found.
ValueError: if `teos_sk_file` is not found.
"""
@@ -82,7 +82,7 @@ class Watcher:
Once a breach is seen on the blockchain, the :obj:`Watcher` will decrypt the corresponding
:obj:`EncryptedBlob <common.encrypted_blob.EncryptedBlob>` and pass the information to the
:obj:`Responder <pisa.responder.Responder>`.
:obj:`Responder <teos.responder.Responder>`.
The tower may store multiple appointments with the same ``locator`` to avoid DoS attacks based on data
rewriting. `locators`` should be derived from the ``dispute_txid``, but that task is performed by the user, and
@@ -90,7 +90,7 @@ class Watcher:
identified by ``uuid`` and stored in ``appointments`` and ``locator_uuid_map``.
Args:
appointment (:obj:`Appointment <pisa.appointment.Appointment>`): the appointment to be added to the
appointment (:obj:`Appointment <teos.appointment.Appointment>`): the appointment to be added to the
:obj:`Watcher`.
Returns:
@@ -134,7 +134,7 @@ class Watcher:
Monitors the blockchain whilst there are pending appointments.
This is the main method of the :obj:`Watcher` and the one in charge to pass appointments to the
:obj:`Responder <pisa.responder.Responder>` upon detecting a breach.
:obj:`Responder <teos.responder.Responder>` upon detecting a breach.
"""
while True:
@@ -233,7 +233,7 @@ class Watcher:
The :obj:`Watcher` cannot if a given :obj:`EncryptedBlob <common.encrypted_blob.EncryptedBlob>` contains a valid
transaction until a breach if seen. Blobs that contain arbitrary data are dropped and not sent to the
:obj:`Responder <pisa.responder.Responder>`.
:obj:`Responder <teos.responder.Responder>`.
Args:
breaches (:obj:`dict`): a dictionary containing channel breaches (``locator:txid``).

View File

@@ -11,10 +11,10 @@ from common.appointment import Appointment
from common.cryptographer import Cryptographer
from common.blob import Blob
import apps.cli.wt_cli as wt_cli
import apps.cli.teos_cli as teos_cli
from test.apps.cli.unit.conftest import get_random_value_hex
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=wt_cli.LOG_PREFIX)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=teos_cli.LOG_PREFIX)
# dummy keys for the tests
dummy_sk = PrivateKey()
@@ -23,11 +23,11 @@ another_sk = PrivateKey()
# Replace the key in the module with a key we control for the tests
wt_cli.pisa_public_key = dummy_pk
teos_cli.teos_public_key = dummy_pk
# Replace endpoint with dummy one
wt_cli.pisa_api_server = "https://dummy.com"
wt_cli.pisa_api_port = 12345
pisa_endpoint = "{}:{}/".format(wt_cli.pisa_api_server, wt_cli.pisa_api_port)
teos_cli.teos_api_server = "https://dummy.com"
teos_cli.teos_api_port = 12345
teos_endpoint = "{}:{}/".format(teos_cli.teos_api_server, teos_cli.teos_api_port)
dummy_appointment_request = {
"tx": get_random_value_hex(192),
@@ -74,17 +74,17 @@ def get_bad_signature(*args):
# f.write(dummy_pk_der)
#
# # Now we can test the function passing the using this files (we'll use the same pk for both)
# r = wt_cli.load_keys(public_key_file_path, private_key_file_path, public_key_file_path)
# r = teos_cli.load_keys(public_key_file_path, private_key_file_path, public_key_file_path)
# assert isinstance(r, tuple)
# assert len(r) == 3
#
# # If any param does not match we should get None as result
# assert wt_cli.load_keys(None, private_key_file_path, public_key_file_path) is None
# assert wt_cli.load_keys(public_key_file_path, None, public_key_file_path) is None
# assert wt_cli.load_keys(public_key_file_path, private_key_file_path, None) is None
# assert teos_cli.load_keys(None, private_key_file_path, public_key_file_path) is None
# assert teos_cli.load_keys(public_key_file_path, None, public_key_file_path) is None
# assert teos_cli.load_keys(public_key_file_path, private_key_file_path, None) is None
#
# # The same should happen if we pass a public key where a private should be, for instance
# assert wt_cli.load_keys(private_key_file_path, public_key_file_path, private_key_file_path) is None
# assert teos_cli.load_keys(private_key_file_path, public_key_file_path, private_key_file_path) is None
#
# os.remove(private_key_file_path)
# os.remove(public_key_file_path)
@@ -95,14 +95,14 @@ def get_bad_signature(*args):
def test_add_appointment(monkeypatch):
# Simulate a request to add_appointment for dummy_appointment, make sure that the right endpoint is requested
# and the return value is True
monkeypatch.setattr(wt_cli, "load_keys", load_dummy_keys)
monkeypatch.setattr(teos_cli, "load_keys", load_dummy_keys)
response = {"locator": dummy_appointment.locator, "signature": get_dummy_signature()}
responses.add(responses.POST, pisa_endpoint, json=response, status=200)
result = wt_cli.add_appointment([json.dumps(dummy_appointment_request)])
responses.add(responses.POST, teos_endpoint, json=response, status=200)
result = teos_cli.add_appointment([json.dumps(dummy_appointment_request)])
assert len(responses.calls) == 1
assert responses.calls[0].request.url == pisa_endpoint
assert responses.calls[0].request.url == teos_endpoint
assert result
@@ -112,39 +112,39 @@ def test_add_appointment_with_invalid_signature(monkeypatch):
# make sure that the right endpoint is requested, but the return value is False
# Make sure the test uses the bad dummy signature
monkeypatch.setattr(wt_cli, "load_keys", load_dummy_keys)
monkeypatch.setattr(teos_cli, "load_keys", load_dummy_keys)
response = {
"locator": dummy_appointment.to_dict()["locator"],
"signature": get_bad_signature(), # Sign with a bad key
}
responses.add(responses.POST, pisa_endpoint, json=response, status=200)
result = wt_cli.add_appointment([json.dumps(dummy_appointment_request)])
responses.add(responses.POST, teos_endpoint, json=response, status=200)
result = teos_cli.add_appointment([json.dumps(dummy_appointment_request)])
assert result is False
def test_parse_add_appointment_args():
# If no args are passed, function should fail.
appt_data = wt_cli.parse_add_appointment_args(None)
appt_data = teos_cli.parse_add_appointment_args(None)
assert not appt_data
# If file doesn't exist, function should fail.
appt_data = wt_cli.parse_add_appointment_args(["-f", "nonexistent_file"])
appt_data = teos_cli.parse_add_appointment_args(["-f", "nonexistent_file"])
assert not appt_data
# If file exists and has data in it, function should work.
with open("appt_test_file", "w") as f:
json.dump(dummy_appointment_request, f)
appt_data = wt_cli.parse_add_appointment_args(["-f", "appt_test_file"])
appt_data = teos_cli.parse_add_appointment_args(["-f", "appt_test_file"])
assert appt_data
os.remove("appt_test_file")
# If appointment json is passed in, function should work.
appt_data = wt_cli.parse_add_appointment_args([json.dumps(dummy_appointment_request)])
appt_data = teos_cli.parse_add_appointment_args([json.dumps(dummy_appointment_request)])
assert appt_data
@@ -155,11 +155,11 @@ def test_post_appointment():
"signature": Cryptographer.sign(dummy_appointment.serialize(), dummy_pk),
}
responses.add(responses.POST, pisa_endpoint, json=response, status=200)
response = wt_cli.post_appointment(json.dumps(dummy_appointment_request))
responses.add(responses.POST, teos_endpoint, json=response, status=200)
response = teos_cli.post_appointment(json.dumps(dummy_appointment_request))
assert len(responses.calls) == 1
assert responses.calls[0].request.url == pisa_endpoint
assert responses.calls[0].request.url == teos_endpoint
assert response
@@ -172,28 +172,28 @@ def test_process_post_appointment_response():
}
# A 200 OK with a correct json response should return the json of the response
responses.add(responses.POST, pisa_endpoint, json=response, status=200)
r = wt_cli.post_appointment(json.dumps(dummy_appointment_request))
assert wt_cli.process_post_appointment_response(r) == r.json()
responses.add(responses.POST, teos_endpoint, json=response, status=200)
r = teos_cli.post_appointment(json.dumps(dummy_appointment_request))
assert teos_cli.process_post_appointment_response(r) == r.json()
# If we modify the response code tor a rejection (lets say 404) we should get None
responses.replace(responses.POST, pisa_endpoint, json=response, status=404)
r = wt_cli.post_appointment(json.dumps(dummy_appointment_request))
assert wt_cli.process_post_appointment_response(r) is None
responses.replace(responses.POST, teos_endpoint, json=response, status=404)
r = teos_cli.post_appointment(json.dumps(dummy_appointment_request))
assert teos_cli.process_post_appointment_response(r) is None
# The same should happen if the response is not in json
responses.replace(responses.POST, pisa_endpoint, status=404)
r = wt_cli.post_appointment(json.dumps(dummy_appointment_request))
assert wt_cli.process_post_appointment_response(r) is None
responses.replace(responses.POST, teos_endpoint, status=404)
r = teos_cli.post_appointment(json.dumps(dummy_appointment_request))
assert teos_cli.process_post_appointment_response(r) is None
def test_save_appointment_receipt(monkeypatch):
appointments_folder = "test_appointments_receipts"
wt_cli.config["APPOINTMENTS_FOLDER_NAME"] = appointments_folder
teos_cli.config["APPOINTMENTS_FOLDER_NAME"] = appointments_folder
# The functions creates a new directory if it does not exist
assert not os.path.exists(appointments_folder)
wt_cli.save_appointment_receipt(dummy_appointment.to_dict(), get_dummy_signature())
teos_cli.save_appointment_receipt(dummy_appointment.to_dict(), get_dummy_signature())
assert os.path.exists(appointments_folder)
# Check that the receipt has been saved by checking the file names
@@ -209,9 +209,9 @@ def test_get_appointment():
dummy_appointment_full["status"] = "being_watched"
response = dummy_appointment_full
request_url = "{}get_appointment?locator={}".format(pisa_endpoint, response.get("locator"))
request_url = "{}get_appointment?locator={}".format(teos_endpoint, response.get("locator"))
responses.add(responses.GET, request_url, json=response, status=200)
result = wt_cli.get_appointment(response.get("locator"))
result = teos_cli.get_appointment(response.get("locator"))
assert len(responses.calls) == 1
assert responses.calls[0].request.url == request_url
@@ -223,7 +223,7 @@ def test_get_appointment_err():
locator = get_random_value_hex(16)
# Test that get_appointment handles a connection error appropriately.
request_url = "{}get_appointment?locator=".format(pisa_endpoint, locator)
request_url = "{}get_appointment?locator=".format(teos_endpoint, locator)
responses.add(responses.GET, request_url, body=ConnectionError())
assert not wt_cli.get_appointment(locator)
assert not teos_cli.get_appointment(locator)

View File

@@ -3,8 +3,8 @@ import pytest
import logging
from copy import deepcopy
# FIXME: Import from pisa. Common should not import anything from cli nor pisa.
from pisa import conf_fields
# FIXME: Import from teos. Common should not import anything from cli nor teos.
from teos import conf_fields
from common.constants import LOCATOR_LEN_BYTES
from common.tools import (

View File

@@ -3,9 +3,9 @@ import random
from multiprocessing import Process
from decimal import Decimal, getcontext
import pisa.conf as conf
from pisa.pisad import main
from pisa.utils.auth_proxy import AuthServiceProxy
import teos.conf as conf
from teos.teosd import main
from teos.utils.auth_proxy import AuthServiceProxy
getcontext().prec = 10
END_TIME_DELTA = 10
@@ -50,11 +50,11 @@ def create_txs(bitcoin_cli):
return signed_commitment_tx, signed_penalty_tx
def run_pisad():
pisad_process = Process(target=main, daemon=True)
pisad_process.start()
def run_teosd():
teosd_process = Process(target=main, daemon=True)
teosd_process.start()
return pisad_process
return teosd_process
def get_random_value_hex(nbytes):

View File

@@ -10,13 +10,13 @@ FEED_PROTOCOL = "tcp"
FEED_ADDR = "127.0.0.1"
FEED_PORT = 28335
# PISA
DATA_FOLDER = "~/.pisa_btc/"
# TEOS
DATA_FOLDER = "~/.teos/"
MAX_APPOINTMENTS = 100
EXPIRY_DELTA = 6
MIN_TO_SELF_DELAY = 20
SERVER_LOG_FILE = "pisa.log"
PISA_SECRET_KEY = "pisa_sk.der"
SERVER_LOG_FILE = "teos.log"
TEOS_SECRET_KEY = "teos_sk.der"
# CHAIN MONITOR
POLLING_DELTA = 60

View File

@@ -2,9 +2,9 @@ import json
from time import sleep
from riemann.tx import Tx
from pisa import config
from pisa import HOST, PORT
from apps.cli import wt_cli
from teos import config
from teos import HOST, PORT
from apps.cli import teos_cli
from common.blob import Blob
import common.cryptographer
@@ -12,31 +12,31 @@ from common.logger import Logger
from common.tools import compute_locator
from common.appointment import Appointment
from common.cryptographer import Cryptographer
from pisa.utils.auth_proxy import JSONRPCException
from test.pisa.e2e.conftest import (
from teos.utils.auth_proxy import JSONRPCException
from test.teos.e2e.conftest import (
END_TIME_DELTA,
build_appointment_data,
get_random_value_hex,
create_penalty_tx,
run_pisad,
run_teosd,
)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix="")
# We'll use wt_cli to add appointments. The expected input format is a list of arguments with a json-encoded
# We'll use teos_cli to add appointments. The expected input format is a list of arguments with a json-encoded
# appointment
wt_cli.pisa_api_server = "http://{}".format(HOST)
wt_cli.pisa_api_port = PORT
teos_cli.teos_api_server = "http://{}".format(HOST)
teos_cli.teos_api_port = PORT
# Run pisad
pisad_process = run_pisad()
# Run teosd
teosd_process = run_teosd()
def get_pisa_pk():
pisa_sk = Cryptographer.load_private_key_der(Cryptographer.load_key_file(config.get("PISA_SECRET_KEY")))
pisa_pk = pisa_sk.public_key
def get_teos_pk():
teos_sk = Cryptographer.load_private_key_der(Cryptographer.load_key_file(config.get("TEOS_SECRET_KEY")))
teos_pk = teos_sk.public_key
return pisa_pk
return teos_pk
def broadcast_transaction_and_mine_block(bitcoin_cli, commitment_tx, addr):
@@ -48,18 +48,18 @@ def broadcast_transaction_and_mine_block(bitcoin_cli, commitment_tx, addr):
def get_appointment_info(locator):
# Check that the justice has been triggered (the appointment has moved from Watcher to Responder)
sleep(1) # Let's add a bit of delay so the state can be updated
return wt_cli.get_appointment(locator)
return teos_cli.get_appointment(locator)
def test_appointment_life_cycle(monkeypatch, bitcoin_cli, create_txs):
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
commitment_tx, penalty_tx = create_txs
commitment_tx_id = bitcoin_cli.decoderawtransaction(commitment_tx).get("txid")
appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx)
locator = compute_locator(commitment_tx_id)
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
appointment_info = get_appointment_info(locator)
assert appointment_info is not None
@@ -97,7 +97,7 @@ def test_appointment_life_cycle(monkeypatch, bitcoin_cli, create_txs):
def test_appointment_malformed_penalty(monkeypatch, bitcoin_cli, create_txs):
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
# Lets start by creating two valid transaction
commitment_tx, penalty_tx = create_txs
@@ -111,7 +111,7 @@ def test_appointment_malformed_penalty(monkeypatch, bitcoin_cli, create_txs):
appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, mod_penalty_tx.hex())
locator = compute_locator(commitment_tx_id)
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
# Broadcast the commitment transaction and mine a block
new_addr = bitcoin_cli.getnewaddress()
@@ -134,14 +134,14 @@ def test_appointment_wrong_key(bitcoin_cli, create_txs):
# The appointment data is built using a random 32-byte value.
appointment_data = build_appointment_data(bitcoin_cli, get_random_value_hex(32), penalty_tx)
# We can't use wt_cli.add_appointment here since it computes the locator internally, so let's do it manually.
# We can't use teos_cli.add_appointment here since it computes the locator internally, so let's do it manually.
# We will encrypt the blob using the random value and derive the locator from the commitment tx.
appointment_data["locator"] = compute_locator(bitcoin_cli.decoderawtransaction(commitment_tx).get("txid"))
appointment_data["encrypted_blob"] = Cryptographer.encrypt(Blob(penalty_tx), get_random_value_hex(32))
appointment = Appointment.from_dict(appointment_data)
# pisa_pk, cli_sk, cli_pk_der = wt_cli.load_keys(
# cli_conf.get("PISA_PUBLIC_KEY"), cli_conf.get("CLI_PRIVATE_KEY"), cli_conf.get("CLI_PUBLIC_KEY")
# teos_pk, cli_sk, cli_pk_der = teos_cli.load_keys(
# cli_conf.get("TEOS_PUBLIC_KEY"), cli_conf.get("CLI_PRIVATE_KEY"), cli_conf.get("CLI_PUBLIC_KEY")
# )
# hex_pk_der = binascii.hexlify(cli_pk_der)
#
@@ -149,18 +149,18 @@ def test_appointment_wrong_key(bitcoin_cli, create_txs):
# data = {"appointment": appointment.to_dict(), "signature": signature, "public_key": hex_pk_der.decode("utf-8")}
# FIXME: Since the pk is now hardcoded for the alpha in the cli we cannot use load_keys here. We need to derive
# the pk from the sk on disk.
pisa_pk = get_pisa_pk()
teos_pk = get_teos_pk()
data = {"appointment": appointment.to_dict()}
# Send appointment to the server.
response = wt_cli.post_appointment(data)
response_json = wt_cli.process_post_appointment_response(response)
response = teos_cli.post_appointment(data)
response_json = teos_cli.process_post_appointment_response(response)
# Check that the server has accepted the appointment
signature = response_json.get("signature")
assert signature is not None
rpk = Cryptographer.recover_pk(appointment.serialize(), signature)
assert Cryptographer.verify_rpk(pisa_pk, rpk) is True
assert Cryptographer.verify_rpk(teos_pk, rpk) is True
assert response_json.get("locator") == appointment.locator
# Trigger the appointment
@@ -177,7 +177,7 @@ def test_appointment_wrong_key(bitcoin_cli, create_txs):
def test_two_identical_appointments(monkeypatch, bitcoin_cli, create_txs):
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
# Tests sending two identical appointments to the tower.
# At the moment there are no checks for identical appointments, so both will be accepted, decrypted and kept until
@@ -191,8 +191,8 @@ def test_two_identical_appointments(monkeypatch, bitcoin_cli, create_txs):
locator = compute_locator(commitment_tx_id)
# Send the appointment twice
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
# Broadcast the commitment transaction and mine a block
new_addr = bitcoin_cli.getnewaddress()
@@ -212,7 +212,7 @@ def test_two_identical_appointments(monkeypatch, bitcoin_cli, create_txs):
def test_two_appointment_same_locator_different_penalty(monkeypatch, bitcoin_cli, create_txs):
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
# This tests sending an appointment with two valid transaction with the same locator.
commitment_tx, penalty_tx1 = create_txs
@@ -227,8 +227,8 @@ def test_two_appointment_same_locator_different_penalty(monkeypatch, bitcoin_cli
appointment2_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx2)
locator = compute_locator(commitment_tx_id)
assert wt_cli.add_appointment([json.dumps(appointment1_data)]) is True
assert wt_cli.add_appointment([json.dumps(appointment2_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment1_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment2_data)]) is True
# Broadcast the commitment transaction and mine a block
new_addr = bitcoin_cli.getnewaddress()
@@ -245,25 +245,25 @@ def test_two_appointment_same_locator_different_penalty(monkeypatch, bitcoin_cli
assert appointment_info[0].get("penalty_rawtx") == penalty_tx1
def test_appointment_shutdown_pisa_trigger_back_online(monkeypatch, create_txs, bitcoin_cli):
global pisad_process
def test_appointment_shutdown_teos_trigger_back_online(monkeypatch, create_txs, bitcoin_cli):
global teosd_process
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
pisa_pid = pisad_process.pid
teos_pid = teosd_process.pid
commitment_tx, penalty_tx = create_txs
commitment_tx_id = bitcoin_cli.decoderawtransaction(commitment_tx).get("txid")
appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx)
locator = compute_locator(commitment_tx_id)
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
# Restart pisa
pisad_process.terminate()
pisad_process = run_pisad()
# Restart teos
teosd_process.terminate()
teosd_process = run_teosd()
assert pisa_pid != pisad_process.pid
assert teos_pid != teosd_process.pid
# Check that the appointment is still in the Watcher
appointment_info = get_appointment_info(locator)
@@ -285,19 +285,19 @@ def test_appointment_shutdown_pisa_trigger_back_online(monkeypatch, create_txs,
assert appointment_info[0].get("status") == "dispute_responded"
def test_appointment_shutdown_pisa_trigger_while_offline(monkeypatch, create_txs, bitcoin_cli):
global pisad_process
def test_appointment_shutdown_teos_trigger_while_offline(monkeypatch, create_txs, bitcoin_cli):
global teosd_process
monkeypatch.setattr(wt_cli, "load_keys", get_pisa_pk)
monkeypatch.setattr(teos_cli, "load_keys", get_teos_pk)
pisa_pid = pisad_process.pid
teos_pid = teosd_process.pid
commitment_tx, penalty_tx = create_txs
commitment_tx_id = bitcoin_cli.decoderawtransaction(commitment_tx).get("txid")
appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx)
locator = compute_locator(commitment_tx_id)
assert wt_cli.add_appointment([json.dumps(appointment_data)]) is True
assert teos_cli.add_appointment([json.dumps(appointment_data)]) is True
# Check that the appointment is still in the Watcher
appointment_info = get_appointment_info(locator)
@@ -306,13 +306,13 @@ def test_appointment_shutdown_pisa_trigger_while_offline(monkeypatch, create_txs
assert appointment_info[0].get("status") == "being_watched"
# Shutdown and trigger
pisad_process.terminate()
teosd_process.terminate()
new_addr = bitcoin_cli.getnewaddress()
broadcast_transaction_and_mine_block(bitcoin_cli, commitment_tx, new_addr)
# Restart
pisad_process = run_pisad()
assert pisa_pid != pisad_process.pid
teosd_process = run_teosd()
assert teos_pid != teosd_process.pid
# The appointment should have been moved to the Responder
sleep(1)
@@ -322,4 +322,4 @@ def test_appointment_shutdown_pisa_trigger_while_offline(monkeypatch, create_txs
assert len(appointment_info) == 1
assert appointment_info[0].get("status") == "dispute_responded"
pisad_process.terminate()
teosd_process.terminate()

View File

@@ -9,9 +9,9 @@ from threading import Thread
from coincurve import PrivateKey
from common.blob import Blob
from pisa.responder import TransactionTracker
from pisa.tools import bitcoin_cli
from pisa.db_manager import DBManager
from teos.responder import TransactionTracker
from teos.tools import bitcoin_cli
from teos.db_manager import DBManager
from common.appointment import Appointment
from common.tools import compute_locator
@@ -19,7 +19,7 @@ from bitcoind_mock.transaction import create_dummy_transaction
from bitcoind_mock.bitcoind import BitcoindMock
from bitcoind_mock.conf import BTC_RPC_HOST, BTC_RPC_PORT
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
import common.cryptographer
from common.logger import Logger
from common.constants import LOCATOR_LEN_HEX
@@ -151,7 +151,7 @@ def generate_dummy_tracker():
def get_config():
data_folder = os.path.expanduser("~/.pisa_btc")
data_folder = os.path.expanduser("~/.teos")
config = {
"BTC_RPC_USER": "username",
"BTC_RPC_PASSWD": "password",
@@ -165,8 +165,8 @@ def get_config():
"MAX_APPOINTMENTS": 100,
"EXPIRY_DELTA": 6,
"MIN_TO_SELF_DELAY": 20,
"SERVER_LOG_FILE": data_folder + "pisa.log",
"PISA_SECRET_KEY": data_folder + "pisa_sk.der",
"SERVER_LOG_FILE": data_folder + "teos.log",
"TEOS_SECRET_KEY": data_folder + "teos_sk.der",
"DB_PATH": "appointments",
}

View File

@@ -4,14 +4,14 @@ import requests
from time import sleep
from threading import Thread
from pisa.api import API
from pisa.watcher import Watcher
from pisa.responder import Responder
from pisa.tools import bitcoin_cli
from pisa import HOST, PORT
from pisa.chain_monitor import ChainMonitor
from teos.api import API
from teos.watcher import Watcher
from teos.responder import Responder
from teos.tools import bitcoin_cli
from teos import HOST, PORT
from teos.chain_monitor import ChainMonitor
from test.pisa.unit.conftest import (
from test.teos.unit.conftest import (
generate_block,
generate_blocks,
get_random_value_hex,
@@ -23,7 +23,7 @@ from test.pisa.unit.conftest import (
from common.constants import LOCATOR_LEN_BYTES
PISA_API = "http://{}:{}".format(HOST, PORT)
TEOS_API = "http://{}:{}".format(HOST, PORT)
MULTIPLE_APPOINTMENTS = 10
appointments = []
@@ -58,7 +58,7 @@ def new_appt_data():
def add_appointment(new_appt_data):
r = requests.post(url=PISA_API, json=json.dumps(new_appt_data), timeout=5)
r = requests.post(url=TEOS_API, json=json.dumps(new_appt_data), timeout=5)
if r.status_code == 200:
appointments.append(new_appt_data["appointment"])
@@ -78,7 +78,7 @@ def test_add_appointment(run_api, run_bitcoind, new_appt_data):
def test_request_random_appointment():
r = requests.get(url=PISA_API + "/get_appointment?locator=" + get_random_value_hex(LOCATOR_LEN_BYTES))
r = requests.get(url=TEOS_API + "/get_appointment?locator=" + get_random_value_hex(LOCATOR_LEN_BYTES))
assert r.status_code == 200
received_appointments = json.loads(r.content)
@@ -113,7 +113,7 @@ def test_add_too_many_appointment(new_appt_data):
def test_get_all_appointments_watcher():
r = requests.get(url=PISA_API + "/get_all_appointments")
r = requests.get(url=TEOS_API + "/get_all_appointments")
assert r.status_code == 200 and r.reason == "OK"
received_appointments = json.loads(r.content)
@@ -137,7 +137,7 @@ def test_get_all_appointments_responder():
generate_blocks(6)
# Get all appointments
r = requests.get(url=PISA_API + "/get_all_appointments")
r = requests.get(url=TEOS_API + "/get_all_appointments")
received_appointments = json.loads(r.content)
# Make sure there is not pending locator in the watcher
@@ -154,7 +154,7 @@ def test_request_appointment_watcher(new_appt_data):
assert r.status_code == 200
# Next we can request it
r = requests.get(url=PISA_API + "/get_appointment?locator=" + new_appt_data["appointment"]["locator"])
r = requests.get(url=TEOS_API + "/get_appointment?locator=" + new_appt_data["appointment"]["locator"])
assert r.status_code == 200
# Each locator may point to multiple appointments, check them all
@@ -181,7 +181,7 @@ def test_request_appointment_responder(new_appt_data):
# Generate a block to trigger the watcher
generate_block()
r = requests.get(url=PISA_API + "/get_appointment?locator=" + new_appt_data["appointment"]["locator"])
r = requests.get(url=TEOS_API + "/get_appointment?locator=" + new_appt_data["appointment"]["locator"])
assert r.status_code == 200
received_appointments = json.loads(r.content)

View File

@@ -1,7 +1,7 @@
import pytest
from pisa.block_processor import BlockProcessor
from test.pisa.unit.conftest import get_random_value_hex, generate_block, generate_blocks, fork
from teos.block_processor import BlockProcessor
from test.teos.unit.conftest import get_random_value_hex, generate_block, generate_blocks, fork
hex_tx = (

View File

@@ -2,10 +2,10 @@ import pytest
from uuid import uuid4
from queue import Queue
from pisa.builder import Builder
from pisa.watcher import Watcher
from pisa.responder import Responder
from test.pisa.unit.conftest import (
from teos.builder import Builder
from teos.watcher import Watcher
from teos.responder import Responder
from test.teos.unit.conftest import (
get_random_value_hex,
generate_dummy_appointment,
generate_dummy_tracker,

View File

@@ -1,9 +1,9 @@
import pytest
from pisa.carrier import Carrier
from teos.carrier import Carrier
from bitcoind_mock.transaction import create_dummy_transaction
from test.pisa.unit.conftest import generate_blocks, get_random_value_hex
from pisa.rpc_errors import RPC_VERIFY_ALREADY_IN_CHAIN, RPC_DESERIALIZATION_ERROR
from test.teos.unit.conftest import generate_blocks, get_random_value_hex
from teos.rpc_errors import RPC_VERIFY_ALREADY_IN_CHAIN, RPC_DESERIALIZATION_ERROR
# FIXME: This test do not fully cover the carrier since the simulator does not support every single error bitcoind may

View File

@@ -3,10 +3,10 @@ import time
from queue import Queue
from threading import Thread, Event, Condition
from pisa.block_processor import BlockProcessor
from pisa.chain_monitor import ChainMonitor
from teos.block_processor import BlockProcessor
from teos.chain_monitor import ChainMonitor
from test.pisa.unit.conftest import get_random_value_hex, generate_block
from test.teos.unit.conftest import get_random_value_hex, generate_block
def test_init(run_bitcoind):

View File

@@ -1,11 +1,11 @@
import random
from uuid import uuid4
from pisa.responder import TransactionTracker
from pisa.cleaner import Cleaner
from teos.responder import TransactionTracker
from teos.cleaner import Cleaner
from common.appointment import Appointment
from test.pisa.unit.conftest import get_random_value_hex
from test.teos.unit.conftest import get_random_value_hex
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX

View File

@@ -4,8 +4,8 @@ import pytest
import shutil
from uuid import uuid4
from pisa.db_manager import DBManager
from pisa.db_manager import (
from teos.db_manager import DBManager
from teos.db_manager import (
WATCHER_LAST_BLOCK_KEY,
RESPONDER_LAST_BLOCK_KEY,
LOCATOR_MAP_PREFIX,
@@ -14,7 +14,7 @@ from pisa.db_manager import (
from common.constants import LOCATOR_LEN_BYTES
from test.pisa.unit.conftest import get_random_value_hex, generate_dummy_appointment
from test.teos.unit.conftest import get_random_value_hex, generate_dummy_appointment
@pytest.fixture(scope="module")

View File

@@ -1,18 +1,18 @@
from binascii import unhexlify
from pisa.errors import *
from pisa.inspector import Inspector
from teos.errors import *
from teos.inspector import Inspector
from common.appointment import Appointment
from pisa.block_processor import BlockProcessor
from pisa.conf import MIN_TO_SELF_DELAY
from teos.block_processor import BlockProcessor
from teos.conf import MIN_TO_SELF_DELAY
from test.pisa.unit.conftest import get_random_value_hex, generate_dummy_appointment_data, generate_keypair, get_config
from test.teos.unit.conftest import get_random_value_hex, generate_dummy_appointment_data, generate_keypair, get_config
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX
from common.cryptographer import Cryptographer
from common.logger import Logger
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
import common.cryptographer
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)

View File

@@ -7,15 +7,15 @@ from shutil import rmtree
from copy import deepcopy
from threading import Thread
from pisa.db_manager import DBManager
from pisa.responder import Responder, TransactionTracker
from pisa.block_processor import BlockProcessor
from pisa.chain_monitor import ChainMonitor
from pisa.tools import bitcoin_cli
from teos.db_manager import DBManager
from teos.responder import Responder, TransactionTracker
from teos.block_processor import BlockProcessor
from teos.chain_monitor import ChainMonitor
from teos.tools import bitcoin_cli
from common.constants import LOCATOR_LEN_HEX
from bitcoind_mock.transaction import create_dummy_transaction, create_tx_from_hex
from test.pisa.unit.conftest import generate_block, generate_blocks, get_random_value_hex
from test.teos.unit.conftest import generate_block, generate_blocks, get_random_value_hex
@pytest.fixture(scope="module")

View File

@@ -1,4 +1,4 @@
from pisa.tools import can_connect_to_bitcoind, in_correct_network, bitcoin_cli
from teos.tools import can_connect_to_bitcoind, in_correct_network, bitcoin_cli
from common.tools import check_sha256_hex_format

View File

@@ -4,23 +4,23 @@ from shutil import rmtree
from threading import Thread
from coincurve import PrivateKey
from pisa.watcher import Watcher
from pisa.responder import Responder
from pisa.tools import bitcoin_cli
from pisa.chain_monitor import ChainMonitor
from pisa.db_manager import DBManager
from teos.watcher import Watcher
from teos.responder import Responder
from teos.tools import bitcoin_cli
from teos.chain_monitor import ChainMonitor
from teos.db_manager import DBManager
from test.pisa.unit.conftest import (
from test.teos.unit.conftest import (
generate_blocks,
generate_dummy_appointment,
get_random_value_hex,
generate_keypair,
get_config,
)
from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS
from teos.conf import EXPIRY_DELTA, MAX_APPOINTMENTS
import common.cryptographer
from pisa import LOG_PREFIX
from teos import LOG_PREFIX
from common.logger import Logger
from common.tools import compute_locator
from common.cryptographer import Cryptographer