Commit Graph

70 Commits

Author SHA1 Message Date
cloudhead ae981ded6e
cli: Add `rad stats` command
Returns aggregate stats as JSON. Useful for tracking seed node metrics.
2024-01-23 15:50:32 +01:00
cloudhead f87dfba9cd
Rename `Id` to `RepoId`
Rename the type to make it clearer and consistent with `NodeId`.
2024-01-22 15:51:44 +01:00
cloudhead 045b3e7175
node: Increase process ulimit on start
Users have been having issues with the process soft file limit.
We set that to a reasonably high value to avoid problems.
2024-01-17 17:34:25 +01:00
cloudhead 76302ffec0
cli: Attempt to fix flaky test
We also move the seed config to the test module.
2024-01-17 12:35:04 +01:00
Fintan Halpenny f7b53139f4
radicle: add Config::seed constructor
Add a `Config` constructor for testing seed nodes that uses
`usize::MAX` for capacity.

This allows test scenarios to not drop messages due to rate limiting
-- all nodes are on the same IP address and rate limiting is performed
per IP address.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2024-01-12 16:21:49 +01:00
cloudhead e4f06e9c9d
cli: Improve `rad remote add`
By default, this command now:
* Follows the peer if not already followed
* Syncs refs of the peer, if it wasn't followed before
* Fetches refs into working copy

This functionality can be disabled via `--no-sync` and `--no-fetch`.
2024-01-08 17:28:01 +01:00
cloudhead 59f506dbb5
radicle: Fix bug in node.db query 2023-12-19 13:26:17 +01:00
cloudhead 6f7c2dca91
node: Introduce connection penalty system
Previously, we might ban a node if we're having trouble connecting to
it, but this could be due to internet connectivity issues.

We introduce a penalty score for nodes, that increases if there are
connection issues or the node misbehaves, and decreases on successful
connections.

When connected to new nodes, we sort them so that low-penalty nodes are
attempted first.
2023-12-15 16:00:09 +01:00
cloudhead d9a84de5ee
radicle: Simple database migration system
We create a system for migrating the our databases, as well as a first
migration, for adding a `penalty` field to the `nodes` table, which we
are going to need soon, as an example.
2023-12-15 12:04:54 +01:00
cloudhead 6ca7da2768
radicle: Rename many more methods using new naming 2023-12-06 10:02:00 +01:00
cloudhead 1b026ae0ee
node: Rename node `tracking` module 2023-12-06 10:00:45 +01:00
cloudhead f453090e27
cli: Consolidate policy/scope variants
* Policy::Track -> Policy::Allow
* Scope::Trusted -> Scope::Followed
2023-12-06 09:56:58 +01:00
cloudhead af095d53ca
radicle: Add foreign-key constraint for routing 2023-11-30 13:00:59 +01:00
cloudhead 6b04eff34c
radicle: Consolidate databases
Instead of having a routing database, and an addresses database,
consolidate that in a single database called `node.db`.

We also simplify database access, by providing a single type for opening
the database, and use traits to access the various functions.

We create a new `seed::Store` that has seed-related methods split out of
the `address::Store`.

Note that tracking is still in its own database currently, as it isn't
ephemeral state. This makes it easy to delete the new `node.db` without
risk of losing any important information.

To avoid renaming all database methods, we create a `Stores` wrapper
that allows us to access routing, addresses, seeds etc. without type
ambiguity.

This is a breaking change and requires `addresses.db` and `routing.db`
to be deleted.
2023-11-30 13:00:59 +01:00
cloudhead 59a08f21a4
radicle: Explorer and preferred seed configuration
Allows users to configure the default node explorer to use.
Allows users to configure their preferred seeds.
2023-11-30 10:46:32 +01:00
cloudhead dfe0cb4342
cli: Polish the `rad sync status` output 2023-11-22 17:40:51 +01:00
cloudhead 358324883c
node: Announce offline ref updates
Currently, if refs are updated while the node is stopped, these refs are
not immediately announced when the node starts, due to the node being
unaware of the updates.

To remedy this, on startup, we compare the refs we have in storage with
the refs we announced to the network. Since only our own refs could have
changed while the node was stopped, this change only applies to owned
refs. If we detect that storage has changed while the node was stopped,
we create ref announcements for the updated repos and store them in our
gossip database. These announcements will be included with other
historical gossip announcements when nodes connect to us.

To keep track of what was announced, we store our local node's sync
status in the database. This is also useful when using the `rad sync status`
command, as it tells us what oid our local node is at, and whether it
is aware of our local changes yet.

In addition to this, we make a small fix: previously, inventory and ref
announcements originating from our local node were not stored in the
announcement database. We ensure that they are via the new `announce`
method.
2023-11-20 17:54:36 +01:00
cloudhead d4ec2176bb
Update Rust toolchain to 1.74 2023-11-17 16:58:24 +01:00
cloudhead d3b0483f42
cli: Implement `rad sync status` command
This command shows the sync status of a repository by consulting the
database via the node.

To make it work, we call into the address store to update the
`repo-sync-status` table when receiving ref announcements that are
relevant to us.
2023-11-17 16:56:19 +01:00
cloudhead ca557909c2
radicle: Fix some serialization issues
For some inexplicable reason, deserializing doesn't work unless we use
our custom de-serializer for `LocalTime`.
2023-11-17 16:54:27 +01:00
cloudhead aa13f57e7d
radicle: Fix issues with the address store SQL 2023-11-17 16:54:27 +01:00
Fintan Halpenny 85d452b222
radicle: return RefsAt for announce_refs
It can be useful to return the `RefsAt` that was announced for this
node, for example, to compare it to node events.

Change the `Handle` method to return `RefsAt` so that when it is
called it returns the local node's `RefsAt`.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-11-17 16:29:02 +01:00
cloudhead cdcc7cfaf9
node: Emit events for gossip messages 2023-11-17 14:56:42 +01:00
cloudhead ea4104dbd7
node: Only process messages from known nodes
Previously, we would process any valid inventory or refs announcement.
This could cause problems for keeping sync statuses, as we could get
a refs announcement from a node that isn't in our database.

In practice, there is no good reason why we should receive a refs or
inventory announcement before the announcer's node announcement, unless
nodes are not following the protocol.

Implementing this change meant that many of the tests needed updating,
as it wasn't assumed that a node announcement was needed before
receiving inventories etc. from a peer.

We also had to implement a basic form of node address banning to make
the tests pass after this change.
2023-11-13 16:15:57 +01:00
cloudhead 0ae3c00cd7
Use cascading deletes for removal of node rows
Instead of manually removing all rows in the address table, use
cascading deletes.
2023-11-13 16:01:18 +01:00
cloudhead 9f45405c64
Add table and types for tracking sync status
We add the necessary database table to keep track of which node has
synced which of our repos. This will be useful for giving the user
information on the sync status of every local repository.
2023-11-13 12:03:24 +01:00
cloudhead b675185538
node: Improve control socket API
We improve the API so that error messages can be sent back and are
always expected as potential responses to commands. This means that
`CommandResult` is always the type that is sent for commands.

This includes some breaking changes, for example the default "success"
message is simply `{}` instead of `{"status":"ok"}`.
2023-11-13 11:02:45 +01:00
cloudhead f0754330c9
Update `sqlite` dependency to 0.32.0 2023-11-08 15:08:01 +01:00
cloudhead f9df360171
node: Persist historical gossip messages
Instead of storing received gossip messages in an in-memory `BTreeMap`,
we persist them to the database (`addresses.db`). There are two reasons
for this:

1. Node restarts do not wipe the state, meaning that it is much less
   likely that some gossip message will get lost before reaching all
   nodes.
2. This will allow us in the next commit to know how far behind we are
   after a restart, to be able to request the correct time range of
   gossip messages that we missed while offline.

Note that we now share the addresses.db file between two connections and
stores, which we don't do anywhere else. Having multiple connections to
the same database is fine, but the way we're having to do it is a bit
awkward. In a future patch, we could pull out the database schema from the
`address` module and rename the database to make things clearer.
2023-11-08 13:15:56 +01:00
Fintan Halpenny ef6ae0fa84
radicle: move service tracking config to radicle::node
The `service::tracking` module has nothing specific to the
radicle-node code. This means that it can be moved to radicle under
the `node::tracking` module.

This makes it more resuable in other contexts, for example, for
fetching logic.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-11-06 12:06:13 +01:00
Michalis Zampetakis 0b6ede69e7
node: Add `listen` option to node config 2023-11-01 12:59:29 +01:00
Alexis Sellier 1abce45d5d
node: Slightly increase rate limit defaults 2023-09-18 11:14:19 +02:00
Alexis Sellier a7cd7b25f5
node: Allow rate-limitting to be configurable 2023-09-18 11:14:19 +02:00
cloudhead 27f39514d4
node: Implement private repos
Private repos are implemented by extending the identity document with a
`visibility` attribute, that can either be `"public"` (default) or
`"private"`.

In case of `private` visibility, only the delegates are allowed to view
the repo, as well as any DIDs added to the allow list.

To implement repo visibility, we simply block fetches from and
announcements to peers for whom the repo should remain invisible.

Private repos are also not announced in the `inventory` message, since
the full list of peers that *may* have the repo is retrievable from the
repo identity. This could cause errors if eg. a peer who is allowed to
view the repo doesn't actually have it. However this is an ok trade-off
for now to keep the complexity low. For repos to truly be private, it's
important that the RIDs don't leak either.

Finally, we modify `radicle-httpd` for now to only list public repos.
Eventually, we would want to change this depending on whether an allowed
peer is authenticated with the service or not.

---

It's also worth mentioning why this approach was taken, vs. end-to-end
encryption. The reasons are as follows:

1. Nodes that do not have access to a private repo will generally not want to
   replicate encrypted data that they cannot examine or use.
2. The chosen solution is trivial, while encrypting git objects isn't.
3. Performance of the chosen solution is much better, there is no
   overhead.
4. Privacy of the chosen solution is better: RIDs are never leaked, and
   neither is the existence of a private repo, nor who has access to it.

There is one downside: Paying for storage of private repos is no better
in terms of privacy than what GitHub offers. Hosting providers will have
access to your private repos, if this solution is used.
2023-09-01 12:13:45 +02:00
cloudhead 8cb8398be9
Introduce `cargo-deny`
Add `deny.toml` with a few exceptions, and update certain dependencies
to get rid of duplicates.

Running `cargo deny check` will yield some warnings still, but no
errors.
2023-08-22 14:33:00 +02:00
cloudhead 15b50ce6a5
radicle: Fix config deserialization
This is a fix for the breaking changes introduced with `PeerConfig`.
2023-08-14 10:31:35 +02:00
cloudhead 14c204a11f
radicle: Fix flaky test due to randomness 2023-08-13 21:20:27 +02:00
cloudhead d973fd42f2
cli: Auto-connect on sync
This adds functionality so that on `rad sync` and `rad clone`, we
connect to known seeds if necessary, before attempting to fetch.

In passing, some related changes were made:

* The `rad sync` command's arguments were reworked:
  `--replicas <count>` can be used to specify a replica count when
    fetching
* The `rad patch` command no longer has a `--fetch` option
* It's now possible to tell the node not to automatically connect to
  peers in the background
* `AddressBook` is being used underneath `Seeds` to allow for shuffled
  iteration
2023-08-11 11:45:27 +02:00
cloudhead efb8de2728
Rename our custom `HashMap` to `RandomMap`
This makes it easier to distinguish with the stdlib.

Also, we add an env var that can control the RNG seed, for testing
purposes.
2023-08-10 16:51:02 +02:00
cloudhead fae518bca2
node: Improve `rad node connect` feedback
Only return once the connection is established or failed.

It's still not perfect, as several failure scenarios are not handled,
but it's an improvement.
2023-08-09 12:49:15 +02:00
cloudhead dc7d67c1e2
node: Ignore non-routable addresses
We ignore addresses that are not globally routable when receiving them
in node announcement message, unless they are coming from a local peer.
2023-08-09 12:39:33 +02:00
cloudhead e888398519
node: Populate address book with bootstrap nodes
As a starting point, we populate the address book (if empty) with some
bootstrap nodes which are trusted.

To prevent these nodes being connected to during tests (including e2e
tests), we create a new constructor for `Config` that is used in tests.

Note that a `cfg(test)` check is not enough given that e2e tests don't
have that set.
2023-08-09 12:39:33 +02:00
Alexis Sellier b953e9f6b5
node: Use `camelCase` for control socket data
It's easier if we use camel-case everywhere, because some types may be
used on the web as well as on the control socket. This way, all
json-encoded data looks the same.
2023-08-01 15:48:44 +02:00
Alexis Sellier 8a3133e137
node: Include addresses in `Command::Seeds` result
This will allow the CLI to connect to seeds on the go.

We also do some refactoring of some of the code involved in fulfilling
the `Seeds` command.
2023-08-01 15:48:44 +02:00
Alexis Sellier 85b092872d
node: Support DNS address types at the wire level 2023-08-01 14:55:20 +02:00
Alexis Sellier 41bff1b3bb
node: Make user connections persistent
While the node is running, connections made via the `Connect` command
should be retried.
2023-07-26 12:52:11 +02:00
Fintan Halpenny dfa7ba1df5
radicle: type safe tracking config
The tracking database can be opened in read-only or read-write
mode. Knowing which is being used is significant in concurrent
scenarios, e.g. it's safer to have a read-only handle on multiple
threads.

Provide static type information by signifying what kind of database
handle is being worked with, read or read-write.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-07-14 16:52:42 +02:00
Alexis Sellier 6b6f087c14
Use transaction to insert inventories
Instead of inserting inventory entries one by one, we use a transaction,
which is much faster.
2023-07-14 15:46:46 +02:00
Alexis Sellier eb701be033
node: Make node aliases required
This is a fairly substantial change, which adds a new configuration file
to the user's `$RAD_HOME` that includes node configuration, including
the alias, and also makes node aliases required.

When running `rad auth`, the user is now prompted for an alias, which
defaults to `$USER`.

When running `rad self`, the alias is now shown.

If the user runs radicle without a config file, the defaults are loaded,
and `$USER` is used as the alias.
2023-07-11 18:08:59 +02:00
Alexis Sellier 5502676aa7
Fixes and improvements to alias handling
* Return the correct alias from a node announcement, stripping '\0'
  bytes.
* Accept `AliasStore` types as references and as owned.
* Store a `null` in the database if the alias received is empty.
2023-06-13 11:09:42 +02:00