mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 06:04:21 +01:00
Merge pull request #143 from talaia-labs/watchtower-plugin
Watchtower plugin
This commit is contained in:
206
watchtower-plugin/README.md
Normal file
206
watchtower-plugin/README.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Watchtower client
|
||||||
|
|
||||||
|
This is a Watchtower client plugin to interact with an [Eye of Satoshi tower](https://github.com/talaia-labs/python-teos),
|
||||||
|
and eventually with any [BOLT13](https://github.com/sr-gi/bolt13/blob/master/13-watchtowers.md) compliant Watchtower.
|
||||||
|
|
||||||
|
The plugin manages all the client-side logic to send appointment to a number of registered towers every time a new
|
||||||
|
commitment transaction is generated. It also keeps a summary of the messages sent to the towers and their responses.
|
||||||
|
|
||||||
|
The plugin has the following methods:
|
||||||
|
|
||||||
|
- `registertower tower_id` : registers the user id (compressed public key) with a given tower.
|
||||||
|
- `list_towers`: lists all registered towers.
|
||||||
|
- `gettowerinfo tower_id`: gets all the locally stored data about a given tower.
|
||||||
|
- `retrytower tower_id`: tries to send pending appointment to a (previously) unreachable tower.
|
||||||
|
- `getappointment tower_id locator`: queries an appointment to a given tower.
|
||||||
|
|
||||||
|
The plugin also has an implicit method to send appointments to the registered towers for every new commitment transaction.
|
||||||
|
|
||||||
|
# Config file, data folder and first bootstrap
|
||||||
|
|
||||||
|
The plugin creates a data folder under the user's home folder (`~/.watchtower`), where all the plugin's data is stored. A config file (`watchtower.conf`) can be placed in the data folder to modify some of the configuration defaults (check [template.conf](template.conf)).
|
||||||
|
|
||||||
|
On first bootstrap, the plugin generates a key pair that is used as the user identifier. All requests from the user are signed using the secret key, so the tower can authenticate the user after the registration process (`registertower`).
|
||||||
|
|
||||||
|
All the appointments generated by the tower, as well as all the registered towers' data, are stored on a `leveldb` under `~/.watchtower/towers`.
|
||||||
|
|
||||||
|
# Getting started
|
||||||
|
|
||||||
|
## Registering with a tower
|
||||||
|
|
||||||
|
Once the plugin is loaded in your node, the first step is to register your node with an active tower. You can do so by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli registertower tower_id [host, port]
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `tower_id` represents the target tower public key. As a convenience, `tower_id` may be of the form `tower_id@host` or `id@host:port`. In this case, the host and port parameters must be omitted. Port defaults to `9814` and can be changed in the config file.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli registertower 0230053e39c53b8bcb43354a4ed886b8082af1d1e8fc14956e60ad0592bfdfab51@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
If the tower is online, you should get back a response similar to this:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"available_slots": 10000,
|
||||||
|
"public_key": "02d5001fb4204fd9ab26f06c7869e3820906be565c5b449ecfb0251af4eff1c752",
|
||||||
|
"subscription_expiry": 4753
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `available_slots` is the amount of free slots the user has available in the tower, `public_key` is the user's public key (`user_id` for now on) and `subscription_expiry` is the block height when the subscription expires. Generally speaking, a slot fits an appointment, so in this example the user can send **10000** appointments in roughly **one month**.
|
||||||
|
|
||||||
|
Notice that, ideally, the client and the tower have to agree on the **subscription details** (`available_slots` and `subscription_expiry`). Currently, those depend only on the tower, since it is offering the service for free. However, in the current state, hitting `registertower` again will add another `10000` slots and reset the time to `current_height + roughtly_one_mont_in_blocks`.
|
||||||
|
|
||||||
|
## Sending data to the tower
|
||||||
|
Once your node is registered with at least one tower it will start sending appointments to the tower for every commitment transaction update on any of your channels. In the current version of the plugin, everything is sent to every registered tower (**full replication**). There is nothing to be done here, under normal conditions, the plugin takes care of it.
|
||||||
|
|
||||||
|
## Checking the state of the towers
|
||||||
|
|
||||||
|
To find out more information about registered towers, you can use `list_towers` and `gettowerinfo`:
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli listtowers
|
||||||
|
```
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"towers": [
|
||||||
|
{
|
||||||
|
"id": "0230053e39c53b8bcb43354a4ed886b8082af1d1e8fc14956e60ad0592bfdfab51",
|
||||||
|
"netaddr": "http://localhost:1234",
|
||||||
|
"status": "unreachable",
|
||||||
|
"available_slots": 9998,
|
||||||
|
"pending_appointments": [
|
||||||
|
"fff5ceaff045b0e4ddf11936d66c02a0",
|
||||||
|
"0698bd6c0e1f74c11857b99ef6009156"
|
||||||
|
],
|
||||||
|
"invalid_appointments": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The overview contains the `id` and network address of the tower (`netaddr`), as well as the current `status` and two list of appointments: **pending** and **invalid**.
|
||||||
|
|
||||||
|
The tower has 5 differents states:
|
||||||
|
|
||||||
|
- `reachable`: the tower is reachable at the given network address.
|
||||||
|
- `temporarily unreachable`: the tower is temporarily unreachable, meaning that one of the last requests sent to it has failed.
|
||||||
|
- `unreachable`: the tower has been unreachable for a while.
|
||||||
|
- `misbehaving`: the tower has sent us incorrect data.
|
||||||
|
- `subscription_error`: the subscription with the tower has expired or run out of slots.
|
||||||
|
|
||||||
|
The main difference between `temporarily unreachable` and `unreachable` is the amount of time that has passed since we last received a response. If a tower is temporarily unreachable, a backoff strategy is triggered and all the appointments that cannot be delivered are stored under `pending_appointments`. If the tower comes back online within the retry strategy, every pending appointment is sent through and the tower is flagged back as `reachable`. However, if the backoff strategy ends up giving up, the tower is flagged as `unreachable`.
|
||||||
|
|
||||||
|
If the client receives data from a tower that is not properly signed, the tower is flagged as `misbehaving` and it is abandoned, meaning that no more appointments are sent to it. This state should never be reached by honest towers.
|
||||||
|
|
||||||
|
A `subscription error` means that the subscription needs to be renewed (hit `registertower` again).
|
||||||
|
|
||||||
|
Regarding `pending_appointments` and `invalid_appointments` they store the data that is pending to be sent to the tower (for unreachable towers) and the appointments that have been rejected by the tower for being invalid, respectively. The latter should never get populated for honest clients.
|
||||||
|
|
||||||
|
`gettowerinfo` provides more detailed information about the tower:
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli gettowerinfo tower_id
|
||||||
|
```
|
||||||
|
|
||||||
|
**Call**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli gettowerinfo 0230053e39c53b8bcb43354a4ed886b8082af1d1e8fc14956e60ad0592bfdfab51
|
||||||
|
```
|
||||||
|
|
||||||
|
**Return**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"id": "03623859b406e83ec7fab195cd67f1ba9e6d46bc07fac3e900351d657dd8ad05aa",
|
||||||
|
"netaddr": "http://localhost:1234",
|
||||||
|
"available_slots": 9998,
|
||||||
|
"status": "unreachable",
|
||||||
|
"appointments": {
|
||||||
|
"3866ee02e6249454bba39fd52fbf673b": "rytpauxwoyic3ui47kojj7cjg415t8cws1nu3r9gj9h6dp5mpgkky9o9i8qfud5tguo85gyhfr7pjja368isq6di1c9ghic9pckz3838",
|
||||||
|
"1a03e9239a459d8166cd6b7dba781574": "d7b9ucq8rihduk8w6c3fmeq86hcmpk5kfoqoerpjpiob4fsc9kbiqi8uz484tk9bcxnehdn8prt9s8wrejh78pan995f6314sf6hht89"
|
||||||
|
},
|
||||||
|
"pending_appointments": [
|
||||||
|
{
|
||||||
|
"appointment": {
|
||||||
|
"locator": "fff5ceaff045b0e4ddf11936d66c02a0",
|
||||||
|
"to_self_delay": 20,
|
||||||
|
"encrypted_blob": "2cb558721e22c34d62aab6395aff3b0611f7ce29fbb8d699c998e4874649be01097ed910ffd6253738b4d565eb6b9f1df1dcb9f4fbe2c0b71fb56d497fe1e0a2a41647bfb1d88c7270d502f19472ef39de74e05e7651cd31c705e7daa5f3bd91151c25ef8def635e172f720baef1141f6291a660bdc2b702396f89b69254ccae9f92eb12ed3d6c782a4309eba0ab78cb1d7d8c39e7524c476777e5022e43b8f201aae0c69aaa6c8d9bd864ed1b16459967efbbb63b16ced56b585279c381fb9a03012d578bd90b9de2e718259ddeb4d3acb91eabe5328ac6089642a4efc248e7b940a2f68c8d106868514dfd29a5f3dd8d07ece518c604311425d4"
|
||||||
|
},
|
||||||
|
"signature": "rns7z4orgjninrfguygzuij5ndek5544kdoncudbx9kqcxk3gpjjyd3f7qmixygzobko3n1nqwqycmi89uo6d8e56k3iyd3trtihec7s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appointment": {
|
||||||
|
"locator": "0698bd6c0e1f74c11857b99ef6009156",
|
||||||
|
"to_self_delay": 20,
|
||||||
|
"encrypted_blob": "b77b5eb73b4901abe24427c7786233fce6aefb4655757802f7ff342a1ab90d8b20a65941038fbe4dba9c775f25650f6bb4c3f3caf6906c4b2c6b6bc09c943a61c57d14204e36a4094b92dc45492d0eaef7165ec5a7af4e8d33c38bfbeeb4e21e9fd699f1046ad0e0a442ff113b3d2f1e956cf912b075c4e0845d009c5913c06c6336c6dd1682e0a0ec696026970388c9a68a7e84d6c25b8346cb39bc0d0d3610beccee02fe999981be1c209d4efd0b2e966068e31c5f5e34507c739a849e1527c7102afbc610e344d6757db57fe3994119880856c6ab997a257ed477a66d5e95505052558b856e4b1df23e7d0ed49164c5063bc731c3ad6bc08a35"
|
||||||
|
},
|
||||||
|
"signature": "dhcr7jmokewgxnrdh4o6zaq3wxrfjdmkhj5y81rcff1utr7riut7kn7yzzoaxhsxezgu7xmq93fwsb1cc6ghbbrwxgwt5tyasr3aswf1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"invalid_appointments": [],
|
||||||
|
"misbehaving_proof": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that there are two new fields in this report: `appointments` and `misbehaving_proof`.
|
||||||
|
|
||||||
|
`appointments` contains a collection of `locator:tower_signature` pairs of all the appointments sent and accepted by the tower.
|
||||||
|
|
||||||
|
`misbehaving_proof` contains a proof of misbehaviour of the tower in the form of an `appointment:wrong_signature` pair. In this case the tower has not misbehaved, so it is empty.
|
||||||
|
|
||||||
|
Finally, notice how `pending_appointments` now contains all the data about the pending appointments (**the full appointment plus the signature**). The same applies to `invalid_appointments`.
|
||||||
|
|
||||||
|
## Manually retrying a tower
|
||||||
|
If a tower has been flagged as **unreachable** (after the default backoff has failed) or there has been a **subscription error**, the tower won't be tried again until the user manually requests so. This can be managed with the `retrytower` command:
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli retrytower tower_id
|
||||||
|
```
|
||||||
|
**Call**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli retrytower 03623859b406e83ec7fab195cd67f1ba9e6d46bc07fac3e900351d657dd8ad05aa
|
||||||
|
```
|
||||||
|
**Return**
|
||||||
|
|
||||||
|
```
|
||||||
|
"Retrying tower
|
||||||
|
03623859b406e83ec7fab195cd67f1ba9e6d46bc07fac3e900351d657dd8ad05aa"
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that this only works if the tower is in **unreachable** or **subscription error** state. A tower cannot be retried if it is already being retried (**temporarily unreachable**), or if it has **misbehaved**.
|
||||||
|
## Query data from a tower
|
||||||
|
Data can be queried from a tower to check, for instance, that the tower is keeping it or that it is correct. This can be done using the `getappointment` command:
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli getappointment 03623859b406e83ec7fab195cd67f1ba9e6d46bc07fac3e900351d657dd8ad05aa 3866ee02e6249454bba39fd52fbf673b
|
||||||
|
```
|
||||||
|
**Call**
|
||||||
|
|
||||||
|
```
|
||||||
|
lightning-cli getappointment 03623859b406e83ec7fab195cd67f1ba9e6d46bc07fac3e900351d657dd8ad05aa 3866ee02e6249454bba39fd52fbf673b
|
||||||
|
```
|
||||||
|
|
||||||
|
**Return**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"encrypted_blob": "e0622ceac74be1def70de5fdcaf0f498f9f9abae54cf2418358f8843eb22b683607ce298ea19f990fd74d9bf673c3d3c5a171fa6a2f635f6a2bbf06167504400000545ec192007811ef08027ff3dcec42058a3f309c0bb3b0f42990c0e46802b86cd7dba4053800d90766d3c050d1a38ed3a949f9bc02b30a641a43dd4566463607d4b5db1853ef6013e2df0b08cf5355a2f8f0aef23025a59f53e30f1aaad9c079d2f468b118f3450c33d015ba0d03d812328f5f16ef8ea4cefc75531f0f6e828b224c190980f1e7d8704853349a75e5d3e114c2cdf275b952e9c52457194dbf8991912ced217f20cc3f6a694a20cc5c274b984c48004777deba3",
|
||||||
|
"locator": "3866ee02e6249454bba39fd52fbf673b",
|
||||||
|
"status": "being_watched",
|
||||||
|
"to_self_delay": 20
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -29,7 +29,7 @@ class TowerInfo:
|
|||||||
self.appointments = {}
|
self.appointments = {}
|
||||||
self.pending_appointments = []
|
self.pending_appointments = []
|
||||||
self.invalid_appointments = []
|
self.invalid_appointments = []
|
||||||
self.misbehaving_proof = None
|
self.misbehaving_proof = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, tower_data):
|
def from_dict(cls, tower_data):
|
||||||
|
|||||||
Reference in New Issue
Block a user