# DEP 0007: Network Profiles

```
status: accepted
```

## Motivation

Currently, network settings such as `seeds`, `peers`, `inbound`,
`outbound_connection_timeout`, and others are not configured per
transport.

This leads to several UX issues. For instance, it's not possible
to specify different outbound connection timeouts for different
transports. As a result, a `tcp+tls` connection might be forced
to use the timeout configured for a `tor` transport, and similar
limitations apply to other settings.

Additionally, it's easier to misconfigure the setup—for example,
a user might inadvertently connect to `clearnet` seeds while using
the `tor` transport, since all seed addresses are grouped under a single
field without transport separation.

## Proposal

The current `toml` config for `net` settings looks like the following.
Note, only the parts that are proposed to be changed are shown here.

```toml
allowed_transports = ["tcp+tls"]

mixed_transports = []

inbound = ["tcp+tls://0.0.0.0:9600", "tcp+tls://[::]:9600"]

external_addrs = ["tcp+tls://my.resolveable.address:9600"]

seeds = [
    "tcp+tls://lilith0.dark.fi:9600",
    "tcp+tls://lilith1.dark.fi:9600",
    #"tor://g7fxelebievvpr27w7gt24lflptpw3jeeuvafovgliq5utdst6xyruyd.onion:9601",
    #"tor://yvklzjnfmwxhyodhrkpomawjcdvcaushsj6torjz2gyd7e25f3gfunyd.onion:9601",
]

peers = []

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 9
```

We propose introducing network profiles, allowing each supported
transport to be configured individually.

```toml
active_profiles = ["tor"]

mixed_profiles = []

[net.profiles."tcp+tls"]
seeds = ["tcp+tls://lilith0.dark.fi:9600", "tcp+tls://lilith1.dark.fi:9600"]

peers = []

inbound = ["tcp+tls://0.0.0.0:9600", "tcp+tls://[::]:9600"]

external_addrs = ["tcp+tls://my.resolveable.address:9600"]

[net.profiles."tor"]
seeds = [
    "tor://g7fxelebievvpr27w7gt24lflptpw3jeeuvafovgliq5utdst6xyruyd.onion:9601",
    "tor://yvklzjnfmwxhyodhrkpomawjcdvcaushsj6torjz2gyd7e25f3gfunyd.onion:9601",
]

peers = []

inbound = ["tor://127.0.0.1:9601"]

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 90

[net.profiles."i2p"]
seeds = [
    "i2p://6l2rdfriixo2nh5pr5bt555lyz56qox2ikzia4kuzm4okje7gtmq.b32.i2p:9602"
]

peers = []

inbound = ["tcp://127.0.0.1:9602"]

external_addrs = ["i2p://youraddress.b32.i2p:9602"]

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 90

[net.profiles."socks5"]
seeds = [
    "socks5://127.0.0.1:9050/g7fxelebievvpr27w7gt24lflptpw3jeeuvafovgliq5utdst6xyruyd.onion:9601",
    "socks5://127.0.0.1:9050/yvklzjnfmwxhyodhrkpomawjcdvcaushsj6torjz2gyd7e25f3gfunyd.onion:9601",
]

peers = []

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 90

[net.profiles."socks5+tls"]
seeds = [
    #"socks5+tls://127.0.0.1:9050/lilith0.dark.fi:9601",
    #"socks5+tls://127.0.0.1:1080/lilith1.dark.fi:9601"
]

peers = []

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 90

[net.profiles."tor+tls"]
seeds = [
    "tor+tls://lilith0.dark.fi:9600",
    "tor+tls://lilith1.dark.fi:9600"
]

peers = []

outbound_connect_timeout = 60
channel_handshake_timeout = 55
channel_heartbeat_interval = 90

[net.profiles."tcp"]
seeds = ["tcp://127.0.0.1:9600"]

peers = []

inbound = ["tcp://127.0.0.1:9600"]

external_addrs = ["tcp://127.0.0.1:9600"]
```

Each profile will have the following fields `seeds`, `peers`,
`inbound`, `external_addrs`, `outbound_connect_timeout`,
`channel_handshake_timeout`, `channel_heartbeat_interval`.

The `SettingsOpt` struct will be updated to include a new `profiles`
field of type `NetworkProfileOpt`. The fields in `NetworProfileOpt`
are moved from `SettingsOpt`. Additionally, the `allowed_transports`
field will be renamed to `active_profiles`, and `mixed_transports`
will be renamed to `mixed_profiles`.

```rust
#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
#[structopt()]
pub struct SettingsOpt {
    // --- REMOVED START ---
    #[serde(default)]
    #[structopt(long = "accept")]
    pub inbound: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub external_addrs: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub peers: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub seeds: Vec<Url>,

    #[structopt(skip)]
    pub outbound_connect_timeout: Option<u64>,

    #[structopt(skip)]
    pub channel_handshake_timeout: Option<u64>,

    #[structopt(skip)]
    pub channel_heartbeat_interval: Option<u64>,
    // --- REMOVED END ---

    // --- MODIFIED START ---
    #[serde(default)]
    #[structopt(long = "profiles")]
    pub active_profiles: Option<Vec<String>>,

    #[serde(default)]
    #[structopt(long = "mixed-profiles")]
    pub mixed_profiles: Option<Vec<String>>,
    // --- MODIFIED END ---

    // --- NEWLY ADDED START ---
    #[serde(default)]
    #[structopt(skip)]
    pub profiles: HashMap<String, NetworkProfileOpt>,
    // --- NEWLY ADDED END ---
}

#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
#[structopt()]
pub struct NetworkProfileOpt {
    #[serde(default)]
    #[structopt(long = "accept")]
    pub inbound: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub external_addrs: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub peers: Vec<Url>,

    #[serde(default)]
    #[structopt(long)]
    pub seeds: Vec<Url>,

    #[structopt(skip)]
    pub outbound_connect_timeout: Option<u64>,

    #[structopt(skip)]
    pub channel_handshake_timeout: Option<u64>,

    #[structopt(skip)]
    pub channel_heartbeat_interval: Option<u64>,
}
```

The `Settings` struct will also be updated to include a `profiles`
field of type `NetworkProfile`. The `NetworkProfile` struct will
correspond to and map the three fields defined in `NetworkProfileOpt`.

```rust
#[derive(Debug, Clone)]
pub struct Settings {
    //...
    pub profiles : HashMap<String, NetworkProfile>,
    //...
}

#[derive(Debug, Clone)]
pub struct NetworkProfile {
    pub outbound_connect_timeout: u64,

    pub channel_handshake_timeout: u64,

    pub channel_heartbeat_interval: u64,
}
```

We construct the `Settings` struct from `SettingsOpt` by filtering the
`profiles` hashmap using the `active_profiles` list. The `seeds`,
`peers`, `inbound_addrs`, and `external_addrs` fields are aggregated
from the filtered profiles and assigned to the corresponding fields in
`Settings`. These fields are not retained in `NetworkProfile`, as
they are not transport-specific.