-
Couldn't load subscription status.
- Fork 978
feat: add DiscV5 config and DiscV5 service (MutableDiscoverySystem) + test case for Service #9238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Preeti <[email protected]>
ethereum/p2p/build.gradle
Outdated
| implementation("tech.pegasys.discovery:discovery:25.4.0") { | ||
| exclude group: "org.apache.tuweni" | ||
| } |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
….tuweni centrally Signed-off-by: Preeti <[email protected]>
There was a problem hiding this 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?
| this.bootEnrs = Collections.unmodifiableList(new ArrayList<>(b.bootEnrs)); | ||
| this.bindInterfaces = Collections.unmodifiableList(new ArrayList<>(b.bindInterfaces)); | ||
| this.advertisedIps = Collections.unmodifiableList(new ArrayList<>(b.advertisedIps)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * Copyright ConsenSys AG. | |
| * Copyright contributors to Hyperledger Besu. |
| private final ScheduledExecutorService scheduler = | ||
| Executors.newSingleThreadScheduledExecutor( | ||
| r -> { | ||
| final Thread t = new Thread(r, "besu-discv5-poller"); | ||
| t.setDaemon(true); | ||
| return t; | ||
| }); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Signed-off-by: Preeti <[email protected]>
|
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 ( |
There was a problem hiding this 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"); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
|
hey @pinges could you have a look from p2p POV - any changes you would like to see on this approach? |
There was a problem hiding this 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"); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Thanks for the feedback! I’ll work on adding these improvements. |
Signed-off-by: Preeti <[email protected]>
PR description
tech.pegasys.discovery:discovery:<25.4.0>and excludesorg.apache.tuwenito avoid clashes with existing io.consensys.tuweni jars used elsewhere.DiscoveryV5Config.java(builder-style config used by the service)DiscoveryV5Service(thin wrapper around MutableDiscoverySystem).DiscoveryV5ServiceTest) that starts/stops and asserts ENR presence.Fixed Issue(s)
fixes #4089
Thanks for sending a pull request! Have you done the following?
doc-change-requiredlabel to this PR if updates are required.Locally, you can run these tests to catch failures early:
./gradlew spotlessApply./gradlew build./gradlew acceptanceTest./gradlew integrationTest./gradlew ethereum:referenceTests:referenceTests