Merge pull request #132 from talaia-labs/131-host-port-cofig

Adds API HOST and PORT as configurable parameters
This commit is contained in:
Sergi Delgado Segura
2020-04-20 17:24:29 +02:00
committed by GitHub
16 changed files with 279 additions and 50 deletions

View File

@@ -15,8 +15,8 @@ Refer to [INSTALL.md](INSTALL.md)
#### Global options #### Global options
- `-s, --server`: API server where to send the requests. Defaults to 'localhost' (modifiable in conf file). - `--apiconnect`: API server where to send the requests. Defaults to 'localhost' (modifiable in conf file).
- `-p, --port` : API port where to send the requests. Defaults to '9814' (modifiable in conf file). - `-apiport` : API port where to send the requests. Defaults to '9814' (modifiable in conf file).
- `-h --help`: shows a list of commands or help for a specific command. - `-h --help`: shows a list of commands or help for a specific command.
#### Commands #### Commands
@@ -191,10 +191,10 @@ By default, `teos_cli` will connect to your local instance (running on localhost
- mainnet endpoint = `teosmainnet.pisa.watch` - mainnet endpoint = `teosmainnet.pisa.watch`
### Connecting to the mainnet instance ### Connecting to the mainnet instance
Add `-s https://teosmainnet.pisa.watch` to your calls, for example: Add `--apiconnect https://teosmainnet.pisa.watch` to your calls, for example:
``` ```
python teos_cli.py -s https://teosmainnet.pisa.watch add_appointment -f dummy_appointment_data.json python teos_cli.py --apiconnect 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: You can also change the config file to avoid specifying the server every time:

210
cli/README.md.orig Normal file
View File

@@ -0,0 +1,210 @@
# teos_cli
`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)
## Installation
Refer to [INSTALL.md](INSTALL.md)
## Usage
python teos_cli.py [global options] command [command options] [arguments]
#### Global options
- `-s, --server`: API server where to send the requests. Defaults to 'localhost' (modifiable in conf file).
- `-p, --port` : API port where to send the requests. Defaults to '9814' (modifiable in conf file).
- `-h --help`: shows a list of commands or help for a specific command.
#### Commands
The command line interface has, currently, four commands:
- `register`: registers your user with the tower.
- `add_appointment`: sends a json formatted appointment to the tower.
- `get_appointment`: gets json formatted data about an appointment from the tower.
- `help`: shows a list of commands or help for a specific command.
### register
This commands serves as registration. It sends your public key to the tower to create a subscription (fee atm) and returns a number of available appointment slots in the tower. Toping up the subscription can be done by simply sending a register message again.
Notice that you need to be register before sending any other type of request to the tower.
#### Usage
python teos_cli.py register
### add_appointment
This command is used to send appointments to the watchtower. Appointments **must** be `json` encoded, and match the following format:
{ "tx": tx,
"tx_id": tx_id,
"start_time": s,
"end_time": e,
"to_self_delay": d }
`tx` **must** be the raw penalty transaction that will be encrypted before sent to the watchtower. `type(tx) = hex encoded str`
`tx_id` **must** match the **commitment transaction id**, and will be used to encrypt the **penalty transaction** and **generate the locator**. `type(tx_id) = hex encoded str`
`s` is the time when the watchtower will start watching your transaction, and will normally match to whenever you will be offline. `s` is measured in block height, and must be **higher than the current block height**. `type(s) = int`
`e` is the time where the watchtower will stop watching your transaction, and will normally match with whenever you should be back online. `e` is also measured in block height, and must be **higher than** `s`. `type(e) = int`
`d` is the time the watchtower would have to respond with the **penalty transaction** once the **dispute transaction** is seen in the blockchain. `d` must match with the `OP_CSV` specified in the dispute transaction. If the to\_self\_delay does not match the `OP_CSV`, the watchtower will try to respond with the penalty transaction anyway, but success is not guaranteed. `d` is measured in blocks and should be at least `20`. `type(d) = int`
The API will return a `application/json` HTTP response code `200/OK` if the appointment is accepted, with the locator encoded in the response text, or a `400/Bad Request` if the appointment is rejected, with the rejection reason encoded in the response text.
### Alpha release restrictions
The alpha release does not have authentication, payments nor rate limiting, therefore some self imposed restrictions apply:
- `start_time` should be within the next 6 blocks `[current_time+1, current_time+6]`.
- `end_time` cannot be bigger than (roughly) a month. That is `4320` blocks on top of `start_time`.
#### Usage
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.
#### Options
- `-f, --file path_to_json_file` loads the appointment data from the specified json file instead of command line.
### get_appointment
This command is used to get information about a specific appointment from the Eye of Satoshi.
**Appointment can be in three states:**
- `not_found`: meaning the locator is not recognised by the tower. This can either mean the locator is wrong, or the appointment has already been fulfilled (the tower does not keep track of completed appointments for now).
- `being_watched`: the appointment has been accepted by the tower and it's being watched at the moment. This stage means that the dispute transaction has not been seen yet, and therefore no penalty transaction has been broadcast.
- `dispute_responded`: the dispute was found by the watcher and the corresponding penalty transaction has been broadcast by the node. In this stage the tower is actively monitoring until the penalty transaction reaches enough confirmations and making sure no fork occurs in the meantime.
**Response formats**
**not_found**
{
"locator": l,
"status": "not_found"
}
**being_watched**
{
"locator": l,
"status": "being_watched",
"appointment":
{
"encrypted_blob": eb,
"end_time": e,
"locator": appointment_locator,
"start_time": s,
"status": "being_watched",
"to_self_delay": d
}
}
**dispute_responded**
{
"locator": l,
"status": "dispute_responded",
"appointment":
{
"appointment_end": e,
"dispute_txid": dispute_txid,
"locator": appointment_locator,
"penalty_rawtx": penalty_rawtx,
"penalty_txid": penalty_txid,
"status": "dispute_responded"
}
}
#### Usage
python teos_cli.py get_appointment <appointment_locator>
### get_all_appointments
This command is used to get information about all the appointments stored in a Eye of Satoshi tower.
**Responses**
This command returns all appointments stored in the watchtower. More precisely, it returns all the "response_trackers" and "watchtower_appointments" in a dictionary.
#### Usage
python teos_cli.py get_all_appointments
### help
Shows the list of commands or help about how to run a specific command.
#### Usage
python teos_cli.py help
or
python teos_cli.py help command
## Example
1. Register with the tower.
<<<<<<< HEAD
```
python teos_cli.py register
```
=======
```
python teos_cli.py register
```
>>>>>>> Adds register docs and removes API readme
2. Generate a new dummy appointment. **Note:** this appointment will never be fulfilled (it will eventually expire) since it does not correspond to a valid transaction. However it can be used to interact with the Eye of Satoshi's API.
```
echo '{"tx": "4615a58815475ab8145b6bb90b1268a0dbb02e344ddd483f45052bec1f15b1951c1ee7f070a0993da395a5ee92ea3a1c184b5ffdb2507164bf1f8c1364155d48bdbc882eee0868ca69864a807f213f538990ad16f56d7dfb28a18e69e3f31ae9adad229e3244073b7d643b4597ec88bf247b9f73f301b0f25ae8207b02b7709c271da98af19f1db276ac48ba64f099644af1ae2c90edb7def5e8589a1bb17cc72ac42ecf07dd29cff91823938fd0d772c2c92b7ab050f8837efd46197c9b2b3f", "tx_id": "0b9510d92a50c1d67c6f7fc5d47908d96b3eccdea093d89bcbaf05bcfebdd951", "start_time": 0, "end_time": 0, "to_self_delay": 20}' > dummy_appointment_data.json
```
That will create a json file that follows the appointment data structure filled with dummy data and store it in `dummy_appointment_data.json`. **Note**: You'll need to update the `start_time` and `end_time` to match valid block heights.
3. Send the appointment to the tower API. Which will then start monitoring for matching transactions.
```
python teos_cli.py add_appointment -f dummy_appointment_data.json
```
This returns an appointment locator that can be used to get updates about this appointment from the tower.
4. Test that the tower is still watching the appointment by replacing the appointment locator received into the following command:
```
python teos_cli.py get_appointment <appointment_locator>
```
## Try our live instance
By default, `teos_cli` will connect to your local instance (running on localhost). There are also a couple of live instances running, one for mainet and one for testnet:
- testnet endpoint = `teos.pisa.watch`
- mainnet endpoint = `teosmainnet.pisa.watch`
### Connecting to the mainnet instance
Add `-s https://teosmainnet.pisa.watch` to your calls, for example:
```
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:
`TEOS_SERVER = "https://teosmainnet.pisa.watch"`

View File

@@ -6,8 +6,8 @@ LOG_PREFIX = "cli"
# Load config fields # Load config fields
DEFAULT_CONF = { DEFAULT_CONF = {
"TEOS_SERVER": {"value": "localhost", "type": str}, "API_CONNECT": {"value": "localhost", "type": str},
"TEOS_PORT": {"value": 9814, "type": int}, "API_PORT": {"value": 9814, "type": int},
"LOG_FILE": {"value": "teos_cli.log", "type": str, "path": True}, "LOG_FILE": {"value": "teos_cli.log", "type": str, "path": True},
"APPOINTMENTS_FOLDER_NAME": {"value": "appointment_receipts", "type": str, "path": True}, "APPOINTMENTS_FOLDER_NAME": {"value": "appointment_receipts", "type": str, "path": True},
"CLI_PUBLIC_KEY": {"value": "cli_pk.der", "type": str, "path": True}, "CLI_PUBLIC_KEY": {"value": "cli_pk.der", "type": str, "path": True},

View File

@@ -2,7 +2,7 @@ class InvalidParameter(ValueError):
"""Raised when a command line parameter is invalid (either missing or wrong)""" """Raised when a command line parameter is invalid (either missing or wrong)"""
def __init__(self, msg, **kwargs): def __init__(self, msg, **kwargs):
self.msg = msg self.reason = msg
self.kwargs = kwargs self.kwargs = kwargs

View File

@@ -9,8 +9,8 @@ def show_usage():
"\n\tget_all_appointments \tGets information about all appointments stored in the tower." "\n\tget_all_appointments \tGets information about all appointments stored in the tower."
"\n\thelp \t\t\tShows a list of commands or help for a specific command." "\n\thelp \t\t\tShows a list of commands or help for a specific command."
"\n\nGLOBAL OPTIONS:" "\n\nGLOBAL OPTIONS:"
"\n\t-s, --server \tAPI server where to send the requests. Defaults to 'localhost' (modifiable in conf file)." "\n\t--apiconnect \tAPI server where to send the requests. Defaults to 'localhost' (modifiable in conf file)."
"\n\t-p, --port \tAPI port where to send the requests. Defaults to '9814' (modifiable in conf file)." "\n\t--apiport \tAPI port where to send the requests. Defaults to '9814' (modifiable in conf file)."
"\n\t-d, --debug \tshows debug information and stores it in teos_cli.log." "\n\t-d, --debug \tshows debug information and stores it in teos_cli.log."
"\n\t-h --help \tshows this message." "\n\t-h --help \tshows this message."
) )

View File

@@ -1,4 +1,4 @@
[teos] [teos]
TEOS_SERVER = localhost api_connect = localhost
TEOS_PORT = 9814 api_port = 9814

View File

@@ -166,7 +166,7 @@ def get_appointment(locator, cli_sk, teos_pk, teos_url):
# Send request to the server. # Send request to the server.
get_appointment_endpoint = "{}/get_appointment".format(teos_url) get_appointment_endpoint = "{}/get_appointment".format(teos_url)
logger.info("Sending appointment to the Eye of Satoshi") logger.info("Requesting appointment from the Eye of Satoshi")
response = process_post_response(post_request(data, get_appointment_endpoint)) response = process_post_response(post_request(data, get_appointment_endpoint))
return response return response
@@ -406,7 +406,7 @@ def main(command, args, command_line_conf):
setup_logging(config.get("LOG_FILE"), LOG_PREFIX) setup_logging(config.get("LOG_FILE"), LOG_PREFIX)
# Set the teos url # Set the teos url
teos_url = "{}:{}".format(config.get("TEOS_SERVER"), config.get("TEOS_PORT")) teos_url = "{}:{}".format(config.get("API_CONNECT"), config.get("API_PORT"))
# If an http or https prefix if found, leaves the server as is. Otherwise defaults to http. # If an http or https prefix if found, leaves the server as is. Otherwise defaults to http.
if not teos_url.startswith("http"): if not teos_url.startswith("http"):
teos_url = "http://" + teos_url teos_url = "http://" + teos_url
@@ -469,7 +469,7 @@ def main(command, args, command_line_conf):
except (FileNotFoundError, IOError, ConnectionError, ValueError) as e: except (FileNotFoundError, IOError, ConnectionError, ValueError) as e:
logger.error(str(e)) logger.error(str(e))
except (InvalidKey, InvalidParameter, TowerResponseError) as e: except (InvalidKey, InvalidParameter, TowerResponseError) as e:
logger.error(e.reason, **e.params) logger.error(e.reason, **e.kwargs)
except Exception as e: except Exception as e:
logger.error("Unknown error occurred", error=str(e)) logger.error("Unknown error occurred", error=str(e))
@@ -479,17 +479,17 @@ if __name__ == "__main__":
commands = ["register", "add_appointment", "get_appointment", "get_all_appointments", "help"] commands = ["register", "add_appointment", "get_appointment", "get_all_appointments", "help"]
try: try:
opts, args = getopt(argv[1:], "s:p:h", ["server", "port", "help"]) opts, args = getopt(argv[1:], "h", ["apiconnect=", "apiport=", "help"])
for opt, arg in opts: for opt, arg in opts:
if opt in ["-s", "--server"]: if opt in ["--apiconnect"]:
if arg: if arg:
command_line_conf["TEOS_SERVER"] = arg command_line_conf["API_CONNECT"] = arg
if opt in ["-p", "--port"]: if opt in ["--apiport"]:
if arg: if arg:
try: try:
command_line_conf["TEOS_PORT"] = int(arg) command_line_conf["API_PORT"] = int(arg)
except ValueError: except ValueError:
sys.exit("port must be an integer") sys.exit("port must be an integer")

View File

@@ -1,13 +1,13 @@
import os import os
HOST = "localhost"
PORT = 9814
DATA_DIR = os.path.expanduser("~/.teos/") DATA_DIR = os.path.expanduser("~/.teos/")
CONF_FILE_NAME = "teos.conf" CONF_FILE_NAME = "teos.conf"
LOG_PREFIX = "teos" LOG_PREFIX = "teos"
# Default conf fields # Default conf fields
DEFAULT_CONF = { DEFAULT_CONF = {
"API_BIND": {"value": "localhost", "type": str},
"API_PORT": {"value": 9814, "type": int},
"BTC_RPC_USER": {"value": "user", "type": str}, "BTC_RPC_USER": {"value": "user", "type": str},
"BTC_RPC_PASSWORD": {"value": "passwd", "type": str}, "BTC_RPC_PASSWORD": {"value": "passwd", "type": str},
"BTC_RPC_CONNECT": {"value": "127.0.0.1", "type": str}, "BTC_RPC_CONNECT": {"value": "127.0.0.1", "type": str},

View File

@@ -3,8 +3,8 @@ import logging
from math import ceil from math import ceil
from flask import Flask, request, abort, jsonify from flask import Flask, request, abort, jsonify
from teos import LOG_PREFIX
import teos.errors as errors import teos.errors as errors
from teos import HOST, PORT, LOG_PREFIX
from teos.inspector import InspectionFailed from teos.inspector import InspectionFailed
from teos.gatekeeper import NotEnoughSlots, IdentificationFailure from teos.gatekeeper import NotEnoughSlots, IdentificationFailure
@@ -79,7 +79,9 @@ class API:
access. access.
""" """
def __init__(self, inspector, watcher, gatekeeper): def __init__(self, host, port, inspector, watcher, gatekeeper):
self.host = host
self.port = port
self.inspector = inspector self.inspector = inspector
self.watcher = watcher self.watcher = watcher
self.gatekeeper = gatekeeper self.gatekeeper = gatekeeper
@@ -341,4 +343,4 @@ class API:
logging.getLogger("werkzeug").setLevel(logging.ERROR) logging.getLogger("werkzeug").setLevel(logging.ERROR)
os.environ["WERKZEUG_RUN_MAIN"] = "true" os.environ["WERKZEUG_RUN_MAIN"] = "true"
app.run(host=HOST, port=PORT) app.run(host=self.host, port=self.port)

View File

@@ -3,6 +3,8 @@ def show_usage():
"USAGE: " "USAGE: "
"\n\tpython teosd.py [global options]" "\n\tpython teosd.py [global options]"
"\n\nGLOBAL OPTIONS:" "\n\nGLOBAL OPTIONS:"
"\n\t--apibind \t\taddress that teos API will bind to. Defaults to 'localhost' (modifiable in conf file)."
"\n\t--apiport \t\tport that teos API will bind to. Defaults to '9814' (modifiable in conf file)."
"\n\t--btcnetwork \t\tNetwork bitcoind is connected to. Either mainnet, testnet or regtest. Defaults to " "\n\t--btcnetwork \t\tNetwork bitcoind is connected to. Either mainnet, testnet or regtest. Defaults to "
"'mainnet' (modifiable in conf file)." "'mainnet' (modifiable in conf file)."
"\n\t--btcrpcuser \t\tbitcoind rpcuser. Defaults to 'user' (modifiable in conf file)." "\n\t--btcrpcuser \t\tbitcoind rpcuser. Defaults to 'user' (modifiable in conf file)."

View File

@@ -11,6 +11,8 @@ feed_connect = 127.0.0.1
feed_port = 28332 feed_port = 28332
[teos] [teos]
api_bind = localhost
api_port = 9814
subscription_slots = 100 subscription_slots = 100
max_appointments = 1000000 max_appointments = 1000000
expiry_delta = 6 expiry_delta = 6

View File

@@ -154,7 +154,8 @@ def main(command_line_conf):
# FIXME: 92-block-data-during-bootstrap-db # FIXME: 92-block-data-during-bootstrap-db
chain_monitor.monitor_chain() chain_monitor.monitor_chain()
gatekeeper = Gatekeeper(UsersDBM(config.get("USERS_DB_PATH")), config.get("DEFAULT_SLOTS")) gatekeeper = Gatekeeper(UsersDBM(config.get("USERS_DB_PATH")), config.get("DEFAULT_SLOTS"))
API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")), watcher, gatekeeper).start() inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY"))
API(config.get("API_BIND"), config.get("API_PORT"), inspector, watcher, gatekeeper).start()
except Exception as e: except Exception as e:
logger.error("An error occurred: {}. Shutting down".format(e)) logger.error("An error occurred: {}. Shutting down".format(e))
exit(1) exit(1)
@@ -167,9 +168,23 @@ if __name__ == "__main__":
opts, _ = getopt( opts, _ = getopt(
argv[1:], argv[1:],
"h", "h",
["btcnetwork=", "btcrpcuser=", "btcrpcpassword=", "btcrpcconnect=", "btcrpcport=", "datadir=", "help"], [
"apiconnect=",
"apiport=",
"btcnetwork=",
"btcrpcuser=",
"btcrpcpassword=",
"btcrpcconnect=",
"btcrpcport=",
"datadir=",
"help",
],
) )
for opt, arg in opts: for opt, arg in opts:
if opt in ["--apibind"]:
command_line_conf["API_BIND"] = arg
if opt in ["--apiport"]:
command_line_conf["API_PORT"] = arg
if opt in ["--btcnetwork"]: if opt in ["--btcnetwork"]:
command_line_conf["BTC_NETWORK"] = arg command_line_conf["BTC_NETWORK"] = arg
if opt in ["--btcrpcuser"]: if opt in ["--btcrpcuser"]:

View File

@@ -75,7 +75,7 @@ class UsersDBM(DBManager):
user_pk (:obj:`str`): a 33-byte hex-encoded string identifying the user. user_pk (:obj:`str`): a 33-byte hex-encoded string identifying the user.
Returns: Returns:
:obj:`dict`: A dictionary containing the appointment data if the ``key`` is found. :obj:`dict`: A dictionary containing the user data if the ``key`` is found.
Returns ``None`` otherwise. Returns ``None`` otherwise.
""" """
@@ -105,7 +105,7 @@ class UsersDBM(DBManager):
return True return True
except TypeError: except TypeError:
logger.info("Cant delete user from db, user key has wrong type", uuid=user_pk) logger.info("Cannot delete user from db, user key has wrong type", uuid=user_pk)
return False return False
def load_all_users(self): def load_all_users(self):

View File

@@ -30,7 +30,7 @@ dummy_teos_sk = PrivateKey.from_int(2)
dummy_teos_pk = dummy_teos_sk.public_key dummy_teos_pk = dummy_teos_sk.public_key
another_sk = PrivateKey.from_int(3) another_sk = PrivateKey.from_int(3)
teos_url = "http://{}:{}".format(config.get("TEOS_SERVER"), config.get("TEOS_PORT")) teos_url = "http://{}:{}".format(config.get("API_CONNECT"), config.get("API_PORT"))
add_appointment_endpoint = "{}/add_appointment".format(teos_url) add_appointment_endpoint = "{}/add_appointment".format(teos_url)
register_endpoint = "{}/register".format(teos_url) register_endpoint = "{}/register".format(teos_url)
get_appointment_endpoint = "{}/get_appointment".format(teos_url) get_appointment_endpoint = "{}/get_appointment".format(teos_url)

View File

@@ -28,7 +28,7 @@ from test.teos.e2e.conftest import (
cli_config = get_config(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF) cli_config = get_config(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF)
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix="") common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix="")
teos_base_endpoint = "http://{}:{}".format(cli_config.get("TEOS_SERVER"), cli_config.get("TEOS_PORT")) teos_base_endpoint = "http://{}:{}".format(cli_config.get("API_CONNECT"), cli_config.get("API_PORT"))
teos_add_appointment_endpoint = "{}/add_appointment".format(teos_base_endpoint) teos_add_appointment_endpoint = "{}/add_appointment".format(teos_base_endpoint)
teos_get_appointment_endpoint = "{}/get_appointment".format(teos_base_endpoint) teos_get_appointment_endpoint = "{}/get_appointment".format(teos_base_endpoint)
teos_get_all_appointments_endpoint = "{}/get_all_appointments".format(teos_base_endpoint) teos_get_all_appointments_endpoint = "{}/get_all_appointments".format(teos_base_endpoint)
@@ -108,7 +108,6 @@ def test_appointment_life_cycle(bitcoin_cli):
# Get the information from the tower to check that it matches # Get the information from the tower to check that it matches
appointment_info = get_appointment_info(locator) appointment_info = get_appointment_info(locator)
assert appointment_info is not None
assert appointment_info.get("status") == "being_watched" assert appointment_info.get("status") == "being_watched"
assert appointment_info.get("locator") == locator assert appointment_info.get("locator") == locator
assert appointment_info.get("appointment") == appointment.to_dict() assert appointment_info.get("appointment") == appointment.to_dict()
@@ -122,9 +121,7 @@ def test_appointment_life_cycle(bitcoin_cli):
# Trigger a breach and check again # Trigger a breach and check again
new_addr = bitcoin_cli.getnewaddress() new_addr = bitcoin_cli.getnewaddress()
broadcast_transaction_and_mine_block(bitcoin_cli, commitment_tx, new_addr) broadcast_transaction_and_mine_block(bitcoin_cli, commitment_tx, new_addr)
appointment_info = get_appointment_info(locator) appointment_info = get_appointment_info(locator)
assert appointment_info is not None
assert appointment_info.get("status") == "dispute_responded" assert appointment_info.get("status") == "dispute_responded"
assert appointment_info.get("locator") == locator assert appointment_info.get("locator") == locator
@@ -162,15 +159,16 @@ def test_multiple_appointments_life_cycle(bitcoin_cli):
# Create five appointments. # Create five appointments.
for commitment_tx, penalty_tx in zip(commitment_txs, penalty_txs): for commitment_tx, penalty_tx in zip(commitment_txs, penalty_txs):
appointment = {}
appointment["commitment_tx"] = commitment_tx
appointment["penalty_tx"] = penalty_tx
commitment_tx_id = bitcoin_cli.decoderawtransaction(commitment_tx).get("txid") commitment_tx_id = bitcoin_cli.decoderawtransaction(commitment_tx).get("txid")
appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx) appointment_data = build_appointment_data(bitcoin_cli, commitment_tx_id, penalty_tx)
appointment["appointment_data"] = appointment_data
locator = compute_locator(commitment_tx_id) locator = compute_locator(commitment_tx_id)
appointment["locator"] = locator appointment = {
"locator": locator,
"commitment_tx": commitment_tx,
"penalty_tx": penalty_tx,
"appointment_data": appointment_data,
}
appointments.append(appointment) appointments.append(appointment)
@@ -195,14 +193,16 @@ def test_multiple_appointments_life_cycle(bitcoin_cli):
responder_locators = [appointment["locator"] for uuid, appointment in responding.items()] responder_locators = [appointment["locator"] for uuid, appointment in responding.items()]
assert set(responder_locators) == set(breached_appointments) assert set(responder_locators) == set(breached_appointments)
# Now let's mine some blocks so these appointments reach the end of their lifecycle.
# Since we are running all the nodes remotely data may take more time than normal, and some confirmations may be
# missed, so we generate more than enough confirmations and add some delays.
new_addr = bitcoin_cli.getnewaddress() new_addr = bitcoin_cli.getnewaddress()
for _ in range(int(1.5 * END_TIME_DELTA) + 5): # Now let's mine some blocks so the appointment reaches its end.
sleep(1) for _ in range(END_TIME_DELTA):
bitcoin_cli.generatetoaddress(1, new_addr) bitcoin_cli.generatetoaddress(1, new_addr)
# The appointment is no longer in the tower
with pytest.raises(TowerResponseError):
for appointment in appointments:
get_appointment_info(appointment["locator"])
def test_appointment_malformed_penalty(bitcoin_cli): def test_appointment_malformed_penalty(bitcoin_cli):
# Lets start by creating two valid transaction # Lets start by creating two valid transaction

View File

@@ -3,7 +3,6 @@ from shutil import rmtree
from binascii import hexlify from binascii import hexlify
from teos.api import API from teos.api import API
from teos import HOST, PORT
import teos.errors as errors import teos.errors as errors
from teos.watcher import Watcher from teos.watcher import Watcher
from teos.inspector import Inspector from teos.inspector import Inspector
@@ -22,8 +21,9 @@ from common.constants import (
ENCRYPTED_BLOB_MAX_SIZE_HEX, ENCRYPTED_BLOB_MAX_SIZE_HEX,
) )
config = get_config()
TEOS_API = "http://{}:{}".format(HOST, PORT) TEOS_API = "http://{}:{}".format(config.get("API_HOST"), config.get("API_PORT"))
register_endpoint = "{}/register".format(TEOS_API) register_endpoint = "{}/register".format(TEOS_API)
add_appointment_endpoint = "{}/add_appointment".format(TEOS_API) add_appointment_endpoint = "{}/add_appointment".format(TEOS_API)
get_appointment_endpoint = "{}/get_appointment".format(TEOS_API) get_appointment_endpoint = "{}/get_appointment".format(TEOS_API)
@@ -38,8 +38,6 @@ TWO_SLOTS_BLOTS = "A" * ENCRYPTED_BLOB_MAX_SIZE_HEX + "AA"
appointments = {} appointments = {}
locator_dispute_tx_map = {} locator_dispute_tx_map = {}
config = get_config()
client_sk, client_pk = generate_keypair() client_sk, client_pk = generate_keypair()
compressed_client_pk = hexlify(client_pk.format(compressed=True)).decode("utf-8") compressed_client_pk = hexlify(client_pk.format(compressed=True)).decode("utf-8")
@@ -62,8 +60,8 @@ def api(db_manager, carrier, block_processor, gatekeeper, run_bitcoind):
responder = Responder(db_manager, carrier, block_processor) responder = Responder(db_manager, carrier, block_processor)
watcher = Watcher(db_manager, block_processor, responder, sk.to_der(), MAX_APPOINTMENTS, config.get("EXPIRY_DELTA")) watcher = Watcher(db_manager, block_processor, responder, sk.to_der(), MAX_APPOINTMENTS, config.get("EXPIRY_DELTA"))
inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY"))
api = API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")), watcher, gatekeeper) api = API(config.get("API_HOST"), config.get("API_PORT"), inspector, watcher, gatekeeper)
return api return api