Commit Graph

284 Commits

Author SHA1 Message Date
Fintan Halpenny d27cd0db0c
node: minimise refs announcement to key and Oid
The RefsAnnouncement previous announced its complete set of
`rad/sigrefs`. This was useful in that verification can occur on the
receiveing side immediately by verifying the refs and proceeding with
the fetch -- note that it did nothing with the ref information it
received.

This can be minimised to only advertising the namespace, i.e. the
NID, and the new SHA of the `rad/sigrefs`. This is represented by a
new message type, `RefsAt`, which contains the NID and the Oid.

For checking if an announcement is stale or fresh, the receiving
side can check the existence of the SHA in its Git repository.

The tests are appropriately modified to use NIDs and Oids.

To prepare for a follow-up change, the announcement data is also
threaded through for the fetch protocol to focus fetching only the
advertised set of Oids.

N.B.: because the refs aren't communicated, the verification happens
when fetching since the data needs to be fetched before
verifying. This is a trade-off with minimising the message payload for
verifying earlier.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-11-09 17:47:09 +01:00
cloudhead 947f1bfc01
node: Use variable subscribe backlog delta
Previously, we would always ask nodes for messages from one hour ago.
This meant that we could miss messages if our node was offline for more
than an hour. This change uses a variable backlog by checking the
timestamp of the last gossip message we received.
2023-11-08 15:10:11 +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 ea7f26dbdf
radicle: wire up radicle-fetch
Wire up the `radicle-fetch` crate to the fetch logic in the
`radicle-node` worker.

Any required traits for storage, identity, tracking, and transport
used by `radicle-fetch`.

The worker adds a new module to run the `git upload-pack` process and
pipes the `stdout`/`stdin` to the respective channels.

The `Worker` type required adding a `FetchConfig` to easily allow the
configuration of fetches and passing the signer and tracking store
location through to the fetch `Handle`.

The channels code is adapted to have a new writer that always flushes
when a call to `write_all` is made. This is necessary since the
Gitoxide code never calls `flush`, and so it will hang since no data
is sent until `flush` is called.

Since `UserInfo` is used to set up a newly cloned repository, this
changed some of the SHA1 hashes output in the CLI test examples. It
was also necessary to update the CLI's clone code to be deterministic
in its output for tests.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-11-06 12:06:13 +01:00
Fintan Halpenny 75b52e28b2
radicle: separate repository validation
Make the validation logic customisable by extracting it out into a
separate trait that can be defined by other crates.

The Repository validation logic stays the same.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-11-06 12:06:13 +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
cloudhead d150938b38
cli: Update tracking without a running node
This change allows users to track/untrack peers and repos without a
running node. This fixes a bug when running `rad init` without the node
running, where the repo would be tracked with a different scope than
what was specified on the CLI.
2023-11-03 17:17:07 +01:00
cloudhead 1d167581f2
cob: Introduce `xyz.radicle.id` COB
Introduces a new COB type to store repository identity documents.

The reason for this change is to:

1. Simplify the code, as the identity document logic resembled a COB,
   yet it had custom logic. This allows existing COB code to be used for
   identities.
2. Make identity document update logic more flexible, since COB actions
   can be added in the future.
3. Re-purpose existing tools around COBs to work on identities, eg. `rad
   cob`.
4. Unify the concept of an identity change proposal, with regular identity
   changes. This means we can remove the `id.proposal` COB in favor of
   using the `id` COB itself.

Notes
-----

* Each repository has one Identity COB.
* The `Proposal` COB has been repurposed into the `Identity` COB.
* Identity documents are stored as *embeds* inside the Identity COB
  actions.
* The action that contains new document versions is called `revision`,
  just like the Patches COB.
* The namespaced `rad/id` ref is a symbolic reference to that Identity
  COB.
* The canonical `rad/id` ref is a direct reference to the commit in the
  Identity COB that contains the latest *accepted* revision of the
  document.
* All commands for managing identities have been folded into `rad id`.
  Hence `rad delegate` and `rad edit` are removed.
* The concept of "rebasing" an identity document is gone.
* The `rad id` output has been updated to match the style of other
  commands.
* When a revision has enough signatures, it is automatically adopted as
  the current identity, there is no longer the need for a "commit"
  action.
* When an identity revision is proposed, and the current identity has a
  threshold of `1`, that identity is automatically accepted due to the
  above point.
* The idea of "verifying a peer's identity branch" no longer applies, as
  COBs cannot be verified one history at a time.
* Since the root commit of the Identity COB does not have a "Resource"
  to point to (it would have to point to itself, which is impossible),
  we've made the resource id optional for COBs.
2023-10-12 17:32:33 +02:00
Alexis Sellier a7cd7b25f5
node: Allow rate-limitting to be configurable 2023-09-18 11:14:19 +02:00
Alexis Sellier af724eeb0d
cli: Add `node config` command
Shows the current (loaded) node configuration.
2023-09-18 11:14:19 +02:00
cloudhead 09a284f09c
node: Make fetch timeout configurable
When a fetch is user-requested, a timeout can be supplied that is passed
down to the worker.

When a fetch is service-requested, a default timeout is used.
2023-09-01 12:13:45 +02:00
cloudhead a1df6d3748
cli: Add private repo support to `rad sync`
We can't use `node::seeds` for private repos.
2023-09-01 12:13:45 +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 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 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 fb4a4e0079
node: Implement token-bucket rate limitter
Limit gossip messages and inbound connections.
For now, we don't limit git fetches.
2023-08-09 12:41:21 +02:00
cloudhead 260b1a428c
node: Move `address` field out of `State`
We move the session address to the top-level struct, since it's needed
in a bunch of places. This change is required for the rate-limiting
code that is coming next.
2023-08-09 12:41:21 +02:00
cloudhead 66799e2211
node: Improve address selection
Improve the logic when choosing addresses to connect to. Previously we
would wait much too long, even for good addresses. This was especially a
problem when the reason for disconnection was simply a node restart.
2023-08-09 12:39:33 +02:00
cloudhead 508cf4f68c
node: Connect to peers on startup
We run `maintain_connections` on initialization so that we're
immediately connected to some peers from our address book.
2023-08-09 12:39:33 +02:00
cloudhead 27865a26b2
node: Improve `maintain_connections` function
Ensure we don't try to connect to two addresses of the same node.
2023-08-09 12:39:33 +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
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 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 1a1e63d998
node: Implement `sessions` command
Returns session information through the control socket.

We also update `rad node status` to display sessions.
2023-07-04 00:26:31 +02:00
Alexis Sellier ff7338de17
node: Always send node announcement on handshake
Previously, we only sent the announcement when there were external
addresses. But it contains other information like the node alias,
therefore we always send it.

Since the proof-of-work can be expensive to compute everytime, we add
the ability to load the local node announcement from the file system.

We also change the proof-of-work parameters so that they are relaxed
when running in debug mode, instead of when running tests.

Finally, we remove the boolean validation of the PoW. Instead, we store
the work per-node, in the database, to be used in the future in case of
DoS attacks or network congestion.
2023-06-07 11:39:23 +02:00
xphoniex f526465f1b
radicle: Make addresses.db accessible from profile
Signed-off-by: xphoniex <dj.2dixx@gmail.com>
2023-06-02 14:49:20 +02:00
Alexis Sellier 664aa570e6
node: Spawn a thread for each control connection
Previously, only one connection to the node control socket could be
handled at a time. This usually worked fine, but if one connection hangs
for whatever reason, no other process can access the node.
2023-05-24 11:33:55 +02:00
Alexis Sellier 5a46ded318
node: Allow seed not to be connected on fetch
See code comment for explanation.
2023-05-22 15:30:27 +02:00
Alexis Sellier d758c4f203
node: Move seeds log to better place
Instead of logging connected/disconnected seeds every time the seeds function
is called, we only log it when a user calls the function.
2023-05-11 10:36:30 +02:00
Alexis Sellier 1d9ee81b6d
node: Rename `reactor` module to `io`
The name was always confusing and didn't mean much in the contetx of the
service.
2023-05-08 19:31:20 +02:00
Alexis Sellier 0349699200
node: Don't connect to recently attempted peers 2023-05-05 17:23:52 +02:00
Alexis Sellier ca0abc4356
node: Keep track of connection attempts
When attempting to connect to a peer, and when succeeding, write the timestamp
to the database.

This will allow us to better select addresses and not retry peers to
soon.
2023-05-05 17:23:52 +02:00
Alexis Sellier 448ef67833
node: Add `Disconnect` command
This is useful especially in tests to disconnect two nodes. We also
expose `command` on the handle type (but not the trait).
2023-05-03 16:16:34 +02:00
Alexis Sellier df25e9a2a5
radicle: Fix unverified `Remote::new` constructor
We were allowing remotes to be constructed via a function that didn't
check its inputs.

This is now fixed by moving the public key into the `SignedRefs` struct.
2023-04-26 10:57:26 +02:00
Alexis Sellier 5428420f27
node: Rework peer map to not panic
In the wire protocol, we often panic in case a peer is not found.
With this change, we instead log an error.
2023-04-26 09:59:19 +02:00
Alexis Sellier 671c169244
node: Implement `rad sync` command
This command announces refs to peers and waits for them to be
in sync.

Adds a subscribe method to `Handle` so that we can get the events
from the seed to allow us to confirm that the configured seeds fetched
from us.
2023-04-24 11:39:37 +02:00
Alexis Sellier bf8653b6c2
node: Fix keep-alive delta
By having the keep-alive delta be the same as the ping timeout,
we essentially disconnected peers right after we sent them our
first ping.

This fixes that issue by setting the ping timeout to double the
keep-alive delta.
2023-04-21 16:54:03 +02:00
Alexis Sellier 26ee6d26dc
node: Reduce log messages when sending messages 2023-04-20 16:32:41 +02:00
Alexis Sellier 9120db4ddb
node: Reduce log verbosity when receiving messages 2023-04-20 16:32:41 +02:00
Alexis Sellier 189eb3f201
node: Cleanup logging 2023-04-20 16:32:41 +02:00
Alexis Sellier b51d491ad9
node: Preserve tracking policy on startup
We were needlessly overwriting the policy if it was set to "trusted".
2023-04-20 16:29:55 +02:00
Alexis Sellier 94bef61944
node: Return only remotes that were fetched from
Instead of returning the namespaces that we fetched with,
we return the remotes that were actually fetched from.

This can differ if some trusted peers were not available
on the remote node.

Previously, if that was the case, it would cause errors
since the remotes were looked up and that lookup failed.
2023-04-17 18:58:56 +02:00
Alexis Sellier bb07e25571
node: Emit event when refs are synced
This will help us give the user feedback when he pushes.
2023-04-17 16:18:34 +02:00
Alexis Sellier a8f0329391
node: Downgrade some logs to `trace` level
These logs were a bit noisy and don't help much.
2023-04-17 11:21:22 +02:00
Alexis Sellier f4257eb953
node: Add setting for limiting fetch concurrency
Can be passed via `--limit-fetch-concurrency <num>`.
2023-04-14 13:15:52 +02:00
Alexis Sellier 31647521fa
node: Properly close worker channels
We need to send a 'close' event to the worker channel for it to exit
without an error.

Also updated and improved a bunch of the logs.
2023-04-14 13:15:52 +02:00
Alexis Sellier 267aba5901
node: Announce inventory only if it changed
Previously we were announcing inventories all the time, due to
relying on the timestamp changing on insertion.

We change this to only announce our inventory when it actually changes.
2023-04-14 13:15:52 +02:00
Alexis Sellier 7cbfde1e9b
node: Don't needlessly fetch or announce
* We shouldn't announce if no refs were updated.
* We shouldn't blindly fetch if we don't know if we have an item in
  storage.
2023-04-14 13:15:52 +02:00
Alexis Sellier 89b9eb53b7
node: Implement protocol multiplexing
To improve the reliability and flexibility of the protocol, we introduce
multiplexing over peer connections. This involves a new `Frame` type
that carries a stream-id and payload.

Three stream types are made available:

1. Control
2. Gossip
3. Git

This change brings the following improvements:

* Removed need to queue fetch requests
* Removed need to queue gossip messages
* Removed need for `Fetch` and `FetchOk` messages
* Service doesn't need to know about inbound fetches
* Removed one round-trip for fetch negotiation
* Removed special `done` git packet
* Removed session logic and state around Git/Fetch protocols
* Removed code around upgrading/downgrading transport
* Worker in responder mode is able to process any number of fetches
* Connections support any number of concurrent fetches

We had to introduce a few extra things however to make it all work:

* A `VarInt` type for variable-length integers, since we want the frames
  to be lightweight.
* A custom "tunnel" implementation, since we couldn't use the existing
  one anymore.

Overall the change removes more complexity than it adds, while improving
the protocol along the way.
2023-04-10 14:41:55 +02:00
Alexis Sellier 3f389f37ea
node: Make sure we retry on lock contention
This fixes an issue that came up in tests where we would be reading
and writing to the database at the same time, and it would fail with
an error due to the lock being contended on.
2023-03-31 14:07:45 +02:00
Fintan Halpenny c618c3e443
node: remove Namespaces::One
The One variant caused many paint points for fetching logic, where it
was not necessary. It was only constructed in one place, which could
be replaced by using the variant that holds a set of keys.

Remove the Namespaces::One variant and rename Namespaces::Many to
Namespaces::Trusted.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-31 12:23:32 +01:00
Fintan Halpenny adf6312a55
node: fetch trusted peers on clone
When a repository does not yet exist during a fetch, i.e. a clone,
then only delegates are being fetched.

Augment Namespaces::Many to hold the trusted and optional delegate peers
separately. Doing so allows the construction of the variant without
the repository existing, but tracking relationships existing.

This variant can then be used to build refspecs for both the trusted
peers and delegates when doing a cloning fetch.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-31 12:23:31 +01:00
Alexis Sellier 973f618cd3
node: Fix routing table update on refs
The announcer is always the one who must have the refs, not the relayer.
This was changed in a recent patch.
2023-03-30 10:24:09 +02:00
Alexis Sellier 7c41c5edff
node: Replace most sleeps with events
With the new event system, we can replace the thread sleeps by
waiting for events. This should speed tests up a lot and
be more reliable.
2023-03-30 10:24:06 +02:00
Han Xu b030e9ea80
node: Only fetch from tracked nodes
The tracked nodes include nodes marked tracked in the db, and
the delegates and `Namespaces::All` if it is a new repo.

Signed-off-by: Han Xu <keepsimple@gmail.com>
2023-03-25 12:27:29 +01:00
Alexis Sellier da9d63b284
node: Fix fetch requests code
We were not correctly deleting the fetch request, since only one
was kept per RID.
2023-03-24 13:25:40 +01:00
Alexis Sellier d3f4189324
node: Fix reconnection logic
First, we make sure to always attempt reconnection to persistent peers,
no matter the reason.

Second, we don't re-attempt connections when an inbound peer
disconnects. This minimizes the chance of connections crossing.

Third, we clean up `session::Error`, and don't use it to signal a
missing session, since it doesn't really belong there.
2023-03-24 13:20:34 +01:00
Alexis Sellier 4438a10498
node: Change ping interval to 1 minute
30 seconds is too chatty.
2023-03-24 13:19:36 +01:00
Alexis Sellier bfea229850
node: Relax `Service` storage trait bound 2023-03-23 18:08:06 +01:00
Alexis Sellier c427f41379
node: Fix periodic inventory announcement
1. We were announcing inventory every 30 seconds. This is now changed
   to 1 hour.
2. We were using a variable to track whether our inventory has been
   announced to the network, but this var was set based on what we
   tracked, not the inventory we had. This var has been removed.
2023-03-22 22:03:59 +01:00
Han Xu 241c41a632
node: Queue pending fetches in Session
Pending fetches are drained one at a time after the previous fetch is
completed.

Signed-off-by: Han Xu <keepsimple@gmail.com>
2023-03-22 08:46:27 +01:00
Alexis Sellier ed1120f3eb
node: Don't relay redundant gossip messages
This change ensures that on `Subscribe`, we only relay the latest
announcement of each node, per announcement category.

Previously, we would relay all announcement, while only the last one
was relevant.
2023-03-17 17:10:10 +01:00
xphoniex a49eec9892
node: Add eventing system to `Handler` and `Service`
Signed-off-by: xphoniex <dj.2dixx@gmail.com>
2023-03-16 22:26:57 +01:00
Alexis Sellier c46bc0cc82
node: Start periodic tasks
This change ensures that we start the periodic tasks "loop" by
scheduling the first wakeup during initialization.
2023-03-16 15:26:13 +01:00
Alexis Sellier 5828b917f9
node: Fail fast when repository can't be read
It's not a good idea to have fallible operations run after `FetchOk`
is received, since there's no easy way to communicate the error
to the remote at that point. What would then happen is that the fetch
just "hangs", since nothing is there to cancel it.

Hence, we compute namespaces earlier in the process, and store the
namespaces in the session. If there is a failure, the fetch is
never initiated.
2023-03-15 16:22:43 +01:00
Alexis Sellier 05d7090326
node: Remove `Handle::inventory` method 2023-03-15 12:59:49 +01:00
Alexis Sellier 40c58b45ed
node: Move `routing` to `radicle` crate 2023-03-15 12:59:49 +01:00
Alexis Sellier b558c742e6
node: Rename `repo_entries` to `repo_policies`
Do the same thing for `node_entries` etc.
2023-03-15 12:59:49 +01:00
Alexis Sellier 9b6ede8fc5
cli: Use tracking DB access for `node` command 2023-03-15 12:59:49 +01:00
Alexis Sellier cf80f246b3
node: Fix bug in seed stats 2023-03-15 12:48:03 +01:00
Alexis Sellier cd12741bf2
node: Prevent redundant [re-]connections
It was possible to trigger multiple connection attempts to the same
peer, since we didn't track connection attempts that hadn't yet
returned to the service via `Service::attempted`.

With this change, we add an extra `Initial` state to sessions, so
that redundant connections are not attempted when one is already under
way.
2023-03-14 13:42:59 +01:00
Alexis Sellier 413238a1e0
node: Implement exponential back-off for reconnect
Instead of immediately attempting reconnection when a persistent
peer disconnects, wait some amount of time, increasing on every
attempt.
2023-03-13 17:43:49 +01:00
Alexis Sellier 8e5627d28a
node: Rename `tracked_repo` -> `repo_policies`
I was finding the current naming misleading, as the returned entries
could be for blocked repos/nodes.
2023-03-13 11:41:07 +01:00
Alexis Sellier 4f062ef2c6
node: Fetch missing inventory
Periodically, make sure we try to fetch inventory that is tracked
but missing from local storage.

We decide not to fetch immediately on `TrackRepo`, as this limits
the command's flexibility. For example, when `rad clone` is used,
we want to be able to fetch manually after tracking.
2023-03-13 11:38:33 +01:00
Alexis Sellier db38f2df76
node: Handle `FetchOk` never being received
It's possible for a peer to disconnect before responding with `FetchOk`.
In that case, we make sure to return to any pending fetch request with
an error.
2023-03-08 16:22:42 +01:00
Fintan Halpenny 1e8f5b2259
node: determine fetching namespace based on repo policy
To determine the correct Namespaces to use, the repo Policy and Scope
are consulted.

If the policy is Block then this is a failure state and is reported to
the other end.

Otherwise, if the policy is Track, then the scope is checked. For the
Trusted Scope then the Namespaces should consist of all tracked nodes
and delegates for the given repository. However, the repository might
not exist and so it is necessary for the whole repository to be
fetched.

For the All Scope, all Namespaces are fetched.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 11:33:41 +00:00
Fintan Halpenny e937cdd79a
node: improve fetch
The fetch implementation will potentially fetch the local operator's
remote, which is unnecessary and could result in deleted data.

Fix this by threading the local operator's public key and add an
ignore refspec to the fetch arguments, i.e.

    ^refs/namespaces/<local>/*

The implementation also strictly fetches all or one namespace. This is
improved upon by introducing a new variant for specifying a set of
namespaces.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 11:29:34 +00:00
Fintan Halpenny 3b015a9325
radicle: accept Scope as track_repo argument
The method `track_repo` only accepted the RID as the argument for
tracking.

Instead, allow passing Scope as an argument for tracking a
repository.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 11:29:34 +00:00
Fintan Halpenny e408b0d62c
node: use enum for fetch direction
A fetch is a client-server interaction and so there are two sides to
this interaction. These sides are generally referred to as receive --
the client side -- and upload -- the server side.

The `Fetch` type indicated whether it was doing a receive or upload by
using a field `initiated: bool`. However, this can be confusing when
you pair it with the `namespaces: Namespaces` field, since only the
receive side should be sending what refspecs it wants and the upload
side responds with those matching refspecs.

A better way to represent this is using an enum for which direction
the fetch is being considered, where the receive side contains the
Namespaces. To borrow from Noise, the variant names are 'Initiator'
for the client and 'Responder' for the server.

The resulting code then makes decisions based on what variant of the
enum was passed.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 10:12:54 +00:00
Alexis Sellier c3a5aced07
node: Handle case of crossing fetch requests
It is possible for a pair of nodes to concurrently ask each other
to fetch some repo. These "crossing" requests are problematic,
because the nodes end up waiting for each other to reply, and
the reply never comes.

With this change, the node pair agrees on proceeding with one of
the fetches, while canceling the other.
2023-03-07 16:22:22 +01:00
Alexis Sellier fb635d80c3
node: Gossip once we switch to gossip protocol
Previous to this change, we were attempting to gossip after a successful
fetch, but before the session was switched back to the gossip protocol.
This meant that messages were queued for a short amount of time. With
this change, messages should be sent straight away.
2023-03-07 15:44:10 +01:00
Fintan Halpenny 1f837c6572
node: implement tracking and routing
The routing function for Node was not implemented and there were no
functions for getting any tracking information.

This implements routing, tracked_repos, and tracked_nodes. To
accomplish this it was necessary to add associated types to the
Handler trait so that implementations could differ in the types they
use for returning this data, i.e. the control socket needs to use a
channel while the Node needs to return serializable data.

Currently, the Node uses a `Vec` but it would be more beneficial to
return an Iterator directly to ensure we are not always hitting the
heap.

To allow for the tracking types to be used across radicle-node (the
crate) and in radicle::node (the module), it was necessary to move
the types to the common place, i.e. radicle::node. At the same time,
new structs were added to make it easier to refer to tracked repos vs
tracked nodes.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-07 15:38:41 +01:00
Alexis Sellier 85df613682
cli: Implement automatic issue announcement 2023-03-07 08:40:20 +01:00
Alexis Sellier c8c44c884c
cli: Allow `init` without running node 2023-03-06 15:38:42 +01:00
Alexis Sellier e69be6051d
cli: Give more control over `init` announcement
Instead of always announcing the inventory, by default we don't.
Users can run `rad push` to trigger an announcement.
2023-03-06 15:38:42 +01:00
Alexis Sellier 5f59493c70
cob: Don't require a local fork to exist
Before this change, the identity document would be loaded for the
COB signer. This meant that a fork would be needed for that signer.

After this change, it's no longer necessary, since the identity doc
head is computed from available remotes.

While making those changes, it was also apparent that some of the
identity-related functions had bad names and error types, this
was fixed as well.
2023-03-01 15:40:30 +01:00
Fintan Halpenny c70dc71b18
node: improve seeds information
Previously, the seeds information would only consist of the connected
NodeIds.

Improve on this by adding any disconnected and fetching seeds as
well. A seed can either be disconnected, connected, or fetching --
where fetching implies connected.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-02-27 17:48:11 +01:00
Dr Maxim Orlovsky 158f1ff7fa Update to fixed `io-reactor` timer 2023-02-22 16:21:25 +01:00
Alexis Sellier a7d2fa95cd
node: Remove redundant handshake
With `NoiseXK` handshake implemented, there is no longer a need to
have an `Initialize` message and an extra state in the session.
2023-02-16 15:10:31 +01:00
Alexis Sellier 71561a8e12
node: Move state transition code to session 2023-02-16 15:09:53 +01:00
Alexis Sellier 011923f1df
node: Buffer gossips until fetch is completed
This change ensures that gossip messages are buffered if we try to
send them during a fetch, and sent after the fetch completes.
2023-02-16 15:09:53 +01:00
Alexis Sellier 0f81f8a7aa
node: Take session reference when writing messages
This ensures that we have an existing session when sending messages.
It also will allow us to check the session's state.
2023-02-16 15:09:53 +01:00
Alexis Sellier 89fcc6de1c
node: Subscribe on track-repo
We re-subscribe after our tracking policy has been changed so that
peers are informed of our interests.
2023-02-15 22:07:51 +01:00
Alexis Sellier 8cbc3c2403
node: Move to NoiseXK
Move from NoiseNN with a custom authentication protocol, to NoiseXK.
Uses ECDH on the ed25519 curve via the `ec25519` library.
2023-02-15 22:05:04 +01:00
Alexis Sellier ee513ccf7e
node: Complete the "relay" seed test
These are the final changes to get the "relay" scenario passing.
There are still some issues left, though it's done as far as the
test is concerned.
2023-02-14 20:31:40 +01:00
Alexis Sellier 7919c7ea61
node: Use millisecond precision for timestamps
Previously we used seconds, which could result in false positives
when checking for stale announcements, if things happened too quickly.
2023-02-14 20:31:40 +01:00
Alexis Sellier 3ae826dee2
node: Add clone test with seed acting as relay 2023-02-13 10:30:04 +01:00
Alexis Sellier 3e7761740f
node: Rely on inventory announcement in `rad init` 2023-02-13 09:59:44 +01:00
Alexis Sellier 7087288cfb
node: Implement inventory sync command 2023-02-12 20:57:33 +01:00
Alexis Sellier 2f1a18470e
node: Fix filter construction and policy code 2023-02-12 17:07:57 +01:00
Alexis Sellier 42b4d95f93
node: Improve output of `Session::fetch` function 2023-02-12 16:22:51 +01:00
Alexis Sellier bd7c5a0daa
node: Add ability to have default tracking policy
When a specific tracking policy isn't found, we allow setting a default.
To preserve existing behavior, the default is `Block`, ie. if a node
isn't tracked explicitly, it is blocked.

However, this change allows for using `Track` as the default, which
is a way to track everything without having to know the entities in
advance.
2023-02-12 16:22:51 +01:00
Alexis Sellier 69ac8be8fd
node: Update local routing table on announce 2023-02-08 21:28:49 +01:00
Alexis Sellier f01735bef6
cli: Have `init` trigger routing table updates
Before this change, nodes had to be restarted to announce newly
initialized projects.
2023-02-08 16:29:42 +01:00
Alexis Sellier f66ecd4ece
node: Replication fixes
* Read git request line before starting daemon, so that we don't leave
  git data in the socket read buffer in case of an error connecting to
  the daemon.
* Send a response on the fetch channel even if we disconnect the remote.
* Don't send `done` packet if there's an error; it won't be expected.
2023-02-07 21:04:13 +01:00
Alexis Sellier f5f36191d9
node: Fix some connection-related logic 2023-02-07 10:47:35 +01:00
Alexis Sellier 7bdedd0ffd
node: Fix bug with persistent peer reconnect
We weren't updating the sessions map when a persistent peer
was re-attempted. It would then panic when `connected` was called,
because the state would be `Disconnected`.
2023-02-07 10:47:35 +01:00
Alexis Sellier 45e31a5192
Communicate fetch results through control socket
This allows a CLI to report to the user what fetch requests were
fulfilled, and which ones failed.
2023-02-07 10:46:12 +01:00
Fintan Halpenny 3f48c2c516
Rust 1.67
Rust 1.67 was announced[0]. Update the necessary files for running
1.67 and fix the clippy suggestions for string interpolation.

[0]: https://blog.rust-lang.org/2023/01/26/Rust-1.67.0.html

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-02-04 19:30:29 +01:00
Alexis Sellier 98f7fe1db8
node: Rename `GIT_RESET` env var 2023-01-30 18:23:24 +01:00
Alexis Sellier 498a5c4e4a
node: Handle `fetched` differently if initiated 2023-01-30 13:22:33 +01:00
Alexis Sellier 3aa105afda
node: Return error if remote errors
Instead of simply breaking out of the loop, log and return an error.
2023-01-30 13:15:33 +01:00
Alexis Sellier be77eebc3d
node: Only try to fetch from connected nodes 2023-01-30 11:20:33 +01:00
Alexis Sellier d9e1055067
Improve logging 2023-01-28 23:58:16 +01:00
Alexis Sellier be95222fb5
node: Fix bug in upload-pack
We were not properly exiting one of the threads that was copying
data from the stream to the upload-pack process. This is a fix.
2023-01-27 15:09:17 +01:00
Alexis Sellier 026dfbde5d
node: Improve logging output 2023-01-26 18:15:27 +01:00
Alexis Sellier 963ad3c3d7
Get `rad clone` working correctly 2023-01-25 11:35:20 +01:00
Alexis Sellier fea14ff7b3
Update `clone` functionality for new replication 2023-01-25 10:21:57 +01:00
Alexis Sellier ef950d515a
node: Fully integrate worker fetch into service 2023-01-25 10:21:57 +01:00
Alexis Sellier ec2e7d7ee1
node: Refactor fetch response code
Only user-requested fetches require a response.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-25 10:21:57 +01:00
Alexis Sellier 3bc07195f5
Migrate to `localtime` from `nakamoto`
The only thing we needed nakamoto for was `LocalTime`.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-18 18:03:11 +01:00
Alexis Sellier d25c47ad0e
node: Get rid of worker response channel 2023-01-18 17:45:46 +01:00
Alexis Sellier f33e79f14b
node: Fix redundant announcements
This change makes sure that nodes don't gossip announcements back to
the announcers.

Since the tests were relying on this mechanism to populate the routing
table, we had to change a few more things, such as adding the inventory
to the node's routing table.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-18 08:48:33 +01:00
Alexis Sellier 63e7248847
node: Complete Noise handshake integration
Co-authored-by: Dr. Maxim Orlovsky <dr.orlovsky@gmail.com>
Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-17 11:01:36 +01:00
Alexis Sellier 1aba9812c7
node: Request recent messages on connection
Instead of only being interested in messages from "now", we request
messages from one hour in the past up to now. This lets nodes catch
up on state more quickly, without having to wait for new announcements.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-17 11:01:36 +01:00
Alexis Sellier 6d420813f5
node: Fix attempted session state
We shouldn't be marking attempted peers as "connected". We should wait
for the connection to be properly established.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
2023-01-13 15:44:01 +01:00
Alexis Sellier 438ae84304
node: Implement E2E node test
There are few unrelated changes in this commit that I wasn't able to
split out, mostly due to laziness, so I'll list them here:

* The node startup logic is moved out of the main function, and into a
  dedicated functionin `client.rs`.
* There is a tentative worker implementation that is untested, and
  handles git replication both ways. It's likely lacking in various ways
  but I wanted to get it in there anyway.
* `Address` was moved from `radicle-node` to `radicle`, because it's
  needed to send `Connect` commands from the node handle.
* The `netservices` dependency was updated.
* Finally, there is a first end-to-end node test, which currently
  doesn't use NoiseXK, but uses the new reactor in `netservices`.

Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-12 20:34:31 +01:00
Dr. Maxim Orlovsky 08334f790b
node: Get rid of `nakamoto::DisconnectReason`
Signed-off-by: Alexis Sellier <self@cloudhead.io>
2023-01-10 16:35:40 +01:00
Dr. Maxim Orlovsky a7b1c19746
node: Implement worker thread handover
Also implements listener behavior.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
2023-01-05 15:16:38 +01:00
Dr Maxim Orlovsky aa02c52a2f
node: Integrate new Noise_XK transport
This is a large change that introduces transport encryption via
a Noise_XK handshake. The inner `Service` now works directly
with `NodeId` and doesn't need to interact with socket addresses.

The transport logic takes place in `wire::transport`, and the
established sessions are passed down to `Service`.

Note that the i/o implementation in the `poll-reactor` crate still
needs testing, and there is still work to be done to integrate the
Git transport as part of this architecture.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
2022-12-13 14:59:06 +01:00
Slack Coder e7f2637126
node: Limit number of Refs in RefAnnouncements
Use the BoundedVec to limit the supported number of refs in
RefAnnouncement messages.  The size (235) is the maximum supported by
message wire size.

To reduce the complexity of the changes, BoundedVec is used again
instead of using a new bounded Refs or BTreeMap.  This requires
defining new Decode/Encode logic for Ref's element types, and
workarounds for arbitrary instances.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-12-09 21:54:10 +01:00
Alexis Sellier a100f1c683
cli: Implement tracking correctly
The tracking command was tracking a project when it should
have been tracking peers.

We also add the ability to pass an alias when tracking from
the CLI.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
2022-12-09 10:52:18 +01:00
Dr Maxim Orlovsky 7c9ee0f911
node: Remove `RefClock`
It wasn't used anymore.
2022-12-07 16:06:35 +01:00
Alexis Sellier 1007756238
node: Add tracking configuration store
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
2022-12-07 15:41:56 +01:00
Slack Coder fe60305455
node: Define naive message vector limits
Restrict message size decoding by limiting Message's vector size.
Introduce the BoundedVec type to do this on the type level for
convenience and clarity.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-12-01 14:54:40 +01:00
Dr Maxim Orlovsky da55e521a1
Use socket addr instead of Ip for the address book 2022-11-29 17:58:38 +01:00
Slack Coder f5d06f6138 node: Fix addresses sent to peers on conn.
Send the node's configured external addresses instead of its listenning
addresses.  External addresses are ones which the service is reachable
from the outside world, the listening addresses can be the wrong context
(local area network, or 0.0.0.0).

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-23 13:13:56 -05:00
Dr. Maxim Orlovsky 983b2dc534
Two-stage connectivity with handshake 2022-11-21 16:05:53 +01:00
Dr. Maxim Orlovsky e9ae5897f7
Complete transcoder
* Encode/encrypt data sent to the remote peer
* Remove unused Transport
* Rename Decoder -> Deserializer
2022-11-21 16:05:53 +01:00
Slack Coder 5472931ff0 node: prune project routing table
Avoid wasting persistent memory by cleaning up stale routing entries
when the routing table is considered constrained.  Limit pruning to
improve resiliency in the face of long intervals between service
downtimes.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-15 12:26:34 -05:00
Slack Coder a74cb416c1 node: sync project routing for known nodes
Keep the node's understanding of project hosting location current by
updating how Inventory Announcement messages are processed.

The Inventory Announcements contain a node's entire listing of projects.
Replace the routing table information for the announcer with those from the
message.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-15 12:26:08 -05:00
Slack Coder 186eb42145 node: use announcer's timestamp in project inventory
Address a FIXME in service.process_inventory() by using the announcer's
time instead of the service's.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-15 12:26:08 -05:00
Slack Coder 503a618743 node: announce node only when accessible
Avoid redundantly emitting Node Announcements about it's publicly
available addresses when it has none.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-09 09:49:21 -05:00
Slack Coder a9b38dc1ae node: let others know their address
Include the node's IP address in the Node's announcements.  Source it
from the service's configuration which can assumed to be populated with
default values when available.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-09 09:49:07 -05:00
Slack Coder f3d867af4d node: keep a healthy connection to the network
Try having a number of outbound connections to other Radicle nodes at any
given time.  The number has been defined earlier as TARGET_OUTBOUND_PEERS.
All network nodes are treated equally, there is no preference.

Attempts to keep connected happen at set intervals (IDLE_INTERVAL) or when
a node disconnects.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-09 09:49:07 -05:00
Slack Coder ff045e0813 node: use term 'session' over 'peer'
Keep up to date with recent changes of renaming service.peers to
service.sessions.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-09 09:49:07 -05:00
Slack Coder a91dcfb100 node: sync known sessions on disconnect
Make sure the service is current by removing disconnected peers.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2022-11-09 09:49:07 -05:00