Commit Graph

67 Commits

Author SHA1 Message Date
Fintan Halpenny a9c1c6ef54 protocol: Update to 0.6.0 2026-03-18 20:53:00 +00:00
Lorenz Leutgeb 6967bf8fca
radicle: Automatically upgrade sigrefs
When enumerating repositories in storage, gracefully handle the
case where the identity root is missing from sigrefs and automatically
migrate.
2026-03-17 21:31:42 +01:00
Fintan Halpenny 0c47d06f2d radicle/storage/refs: Strengthen Encapsulation
`radicle::storage::Refs` carries a map from reference names to OIDs, and
there are some invariants.
2026-03-16 14:30:48 +01:00
Fintan Halpenny b8502397a5 protocol/wire: Remove SignedRefs encoding/decoding
The implementations for `Encode` and `Decode` for `SignedRefs` existed
for when `SignedRefs` was communicated over the wire. This was traded
for communicating `RefsAt` instead. So, these can safely be removed.
2026-03-16 14:30:36 +01:00
Fintan Halpenny 9ea1ea2433 Revert "node/debug: Use derived serializers"
This reverts commit 5099c25df7.

The `HostName` of the `RateLimiter` could serialize as an invalid JSON
key, resulting in the command panicking.
2026-03-05 15:29:42 +01:00
Fintan Halpenny 18d6ce9477 protocol: Update 0.5.0 2026-02-19 21:06:43 +01:00
Adrian Duke 1fa14ef529 protocol/service: Use block list for connections
The service learns to consult the policies database to check if a
`NodeId` is blocked.

When a node is blocked the service will prevent any inbound or
outbound connection.

In the case of an inbound connection, a disconnect must be submitted
to the reactor.

In the case of an outbound connection, nodes are filtered out from any
connection lists, and prevented from submitting a connect to the
reactor.
2026-02-17 16:12:04 +01:00
Adrian Duke 94e0a5128d node: Add block command to control socket
Introduces the ability to explicitly block a peer via the node control
socket. Previously, the node only exposed follow and unfollow commands.
While the underlying policy database schema supported a Block variant,
there was no mechanism to trigger this state via the client handle.

The new block command:

 1. Updates the node's follow policy to Block.
 2. Immediately disconnects the peer if a session is active.
2026-02-17 16:12:04 +01:00
Lorenz Leutgeb 0e9d7607e4 hooks: Enable typos, fix reported errors 2026-02-17 11:35:28 +00:00
Adrian Duke 306d0afbfe protocol: Note on peering and fetches
As part of the work to change the default scope, one of the tests
surfaced an issue where the topology was Alice <--> Bob <--> Eve,
however because of the previous 'all' scope Alice could receive Eve
references via Bob, but since the scope was changed to 'follow' Alice
would need to have a direct connection to Eve. TODO left here for future
consideration.
2026-02-16 21:39:11 +01:00
Fintan Halpenny 980ed56186 protocol/service: rename `Responder::new` to `Responder::oneshot`
The `Responder` is a oneshot channel where it sends one result and the
other side receives that result.

This surfaced that the `AnnounceRefs` command was returning one result
at a time. At the moment, this is only used for a single namespace,
the local user's.
2026-02-16 13:33:00 +01:00
Fintan Halpenny 0d628a45e2 protocol: refactor to use Responder
Refactors every command that uses a `Sender` to use a `Responder`
instead. There is an exception for `QueryState` since its usage
differs slightly to the other cases.

To make the usage more ergonomic, constructors for the variants that
require a `Responder` are added.
2026-02-16 13:33:00 +01:00
Fintan Halpenny b1eedd3b64 protocol/service: introduce Responder type
Introduce a `Responder` type that wraps a
`crossbeam_channel::Sender<Result<T>>`.

It provides a standard constructor and three sending methods: one for
a `Result`, one for an `Ok` value, and one for an `Err` value.
2026-02-16 13:25:58 +01:00
Fintan Halpenny 61a9b2140f protocol/service: introduce Result synonym
Create a type synonym for `Result<T, Error>`, to simplify result types
being returned by commands in a later change.
2026-02-16 13:25:58 +01:00
Fintan Halpenny 2c1972151d protocol: opaque command error
Refactor `CommandError` to be an opaque, boxed error.
Rename it to `Error`, so that it is imported via `command::Error`.
2026-02-16 13:25:58 +01:00
Fintan Halpenny 38713a8e62 protocol/service: drop `chan` qualifier
Small refactor to drop the `chan` qualifier and use `Sender` directly.
2026-02-16 13:25:58 +01:00
Fintan Halpenny 912a5ca42b protocol/service: create command module
Create a `command` module to house the command related types.
2026-02-16 13:25:58 +01:00
Lorenz Leutgeb 5099c25df7 node/debug: Use derived serializers
The construction of the debug object is unwieldy, and error prone
(for example, renamed struct members have to be manually renamed
in the serialization code, see "refs" vs. "refsAt").

Use derived serializers where possible to make this easier to maintain.
2026-02-16 09:43:38 +00:00
Lorenz Leutgeb a1fa38018e protocol: Depend on `cypheraddr` not `cyphernet`
`radicle-protocol` depends on `cyphernet`, but only uses the module
`cyphernet::addr`, which is a re-export of `cypheraddr`, which is
unnecessary (as `cypheraddr` alone would do), and invites accidentally
pulling in more dependencies via `cyphernet`.

To prevent accidentally depending on further types from `cyphernet`,
change this to more conservativeley depend on `cypheraddr`.
2026-02-16 09:43:38 +00:00
Lorenz Leutgeb 865abd35e2
protocol/fetcher: Intro `RefsToFetch`
Using empty `Vec`s to mean "all refs" can be confusing. Avoid the chance
of confusion by introduction of a new type that clearly describes which
refs should be fetched.
2026-02-13 15:27:21 +01:00
Lorenz Leutgeb 9081c11b98
protocol/fetcher: Remove `from` from `QueuedFetch` 2026-02-13 15:25:42 +01:00
Lorenz Leutgeb 53a1286901
protocol/service: Remove unnecessary arg 2026-02-13 15:25:42 +01:00
Lorenz Leutgeb 94d7799ffe
protocol/fetcher/state: Typo 2026-02-13 15:25:42 +01:00
Lorenz Leutgeb 56ee626a51
protocol/fetcher: Delete unused file 2026-02-13 15:25:42 +01:00
Fintan Halpenny 613c4e83e0 protocol: separate subscribers by RefsAt
It was found that if a fetch was started for a specific `Vec<RefsAt>`
and a following general, i.e. empty, `Vec<RefsAt>` was queued, the
subscriber for the general one would be removed when the specific
fetch completed.

This behaviour is undesirable, since the general fetch could
potentially fetch more data.

To prevent this from happening, the `Vec<RefsAt>` is added to the
`FetchKey`, so that `subscribers` are matched with the set of
references they want to hear results for.

A test was added for the above scenario.
2026-02-13 12:49:37 +01:00
Fintan Halpenny 1cab036c33 protocol/service: Wire up `FetcherService`
Wire up the new `FetcherService`. This reduces the `Service` fetch
methods down to:
- `fetch`
- `fetched`
- `dequeue_fetches`
- `fetch_refs_at`

This simplifies the code by off-loading the logic to the `fetcher`
family of types, rather than handling the intricacies in the `Service`
itself.

The `Service` now just performs the necessary I/O based on the
returned events from the `fetcher`.

This also removes the fetching state from the node sessions. This
follows the single responsibility, and sessions now only care about
their connectivity.

Breaking changes:
- The `Connected` state of a peer no longer contains fetching
  information, which was being returned as part of the JSON payload
  result.
- The `rad debug` information for ongoing fetches contained the number
  listeners awaiting for results, this was removed.
2026-02-05 20:04:28 +01:00
Fintan Halpenny 9e20890965 protocol: Introduce `FetcherService`
The `FetcherService` wraps the `FetcherState` alongside keeping track
of subscribers for a given fetch.

Typically, this is a channel for which the fetch result should be sent
to.

These subscribers are coalesced by maintaing a map from `(rid, node)`
pairs to the subscriber.

This continues the sans-IO approach where the type of subscribers are
not specified, but rather are kept as a type parameter – to be
specified by the caller.
2026-02-05 20:04:28 +01:00
Fintan Halpenny f0e3ca3403 protocol: Introduce `FetcherState`
This patch introduces the `FetcherState` which encapsulates the logic
and state for keeping track of fetches.

It uses a sans-IO approach, where the state of fetches transition
based on the current state and provided input.

Callers can then decide to perform I/O based on the returned event.
2026-02-05 20:04:28 +01:00
Fintan Halpenny 15adb16135 protocol: missed formatting
Formatting was missed in the `service.rs` file.
2026-01-28 10:16:50 +00:00
Fintan Halpenny 91eb6fc078 protocol: ensure `connect` supports connecting address
Be more defensive by preventing a node, that is not configured for
Tor, to not connect to `.onion` addresses via the `Service::connect`
method.

This means that an `Outbox::connect` should not be produced, and the
address table should not insert an entry.
2026-01-26 18:55:35 +01:00
Fintan Halpenny 36d5a4c8b0 protocol: use helper method
Use the `is_persistent` helper method rather than repeating the
`is_some` check.
2026-01-26 18:55:35 +01:00
Fintan Halpenny 73f9a35033 protocol: reuse session address for reconnect
When maintaining persistent connections, the config was consulted for
a peer address. Multiple addresses for a single `NodeId` can be
listed. This can result in a different address being used for
reconnecting if the `HashSet` returns in a different order.

The original address that was used for connection is in the `Session`,
so this should be used instead.
2026-01-26 18:55:35 +01:00
Defelo 589925e3a3 radicle/node: avoid unnecessary allocations in `Emitter::emit_all` 2026-01-26 17:40:02 +00:00
Defelo 8b1d475170 protocol: batch inventory removals and events in `sync_routing`
The previous implementation would remove routing entries one at a
time.
Improve the performance of this by batching the removal and events
emission.
2026-01-26 17:38:53 +00:00
Fintan Halpenny ee1f55420a protocol: downgrade `error!` logs
Evaluate the `error!` logging in `radicle-protocol`.

The majority of cases, the `error!` is downgraded to `warn!`. These
cases are generally useful to know if there's an issue, but the
operator cannon necessarily do anything about it.

In a few cases, `debug!` was chosen. These are generally when an error
means that a result is not part of an accumulation, or the system will
eventually correct itself during another event or restart.

If the previous message started with "Error", then the wording is
changed to say "Failed to".
2026-01-19 17:59:06 +01:00
Fintan Halpenny 95b3d10961 protocol: downgrade `warn!` logs
Evaluate the `warn!` logging in `radicle-protocol`.

If the event is a result of something being suspicious in the running
of the protocol, then it remains a `warn!`.

However, if the system ends up ignoring the event and can continue
without issues, the log level is reduced to `debug!`.
2026-01-19 17:56:56 +01:00
Fintan Halpenny d5fea6324c core: Introduce RepoId
Introduce the `radicle-core` crate for housing data types that are at
the core of the Radicle protocol. The initial data type being added is
`RepoId`. To make the crate as lightweight as possible many of
dependencies are optional and gated by feature flags.
The crate is marked as `no_std` even though it unconditionally depends
on `radicle-crypto`, which is *not* `no_std`. This is to invite
refactoring of `radicle-crypto` to `no_std` at a later time.
2026-01-09 14:03:27 +01:00
Fintan Halpenny d98033a1ff localtime: localise the localtime dependency
The `localtime` crate was defined by cloudhead, and is a minimal
repository with a single `lib.rs`.

Instead of using it as an external dependency, copy the code directly
into a new workspace crate `radicle-localtime`.

The default `serde` implementation goes through the `LocalTime`'s
seconds values rather than milliseconds, since this is the more common
format. This allows the removal of the `serde_ext` functions.
The one place milliseconds was used was for the
`radicle::cob::common::Timestamp` type, where the `Serialize` and
`Deserialize` implementations are manually written.

It also adds a `schemars` feature to remove `schemars_ext` functions
in `radicle` as well.
2026-01-08 14:58:41 +01:00
Fintan Halpenny 47dc2c562c protocol/service: defensive storage.contains check
In the case of the `storage.contains` call returning an error, it
would be preferable to log the error and continue checking for missing
repositories.
2026-01-05 17:51:43 +01:00
Fintan Halpenny 58305cda32 protocol/limiter: impl AsTokens for limits
Provide `AsTokens` implementations for the `Outbound` and `Inbound`
newtypes of `RateLimit`.

This allows them to be used for the rate limiting method.
2025-12-02 14:18:18 +01:00
Fintan Halpenny c675683da9 protocol: IntoIterator for BoundedVec
Implement `IntoIterator` for the `BoundedVec`.

This allows the use of `into_iter` for returning the owned data,
rather than references via the `Deref` implementation.
2025-12-02 12:55:09 +00:00
Fintan Halpenny 45abb881a3 node: Only consider onion addresses if configured
There is an unfortunate lack of single-responsibility with handling the
addresses to connect to.

This is a band-aid fix until the point in time where this can better improved.
2025-11-28 21:52:39 +01:00
Yaroslav Halchenko 32d77641ab chore: Fix spelling errors with codespell 2025-11-01 12:11:02 +01:00
Lorenz Leutgeb b0beef4391
workspace/rust/clippy: Fix all warnings
Fix clippy warnings following the upgrade of the Rust toolchain to
version 1.90. Almost all are "mismatched_lifetime_syntaxes".
2025-10-17 12:56:43 +02:00
Fintan Halpenny cef0ff571d oid: use `std:#️⃣:Hasher::hash` over `Hasher::write`
Previously, the `RepoId` was backed by the `git2::Oid` type, which has a `Hash`
implementation that uses `std:#️⃣:Hasher::hash`. This uses a length prefixed
form for hashing.

When switching to `radicle_oid::Oid` and implementing `Hash` without the length
prefix, this subtly changed the hashes going forward.

These hashes are used in `BloomFilter`, which is the type underlying `Filter`.
This resulted in cases where a previous `Filter` that certainly contained
`rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5` were suddenly reporting that they did not
contain this repository.

Changing the implementation of `Hash` for `radicle_oid::Oid` fixes this, and is
confirmed by adding the regression test in `filter.rs`.
2025-10-16 15:14:10 +01:00
Lorenz Leutgeb b7cfcfff75
workspace: A Little Less `git2`
Make `git2` an *optional* dependency of `radicle-cob`, and refactor
`radicle` to depend on crates that in turn do not depend on `git2`
*non-optionally*

The main offending dependency of `radicle-cob` is `radicle-git-ext`
from the `radicle-git` workspace in repository
(rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt) which *non-optionally* depends on
`git2`.

So, to achieve removal of this dependency:

 1. The crate is refactored to depend on the new crates
    `radicle-git-ref-format` `radicle-git-metadata`, and
    `radicle-oid` introduced in the previous commits, instead of
    `radicle-git-ext`.
 2. Some code from the `radicle-git-ext` crate in the `radicle-git`
    workspace in repository (rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt) is
    copied. See `crates/radicle-cob/src/backend/git/commit.rs`.

This cascades to `radicle` and its dependents.

  Firstly, the there is an
`impl Deref<Target=git2::Oid> for radicle_git_ext::Oid`. This made
it very convenient to just deref to obtain the wrapped `git2::Oid`,
so there are many expressions of the shape `*oid` in `radicle` and
its dependents. However `radicle-oid` does not provide
`impl Deref<Target=git2::Oid> for radicle_oid::Oid`, as notably,
`Target` is an associated type, and not a type parameter, so an
implementation of `Deref` would tie the new `Oid` too tightly to a
particular implementation.
Instead, work with `impl From<radicle_oid::Oid> for git2::Oid`
(which can be enabled using the feature flag `radicle-oid/git2`).
This explains the changes from `*oid` to `oid.into()` at every
transition to "`git2` land".

  Secondly, `radicle` and its dependents are refactored to also depend
on `radicle-git-ref-format` and (much less prominently)
`radicle-git-metadata` instead of `radicle-git-ext`
This is to avoid pulling in `git2` via these dependencies.

  Thirdly, as the re-exports in `crates/radicle/src/git.rs` change,
they are at the same time also cleaned up. Notably, the types from
`radicle-git-ref-format` are re-exported under `fmt` only, not "twice".

While overall this obviously is very much a breaking change, these
changes should mostly amount to changing from `Deref` to `Into`, i.e.,
`*oid` → `oid.into()` and rewriting imports for `radicle::git::fmt`.
This is indicated by the mostly mechanical nature of the changes to
`crates/radicle-{cli,node,remote-helper}`.
2025-10-13 16:14:23 +02:00
Lorenz Leutgeb 7effa7c64c
node: Report sync status for given namespaces
The "seeds" command does only take a repository ID, and
carries the implicit assumption that the namespace with the same public
key as the Node ID of the receiving `radicle-node` process should be
used as reference for determining whether other nodes are in sync,
but no other namespace.

In the spirit of separating user and node identity, relax this, so that
the command also carries the public keys relative to which the sync
status should be computed. This allows to inspect sync status for
arbitrary namespaces via command.

For now, this feature is not exposed to the CLI, but `rad sync status`
always passes the public key of the active profile.
2025-10-09 07:55:11 +02:00
Lorenz Leutgeb 9689de9af0
node: Allow announcing refs for given public keys
The "announce references" command does only take a repository ID, and
carries the implicit assumption that the namespace with the same public
key as the Node ID of the receiving `radicle-node` process should be
announced, but no other namespace.

In the spirit of separating user and node identity, relax this, so that
the command also carries the public keys for which the announcement
should be made. This allows to announce arbitrary namespaces out of
storage via command.

For now, this feature is not exposed to the CLI, but rather:
 - `rad sync` always announce for the public key of the active profile.
 - `git-remote-rad` ditto, as it calls the same codepath.
2025-10-09 07:55:10 +02:00
Fintan Halpenny ee041d8d06 crates: bump for release
- `radicle-term`: 0.15.0 -> 0.16.0
- `radicle-node`: 0.15.0 -> 0.16.0
- `radicle-fetch`: 0.15.0 -> 0.16.0
- `radicle-crypto`: 0.13.0 -> 0.14.0
- `radicle-cli`: 0.16.0 -> 0.17.0
- `radicle`: 0.19.0 -> 0.20.0
- `radicle-cob`: 0.16.0 -> 0.17.0
- `radicle-remote-helper`: 0.13.0 -> 0.14.0
- `radicle-protocol`: 0.3.0 -> 0.4.0
- `radicle-systemd`: 0.10.0 -> 0.11.0
2025-10-06 16:36:30 +01:00
Lorenz Leutgeb d9ce078d56 protocol: Decrease log-level for logging ping/pong
When logging writes, use a lower more verbose level for ping and pong,
as these messages are quite noisy.
2025-10-02 10:47:29 +01:00