# Specifications for Stronghold-P2P
###### tags: `Stronghold` `P2P` `Spec`
***Date**: January 2022*
This document describes the specification for the refactored Stronghold-P2P library.
## Problem Domain / Requirements
**Fundamental requirements:**
- Allow to send requests and responses between peers
- Dynamically communicate with different / new peers during runtime
- Peers should be able to communicate even if a peer can not be reached directly
- It should be possible to send large messages (e.g. a whole snapshot)
- Support operations with multiple steps / requests (e.g. multi-sig)
- Efficient flow (e.g. not create & close connection for each new step)
- Should the High level have to initate each steps manually?
**Security requirements:**
- The system should be secured against unauthorized access
- Prevent unauthorized peers
- Prevent unauthorized types of requests (e.g. only Read is allowed but not Write)
- Grant temporary access
- The communication should be secret:
- Secured against an untrusted network
- Secured against other processes on the same device
- The system should introduce no additional weakness to the system that is using it
- The system should not expose any secrets
- Denial of Service attacks should be throttled
- Recognition of the real "communication partner" amidst potential attackers
**Interaction with the system:**
- Allow immediate interaction (e.g. to immediatly close a connection)
- The user should be able to get information about the system and its current state
- The user should always be informed if an operation was successful
- the address of a remote peer should only have to be added once, as long as it doesn't change
- the user should be informed if a peer can not be reached (anymore)
- the system should provide some sort of logging to allow debugging
**Suit different systems and devices:**
- Allow communication without internet access if the peers are on the same device or connected via a different medium (e.g. Ethernet over USB)
- Only basic requirements for the hardware (e.g. not depend on a camera to scan a QR code)
## Solution Domain / Specification
**Terminology**
- **Peer**: One participant in the network. In case of Stronghold, one Stronghold instance participates as one **Peer** in the network.
- **Source Peer**: The **Peer** that initiates the communication to a **Target Peer**.
- **Target Peer**: The **Peer** that received the data from the **Source Peer** and is expected to reply to it.
- **Remote Peer**: Any other **Peer** in the network outside of the local application/ system.
- **Peer Id**: SHA2-256 / Identity hash (of a public key) that serves as unique identifier for a **Peer** on the network.
- **Substream**: One active stream of data between two **Peers**. The same **Peers** can establish multiple substreams with each other.
- **Multi-address**: "Path" with multiple layers for addressing a **Peer** ([ref](https://docs.libp2p.io/concepts/addressing/)). One peer can have multiple **Multi-addresses**.
- **Transport**: Low layer that is responsible for establishing outbound connections, listening for inbound connections, and the transmission of data from and to remote **Peers**.
All communication between Peers is realized by sending direct 1:1 Request-Response messages.
Before any messages can be sent, Peers have to establish a connection with each other. The target peer has to actively listen to the transport with one or multiple multi-addresses, e.g. `/ip4/127.0.0.1/tcp/16384` in case of a TCP transport, and the source peer can dial into one of these addresses. When connecting, the peers negotiate the protocols that both of them support; at a minimum it is required that both peers support the Yamux protocol for multiplexing, and the Noise-protocol for authentication. The noise protocol is based on Diffie-Hellman key exchange, using the XX-handshake, which allows secure, end-to-end encrypted communication between the peers that don't have any prior knowledge of each other. It requires that a Keypair is provided, the supported schemes for this keypair are Ed25519, RSA and Secp256k1, and it is also used to derive the peer id of the peer. If a peer claims to have a peer id that doesn't match its public key, the noise protocol will reject the connection to that peer, hence peers can always trust that other peers are not claiming a false id.
For sending requests, the source peer has to support the *Request Protocol*: `Send Request - Receive Response`, and the target peer has to support the *Response Protocol*: `Receive Request - Send Response`. For each outgoing request, it is always expected that a response will be returned by the target peer, otherwise an error will be issued at both peers after a timeout duration.
On each established substream, both participating peers can individually decide for that substream what protcols they support, and therefore e.g. only allow sending requests with the *Request-Protocol*, and prevent to receive any request by not supporting the *Response-Protocol*. This configuration is managed by the firewall that will be described further below.
The Connection between two peers is only kept alive while requests or responses are send, otherwise it will be closed after a timeout. If a connection to a target peer is closed, but the multi-address of the peer is known, sending a request will initiate a new connection attempt to the remote peer.
Optionally, peers can also support the multicast DNS protocol for peer discovery in the same local network. It spawns a mDNS service that frequently queries the local network on a fixed service name to find other peers with their multi-address, this address is then used when attempting to send a requests.
#### Example Scenarios:
Cast:
- **A**: Source Peer
- **B**: Target Peer
- **Addr_B**: The multi-address of **B**
**Scenario 1**: **A** sends a request to **B** and receives a response for it
1. **B** starts listening on address **Addr_B**
2. **A** dials **Addr_B**
3. A connection between **A** and **B** is established
3.1 **A** and **B** negotiate a new Yamux substream
3.2 **A** and **B** perform a handshake to create a shared private key
4. **A** attempts to send a request to **B**, **B** receives the request
5. **B** sends a response back to **A**, **A** receives the response
**Scenario 2**: **A** sends a request to **B**, but **B** does not respond to it
1. **B** starts listening on address **Addr_B**
2. **A** dials **Addr_B**
3. A connection between **A** and **B** is established
4. **A** attempts to send the request to **B**, **B** receives the request
5. No response is send from **B**
6. an outbound timeout error is issued at **A**
7. an inbound response-omission error is issued at **B**
**Scenario 4**: **A** attempts to send a request to the previously connected **B** after the connection closed
1. **B** starts listening on address **Addr_B**
2. **A** dials **Addr_B**
3. A connection between **A** and **B** is established
4. No data is send, the connection gracefully closes after timeout
5. **A** attempts to send the request to **B**
6. the request is queued, **A** dials **B** on the already known **Addr_B**
7. A connection between **A** and **B** is established again
8. The request is send from **A** to **B**, **B** receives the request
9. **B** sends a response back to **A**, **A** receives the response
**Szenario 5**: Both peers support mDNS and discover each other with it
1. **B** starts listening on address **Addr_B**
2. **A** and **B** both send their information to the mDNS service
3. **A** and **B** each received the other peer's information from the mDNS service
4. **A** attempts to send the request to **B**
5. the request is queued, **A** dials **B** on **Addr_B** address received via mDNS
6. A connection between **A** and **B** is established
7. The request is send from **A** to **B**, **B** receives the request
8. **B** sends a response back to **A**, **A** receives the response
### Relay Specification
In many cases, two peers can not establish a direct connection with each other due to e.g. router firewall or different used transports. In these scenarios, a relay is required to allow communication.
**Additional Terminology**
- **Relay**: A Peer that forwards all traffic between the **Source Peer** and the **Target Peer**.
- **Relayed Address**: The **Multi-address** for connecting to a **Target Peer** via a **Relay**.
- **Dialing-Relay**: A **Relay** that is tried by the **Source Peer** if a **Target Peer** can not be reached directly.
- **Listening-Relay**: A **Relay** that the **Target Peer** uses for listening and actively keeps a long-lived connection to.
Any peer can serve as a relay, if both, the source and target, can reach that peer. The target peer has to actively start listening on a relayed address, which chains the address and peer id of the relay with the peer id of the target: `<relay-addr>/p2p/<relay-id>/p2p-circuit/p2p/<target-peer_id>`. If a peer is listening on a relayed address, a connection is established and kept alive between the relay and the target. The source peer can then dial the relayed address, which first establishes a connection to the relay, and then to the target via the relay. The relay is responsible for forwarding all traffic between the two peers, with the source and target both being aware that the traffic is relayed.
Because the noise-protocol allows to create a shared key over an insecure medium (the relay), the source and target can create a shared key without the relay obtaining any knowledge about the private key. Therefore, the whole communication is still end-to-end encrypted between source and target.
Peers maintain a list of dialing-relays. If a direct connection to the target can not be established due to no known addresses, invalid addresses, timeout, or an unsupported transport, each dialing-relay will be tried consecutively. If the source's dialing-relays overlaps with a listening-relay of the target, the connection attempt via that relay will be successful. A relay can be used by one peer for dialing and listening at the same time.
#### Example Scenario:
Cast:
- **A**: Source Peer
- **B**: Target Peer
- **R1**: Relay Peer 1
- **R2**: Relay Peer 2
- **R1Addr_B**: Relayed address of **B** via **R1**
- **R2Addr_B**: Relayed address of **B** via **R2**
**Scenario**: **A** uses **R1** and **R2** as dialing-relays, **B** only uses **R2** as listening-relay
1. **B** starts listening on address **R2Addr_B**
2. A connection between **B** and **R2** is established
3. **A** attempts to send a request to **B** but Error: no addresses known; request is queued
4. **A** attempts to connect to **R1Addr_B**
5. A connection between **A** and **R1** is established
6. connection attempt from **A** to **B** via **R1** fails
7. **A** attempts to connect to **R2Addr_B**
8. A connection between **A** and **R2** is established
9. A connection between **A** and **B** is established via **R2**
10. The request is send from **A** to **B** via **R2**, **B** receives the request
11. **B** sends a response back to **A** via **R2**, **A** receives the response
### Firewall Specification
The firewall validates all outgoing and incoming connections and requests depending on the configuration.
It includes default rules as well as rules for specific peers. The rules for one direction can allow all requests, no requests, or only specific request types (e.g. only read, but not write). If no requests are allowed on a substream, the appropriate *Request-* /*Response-Protocol* will not be supported to begin with, to prevent reading any malicous traffic from the substream. In some cases, it makes sense to not support any requests, but still listen to the transport, since the peer could e.g. serve as relay. If neither incoming, nor outgoing requests are allowed and the peer is not a relay itself or is listening on a relay, the connection will immediatly be closed. If only selected Request variants are allowed, each Request will be checked; unsupported variants of incoming request will be dropped, for unsupported outgoing requests an error will be returned.
Additionally, the rules for the default behaviour or specific peers can be set to ask for approval. In this case, an internal request for approval is reported, and the actual request will only be let on if an approval for that internal request was returned, otherwise it will be dropped.
#### Example Scenarios:
Cast:
- **A**: Source Peer
- **B**: Target Peer 1
- **C**: Target Peer 2
- **Addr_B**: The multi-address of **B**
- **Addr_C**: The multi-address of **C**
- **FA**: Firewall of **A**
- **FB**: Firewall of **B**
- **FC**: Firewall of **C**
**Scenario 1**: **A** attempts to connect to **B**, **FA** allows the request, **FB** rejects all incoming and outgoing requests
1. **B** starts listening on address **Addr_B**
2. **A** dials **Addr_B**
3. A connection between **A** and **B** is established
4. The connection between **A** and **B** is closed again by **B**
**Scenario 2**: **FA** allows outgoing requests to **C**, but not to **B**, **FB** and **FC** allow request from **A**
Assumption: **A** already established a connection to **B** and **C**
1. **A** attempts to send a request to **B**
2. **FA** rejects the request to **B**
3. **A** attempts to send a request to **C**
4. **FA** approves the request to **C**
5. **C** receives the request
6. **FC** approves the requst
7. **C** handles the request and sends a response back to **A** via **FC**, **A** receives the response
**Scenario 3**: **FA** allows the outgoing request but **FB** drops the request.
Assumption: **A** already established a connection to **B**
1. **A** attempts to send a request to **B**
2. **FA** approves the request
3. **B** receives the request
4. **FB** drops the request
5. an outbound timeout error is issued at **A**
**Scenario 4**: **A** attempts to send a request to **B**, but **B** does not support the *Response-Protocol* for any requests from **A**
Assumption: **A** already established a connection to **B**
1. **A** attempts to send a request to **B**
2. **FA** approves the request
3. the data is sent to **B**, but **B** does not read it
4. an outbound "unsupported-protocols" error is issued at **A**