Commit Graph

113 Commits

Author SHA1 Message Date
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 ea4294c79f
node: More realistic concurrent fetch test
This implements a test which can optionally use a lot more data by
setting `RAD_TEST_SCALE` to a higher value.
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
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 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 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 a9d1a71f7a
node: Add timestamp to test logger 2023-03-22 12:22:44 +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 05d7090326
node: Remove `Handle::inventory` method 2023-03-15 12:59:49 +01:00
Alexis Sellier caaa7581e6
node: Remove `Routing` command
Replaced by direct DB access.
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 9b6ede8fc5
cli: Use tracking DB access for `node` command 2023-03-15 12:59:49 +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 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
Fintan Halpenny 821a6b6c08
node: test do not fetch from owned refs
To ensure the behaviour of ignoring references that are owned by the
local peer a test case is added.

The case has two peers: alice and bob, where alice creates a new
repository. bob fetches to be up-to-date with alice. alice, in turn,
creates an issue and fetches from bob -- which should be successful.

If the refspec:

    ^refs/namespaces/<alice>/*

was not in place, her fetch from bob would fail since the signed
references would not be a fast-forward.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 11:33:42 +00: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 b82584617b
node: store Scope in tracking config
The tracking configuration has no way of consulting for a configured
scope.

This change allows the storing of this scope inside the tracking
`Config` -- currently unused.

The default Scope is chosen as Trusted, so that nodes do not
implicitly track any other node. If this behaviour is desired -- for
example, for seed nodes -- then All should be chosen.

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 39be7db1e9
radicle: make alias optional
Previously the alias field was simply a string which could possibly be
empty. Some checks were made to see if this string was empty.

Instead, make the logic more obvious by making the alias field
optional.

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 0302701c98
node: limit number of loops in `routes_to`
The `routes_to` function can loop infinitely during test.

To prevent this from happening a number of tries variable is added. It
checks that the number of tries does not exceed 30, which gives the
function about 3 seconds to complete -- due to the call to
`thread::sleep` using 100ms.

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 d476d35887
radicle: populate MockRepository
The MockStorage holds an inventory of repositories and their
identities but when asking for a MockRepository, none of this
information is transferred.

Add `id` and `doc` fields to MockRepository for defining some of its
functionality.

In addition, add a generator for a nonempty MockStorage to use in
tests that will expect the storage to be populated.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-03-08 11:29:33 +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
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 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 207030d2e1
cli: Don't fail clone if we have repo locally 2023-02-27 18:19:02 +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
Fintan Halpenny c0b92d25fb
radicle: remove FetchResult associated type
The Handle trait defines a FetchResult associated type. This type is
always instantiated to be the FetchResult enum in radicle::node.

Remove the associated type to simplify the trait.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-02-27 17:17:00 +01:00
Fintan Halpenny 8e26e4c046
radicle: canonicalize home path
If a path was passed to `Home` in non-canonical form it would not use
the right path for any initialisation or use.

The aim is to use the `canonicalize` function for paths. However, this
may return an error if none of the paths exist. To ensure that the
path exists the `new` constructor for `Home` creates the directory and
canonicalizes the path.

Since `new` now initialises the home directory, it would be useful if
it also initialised all the necessary subdirectories -- which removes
the need for the `init` method.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
2023-02-16 16:35:59 +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 950fae209d
Make `ReadStorage` more usable
Previously, we were not able to access a `ReadRepository` instance
through `ReadStorage`. With this change, we are able to.
2023-02-15 22:08:20 +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 72c99b7939
node: Handle `SIGINT` and `SIGTERM` properly
This ensures that the socket file is cleaned up on exit.
2023-02-14 13:28:16 +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 c673f5db68
node: Add some useful test utility functions 2023-02-12 21:03:28 +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 5f4c6edee4
node: Simulator logging improvements 2023-02-12 16:48:46 +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
Slack Coder 02c07d7be1
cli: Test rad-clone is deterministic
The last commit of a newly cloned repository should remain untouched by
making `Node::project()` use a repository fixture instead of a randomly
generated one.

Signed-off-by: Slack Coder <slackcoder@server.ky>
2023-02-09 16:49:52 +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 2649e9c6fe
cli: Add `rad-clone` test 2023-02-07 10:46:12 +01:00