Skip to content

Conversation

@pr9t
Copy link
Contributor

@pr9t pr9t commented Sep 29, 2025

PR description

  • Gradle: pins tech.pegasys.discovery:discovery:<25.4.0> and excludes org.apache.tuweni to avoid clashes with existing io.consensys.tuweni jars used elsewhere.
  • AddedDiscoveryV5Config.java (builder-style config used by the service)
  • Introduces DiscoveryV5Service (thin wrapper around MutableDiscoverySystem).
  • Adds a smoke test (DiscoveryV5ServiceTest) that starts/stops and asserts ENR presence.

Fixed Issue(s)

fixes #4089

Thanks for sending a pull request! Have you done the following?

  • Checked out our contribution guidelines?
  • Considered documentation and added the doc-change-required label to this PR if updates are required.
  • Considered the changelog and included an update if required.
  • For database changes (e.g. KeyValueSegmentIdentifier) considered compatibility and performed forwards and backwards compatibility tests

Locally, you can run these tests to catch failures early:

  • spotless: ./gradlew spotlessApply
  • unit tests: ./gradlew build
  • acceptance tests: ./gradlew acceptanceTest
  • integration tests: ./gradlew integrationTest
  • reference tests: ./gradlew ethereum:referenceTests:referenceTests
  • hive tests: Engine or other RPCs modified?

Comment on lines 63 to 65
implementation("tech.pegasys.discovery:discovery:25.4.0") {
exclude group: "org.apache.tuweni"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Versions are managed in the platform module, and should not be re-declared here, and also exclusion of old tuweni should be centralized, probably that could be done in the main gradle.build

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated: move discovery version to platform; exclude org.apache.tuweni centrally

@pr9t pr9t requested a review from fab-10 October 2, 2025 07:10
Copy link
Contributor

@fab-10 fab-10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code wise, I have just few small suggestions, then about the discv5 I am not confident in that part, so I prefer that also someone else reviews it.

One question, how and when this service is called/invoked?

Comment on lines 51 to 53
this.bootEnrs = Collections.unmodifiableList(new ArrayList<>(b.bootEnrs));
this.bindInterfaces = Collections.unmodifiableList(new ArrayList<>(b.bindInterfaces));
this.advertisedIps = Collections.unmodifiableList(new ArrayList<>(b.advertisedIps));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.bootEnrs = Collections.unmodifiableList(new ArrayList<>(b.bootEnrs));
this.bindInterfaces = Collections.unmodifiableList(new ArrayList<>(b.bindInterfaces));
this.advertisedIps = Collections.unmodifiableList(new ArrayList<>(b.advertisedIps));
this.bootEnrs = List.copyOf(b.bootEnrs);
this.bindInterfaces = List.copyOf(b.bindInterfaces);
this.advertisedIps = List.copyOf(b.advertisedIps);


// Can happen on containers or when no interfaces are up; safe to ignore.
// We log at debug to satisfy Error Prone and keep behavior.
LOG.debug("Ignoring SocketException while enumerating network interfaces: {}", e.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LOG.debug("Ignoring SocketException while enumerating network interfaces: {}", e.toString());
LOG.debug("Ignoring SocketException while enumerating network interfaces", e);

@@ -0,0 +1,55 @@
/*
* Copyright ConsenSys AG.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright ConsenSys AG.
* Copyright contributors to Hyperledger Besu.

Comment on lines +55 to +61
private final ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor(
r -> {
final Thread t = new Thread(r, "besu-discv5-poller");
t.setDaemon(true);
return t;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a new scheduler, could be possible to use EthScheduler::scheduleFutureTaskWithFixedDelay

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes—switching to EthScheduler::scheduleFutureTaskWithFixedDelay. I’ll add a small adapter to avoid a direct dependency and refactor the wiring; working on it now and will push updates.

@pr9t
Copy link
Contributor Author

pr9t commented Oct 5, 2025

Thank you for reviewing!

Just to share some context — I’m part of the Ethereum Protocol Fellowship (EPF), and this DiscV5 work is my main project under that program. My mentor (Sally) suggested breaking it into smaller, reviewable PRs that can be merged incrementally instead of one large feature branch.

So, this PR is the first step — it only adds the DiscV5 config and service (a wrapper around MutableDiscoverySystem) along with initial tests. It isn’t wired into Besu’s runtime yet, so the service isn’t being invoked anywhere at this stage.

In the next PR, I’ll handle the wiring part — integrating the service into Besu’s startup flow, gated behind a hidden flag (--Xdiscv5-enabled), and ensuring no regressions for DiscV4.

@pr9t pr9t requested a review from fab-10 October 6, 2025 09:11
Copy link
Contributor

@fab-10 fab-10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @macfarla is there anyone expert in the discovery part that could take a look?


// In some versions stop() returns void; in others it returns a future.
try {
final Method m = discovery.getClass().getMethod("stop");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think I would prefer to avoid reflection here - how else could you achieve this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can just check what the current version of the discV5 library returns ...

private static boolean tryRegister(
final Object target, final String methodName, final Consumer<NodeRecord> handler) {
try {
final Method m = target.getClass().getMethod(methodName, Consumer.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how could you do this without using reflection?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback — I think we can avoid reflection by directly calling the current handler methods (setNewPeerHandler / setPeerRemovedHandler) since Besu now uses a fixed discovery version.

@macfarla
Copy link
Contributor

hey @pinges could you have a look from p2p POV - any changes you would like to see on this approach?

Copy link
Contributor

@pinges pinges left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few things that are still missing:

  • I think we should make sure to ping the bootnodes regularly, to increase our chances of being discovered
  • We should kick off random finds to discover other nodes quicker, which is more important right after start, maybe less once we have found max peers
  • We need to handle the sequence number of out node record (store it, retrieve it at startup, increment when it changes (fork id), ...)
  • Before pushing peers up to the p2p level for connection we should probably filter on the fork id


// In some versions stop() returns void; in others it returns a future.
try {
final Method m = discovery.getClass().getMethod("stop");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can just check what the current version of the discV5 library returns ...


/** Stop asynchronously. */
public CompletableFuture<Void> stopAsync() {
final ScheduledFuture<?> t = pollTask;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: variable is not necessary.


/** Start the DiscV5 system (idempotent). */
public synchronized void start() {
if (started) return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably want to make started atomic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll update started to use AtomicBoolean for safe concurrent access.

@pr9t
Copy link
Contributor Author

pr9t commented Oct 17, 2025

There are a few things that are still missing:

  • I think we should make sure to ping the bootnodes regularly, to increase our chances of being discovered
  • We should kick off random finds to discover other nodes quicker, which is more important right after start, maybe less once we have found max peers
  • We need to handle the sequence number of out node record (store it, retrieve it at startup, increment when it changes (fork id), ...)
  • Before pushing peers up to the p2p level for connection we should probably filter on the fork id

Thanks for the feedback! I’ll work on adding these improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

implement discv5 handling

4 participants