Removes start/end time from appointment

This commit is contained in:
Sergi Delgado Segura
2020-04-14 16:53:35 +02:00
parent 9cbd9ed18a
commit 86e97e37bf
4 changed files with 12 additions and 120 deletions

View File

@@ -49,10 +49,10 @@ for opt, arg in opts:
``` ```
```python ```python
if rcode == 0: if appointment_data is None:
rcode, message = self.check_start_time(start_time, block_height) raise InspectionFailed(errors.APPOINTMENT_EMPTY_FIELD, "empty appointment received")
if rcode == 0: elif not isinstance(appointment_data, dict):
rcode, message = self.check_end_time(end_time, start_time, block_height) raise InspectionFailed(errors.APPOINTMENT_WRONG_FIELD, "wrong appointment format")
``` ```
## Dev Requirements ## Dev Requirements

View File

@@ -44,8 +44,6 @@ This command is used to send appointments to the watchtower. Appointments **must
{ "tx": tx, { "tx": tx,
"tx_id": tx_id, "tx_id": tx_id,
"start_time": s,
"end_time": e,
"to_self_delay": d } "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` **must** be the raw penalty transaction that will be encrypted before sent to the watchtower. `type(tx) = hex encoded str`
@@ -60,12 +58,6 @@ This command is used to send appointments to the watchtower. Appointments **must
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. 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 #### Usage
@@ -103,9 +95,7 @@ if `-f, --file` **is** specified, then the command expects a path to a json file
"appointment": "appointment":
{ {
"encrypted_blob": eb, "encrypted_blob": eb,
"end_time": e,
"locator": appointment_locator, "locator": appointment_locator,
"start_time": s,
"status": "being_watched", "status": "being_watched",
"to_self_delay": d "to_self_delay": d
} }
@@ -118,7 +108,6 @@ if `-f, --file` **is** specified, then the command expects a path to a json file
"status": "dispute_responded", "status": "dispute_responded",
"appointment": "appointment":
{ {
"appointment_end": e,
"dispute_txid": dispute_txid, "dispute_txid": dispute_txid,
"locator": appointment_locator, "locator": appointment_locator,
"penalty_rawtx": penalty_rawtx, "penalty_rawtx": penalty_rawtx,
@@ -164,10 +153,10 @@ python teos_cli.py register
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. 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 echo '{"tx": "4615a58815475ab8145b6bb90b1268a0dbb02e344ddd483f45052bec1f15b1951c1ee7f070a0993da395a5ee92ea3a1c184b5ffdb2507164bf1f8c1364155d48bdbc882eee0868ca69864a807f213f538990ad16f56d7dfb28a18e69e3f31ae9adad229e3244073b7d643b4597ec88bf247b9f73f301b0f25ae8207b02b7709c271da98af19f1db276ac48ba64f099644af1ae2c90edb7def5e8589a1bb17cc72ac42ecf07dd29cff91823938fd0d772c2c92b7ab050f8837efd46197c9b2b3f", "tx_id": "0b9510d92a50c1d67c6f7fc5d47908d96b3eccdea093d89bcbaf05bcfebdd951", "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. That will create a json file that follows the appointment data structure filled with dummy data and store it in `dummy_appointment_data.json`.
3. Send the appointment to the tower API. Which will then start monitoring for matching transactions. 3. Send the appointment to the tower API. Which will then start monitoring for matching transactions.

View File

@@ -9,18 +9,14 @@ class Appointment:
Args: Args:
locator (:obj:`str`): A 16-byte hex-encoded value used by the tower to detect channel breaches. It serves as a locator (:obj:`str`): A 16-byte hex-encoded value used by the tower to detect channel breaches. It serves as a
trigger for the tower to decrypt and broadcast the penalty transaction. trigger for the tower to decrypt and broadcast the penalty transaction.
start_time (:obj:`int`): The block height where the tower is hired to start watching for breaches.
end_time (:obj:`int`): The block height where the tower will stop watching for breaches.
to_self_delay (:obj:`int`): The ``to_self_delay`` encoded in the ``csv`` of the ``to_remote`` output of the to_self_delay (:obj:`int`): The ``to_self_delay`` encoded in the ``csv`` of the ``to_remote`` output of the
commitment transaction that this appointment is covering. commitment transaction that this appointment is covering.
encrypted_blob (:obj:`str`): An encrypted blob of data containing a penalty transaction. The tower will decrypt encrypted_blob (:obj:`str`): An encrypted blob of data containing a penalty transaction. The tower will decrypt
it and broadcast the penalty transaction upon seeing a breach on the blockchain. it and broadcast the penalty transaction upon seeing a breach on the blockchain.
""" """
def __init__(self, locator, start_time, end_time, to_self_delay, encrypted_blob): def __init__(self, locator, to_self_delay, encrypted_blob):
self.locator = locator self.locator = locator
self.start_time = start_time # ToDo: #4-standardize-appointment-fields
self.end_time = end_time # ToDo: #4-standardize-appointment-fields
self.to_self_delay = to_self_delay self.to_self_delay = to_self_delay
self.encrypted_blob = encrypted_blob self.encrypted_blob = encrypted_blob
@@ -33,7 +29,7 @@ class Appointment:
Args: Args:
appointment_data (:obj:`dict`): a dictionary containing the following keys: appointment_data (:obj:`dict`): a dictionary containing the following keys:
``{locator, start_time, end_time, to_self_delay, encrypted_blob}`` ``{locator, to_self_delay, encrypted_blob}``
Returns: Returns:
:obj:`Appointment <teos.appointment.Appointment>`: An appointment initialized using the provided data. :obj:`Appointment <teos.appointment.Appointment>`: An appointment initialized using the provided data.
@@ -43,16 +39,14 @@ class Appointment:
""" """
locator = appointment_data.get("locator") locator = appointment_data.get("locator")
start_time = appointment_data.get("start_time") # ToDo: #4-standardize-appointment-fields
end_time = appointment_data.get("end_time") # ToDo: #4-standardize-appointment-fields
to_self_delay = appointment_data.get("to_self_delay") to_self_delay = appointment_data.get("to_self_delay")
encrypted_blob_data = appointment_data.get("encrypted_blob") encrypted_blob_data = appointment_data.get("encrypted_blob")
if any(v is None for v in [locator, start_time, end_time, to_self_delay, encrypted_blob_data]): if any(v is None for v in [locator, to_self_delay, encrypted_blob_data]):
raise ValueError("Wrong appointment data, some fields are missing") raise ValueError("Wrong appointment data, some fields are missing")
else: else:
appointment = cls(locator, start_time, end_time, to_self_delay, encrypted_blob_data) appointment = cls(locator, to_self_delay, encrypted_blob_data)
return appointment return appointment
@@ -67,8 +61,6 @@ class Appointment:
# ToDO: #3-improve-appointment-structure # ToDO: #3-improve-appointment-structure
appointment = { appointment = {
"locator": self.locator, "locator": self.locator,
"start_time": self.start_time,
"end_time": self.end_time,
"to_self_delay": self.to_self_delay, "to_self_delay": self.to_self_delay,
"encrypted_blob": self.encrypted_blob, "encrypted_blob": self.encrypted_blob,
} }
@@ -80,17 +72,11 @@ class Appointment:
Serializes an appointment to be signed. Serializes an appointment to be signed.
The serialization follows the same ordering as the fields in the appointment: The serialization follows the same ordering as the fields in the appointment:
locator:start_time:end_time:to_self_delay:encrypted_blob locator:to_self_delay:encrypted_blob
All values are big endian. All values are big endian.
Returns: Returns:
:obj:`bytes`: The serialized data to be signed. :obj:`bytes`: The serialized data to be signed.
""" """
return ( return unhexlify(self.locator) + struct.pack(">I", self.to_self_delay) + unhexlify(self.encrypted_blob)
unhexlify(self.locator)
+ struct.pack(">I", self.start_time)
+ struct.pack(">I", self.end_time)
+ struct.pack(">I", self.to_self_delay)
+ unhexlify(self.encrypted_blob)
)

View File

@@ -65,8 +65,6 @@ class Inspector:
raise InspectionFailed(errors.UNKNOWN_JSON_RPC_EXCEPTION, "unexpected error occurred") raise InspectionFailed(errors.UNKNOWN_JSON_RPC_EXCEPTION, "unexpected error occurred")
self.check_locator(appointment_data.get("locator")) self.check_locator(appointment_data.get("locator"))
self.check_start_time(appointment_data.get("start_time"), block_height)
self.check_end_time(appointment_data.get("end_time"), appointment_data.get("start_time"), block_height)
self.check_to_self_delay(appointment_data.get("to_self_delay")) self.check_to_self_delay(appointment_data.get("to_self_delay"))
self.check_blob(appointment_data.get("encrypted_blob")) self.check_blob(appointment_data.get("encrypted_blob"))
@@ -100,87 +98,6 @@ class Inspector:
elif not is_locator(locator): elif not is_locator(locator):
raise InspectionFailed(errors.APPOINTMENT_WRONG_FIELD_FORMAT, "wrong locator format ({})".format(locator)) raise InspectionFailed(errors.APPOINTMENT_WRONG_FIELD_FORMAT, "wrong locator format ({})".format(locator))
@staticmethod
def check_start_time(start_time, block_height):
"""
Checks if the provided ``start_time`` is correct.
Start times must be ahead the current best chain tip.
Args:
start_time (:obj:`int`): the block height at which the tower is requested to start watching for breaches.
block_height (:obj:`int`): the chain height.
Raises:
:obj:`InspectionFailed`: if any of the fields is wrong.
"""
if start_time is None:
raise InspectionFailed(errors.APPOINTMENT_EMPTY_FIELD, "empty start_time received")
elif type(start_time) != int:
raise InspectionFailed(
errors.APPOINTMENT_WRONG_FIELD_TYPE, "wrong start_time data type ({})".format(type(start_time))
)
elif start_time < block_height:
raise InspectionFailed(errors.APPOINTMENT_FIELD_TOO_SMALL, "start_time is in the past")
elif start_time == block_height:
raise InspectionFailed(
errors.APPOINTMENT_FIELD_TOO_SMALL,
"start_time is too close to current height. Accepted times are: [current_height+1, current_height+6]",
)
elif start_time > block_height + 6:
raise InspectionFailed(
errors.APPOINTMENT_FIELD_TOO_BIG,
"start_time is too far in the future. Accepted start times are up to 6 blocks in the future",
)
@staticmethod
def check_end_time(end_time, start_time, block_height):
"""
Checks if the provided ``end_time`` is correct.
End times must be ahead both the ``start_time`` and the current best chain tip.
Args:
end_time (:obj:`int`): the block height at which the tower is requested to stop watching for breaches.
start_time (:obj:`int`): the block height at which the tower is requested to start watching for breaches.
block_height (:obj:`int`): the chain height.
Raises:
:obj:`InspectionFailed`: if any of the fields is wrong.
"""
# TODO: What's too close to the current height is not properly defined. Right now any appointment that ends in
# the future will be accepted (even if it's only one block away).
if end_time is None:
raise InspectionFailed(errors.APPOINTMENT_EMPTY_FIELD, "empty end_time received")
elif type(end_time) != int:
raise InspectionFailed(
errors.APPOINTMENT_WRONG_FIELD_TYPE, "wrong end_time data type ({})".format(type(end_time))
)
elif end_time > block_height + BLOCKS_IN_A_MONTH: # 4320 = roughly a month in blocks
raise InspectionFailed(
errors.APPOINTMENT_FIELD_TOO_BIG, "end_time should be within the next month (<= current_height + 4320)"
)
elif start_time > end_time:
raise InspectionFailed(errors.APPOINTMENT_FIELD_TOO_SMALL, "end_time is smaller than start_time")
elif start_time == end_time:
raise InspectionFailed(errors.APPOINTMENT_FIELD_TOO_SMALL, "end_time is equal to start_time")
elif block_height > end_time:
raise InspectionFailed(errors.APPOINTMENT_FIELD_TOO_SMALL, "end_time is in the past")
elif block_height == end_time:
raise InspectionFailed(errors.APPOINTMENT_FIELD_TOO_SMALL, "end_time is too close to current height")
def check_to_self_delay(self, to_self_delay): def check_to_self_delay(self, to_self_delay):
""" """
Checks if the provided ``to_self_delay`` is correct. Checks if the provided ``to_self_delay`` is correct.