Skip to content

Commit e4902af

Browse files
feat: Node discovery via DNS (#7129)
- Node discovery via DNS module as a vertex verticle (code adapted from Tuweni) - Mock DNS server in unit tests. --------- Signed-off-by: Usman Saleem <[email protected]> Co-authored-by: Sally MacFarlane <[email protected]>
1 parent 9d8c191 commit e4902af

File tree

18 files changed

+1376
-25
lines changed

18 files changed

+1376
-25
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- Default bonsai to use full-flat db and code-storage-by-code-hash [#6984](https://github.com/hyperledger/besu/pull/6894)
2424
- New RPC methods miner_setExtraData and miner_getExtraData [#7078](https://github.com/hyperledger/besu/pull/7078)
2525
- Disconnect peers that have multiple discovery ports since they give us bad neighbours [#7089](https://github.com/hyperledger/besu/pull/7089)
26+
- Port Tuweni dns-discovery into Besu. [#7129](https://github.com/hyperledger/besu/pull/7129)
2627

2728
### Known Issues
2829
- [Frequency: occasional < 10%] Chain download halt. Only affects new syncs (new nodes syncing from scratch). Symptom: Block import halts, despite having a full set of peers and world state downloading finishing. Generally restarting besu will resolve the issue. We are tracking this in [#6884](https://github.com/hyperledger/besu/pull/6884)

NOTICE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Hyperledger Besu
2+
Copyright contributors to Hyperledger Besu.
3+
4+
This product includes software adapted from Tuweni. (https://tuweni.tmio.io/)
5+
Copyright 2023-2024 The Machine Consultancy LLC
6+
Licensed under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
7+
8+
The following NOTICE file content is provided by Tuweni:
9+
------------------------------------------------------------
10+
This product includes code developed under the Apache Tuweni incubation project.
11+
12+
Copyright 2019-2023 The Apache Software Foundation
13+
14+
This product includes software developed at
15+
The Apache Software Foundation (http://www.apache.org/).
16+
17+
In addition, this product includes software developed by
18+
Copyright 2018-2019 ConsenSys, Inc.
19+
------------------------------------------------------------

NOTICE.md

Whitespace-only changes.

ethereum/p2p/build.gradle

+1-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ dependencies {
5050
implementation('io.tmio:tuweni-devp2p') {
5151
exclude group:'ch.qos.logback', module:'logback-classic'
5252
}
53-
implementation('io.tmio:tuweni-dns-discovery'){
54-
exclude group:'ch.qos.logback', module:'logback-classic'
55-
}
5653
implementation 'io.tmio:tuweni-io'
5754
implementation 'io.tmio:tuweni-rlp'
5855
implementation 'io.tmio:tuweni-units'
@@ -84,6 +81,7 @@ dependencies {
8481
}
8582
testImplementation 'io.vertx:vertx-codegen'
8683
testImplementation 'io.vertx:vertx-unit'
84+
testImplementation 'io.vertx:vertx-junit5'
8785
testImplementation 'org.assertj:assertj-core'
8886
testImplementation 'org.awaitility:awaitility'
8987
testImplementation 'org.junit.jupiter:junit-jupiter'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
16+
17+
import java.util.List;
18+
import java.util.Optional;
19+
20+
import io.vertx.core.AbstractVerticle;
21+
import org.apache.tuweni.devp2p.EthereumNodeRecord;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
25+
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
26+
/**
27+
* Resolves DNS records over time, refreshing records. This is written as a Vertx Verticle which
28+
* allows to run outside the Vertx event loop
29+
*/
30+
public class DNSDaemon extends AbstractVerticle {
31+
private static final Logger LOG = LoggerFactory.getLogger(DNSDaemon.class);
32+
private final String enrLink;
33+
private final long seq;
34+
private final long initialDelay;
35+
private final long delay;
36+
private final Optional<DNSDaemonListener> listener;
37+
private final Optional<String> dnsServer;
38+
private Optional<Long> periodicTaskId = Optional.empty();
39+
private DNSResolver dnsResolver;
40+
41+
/**
42+
* Creates a new DNSDaemon.
43+
*
44+
* @param enrLink the ENR link to start with, of the form enrtree://PUBKEY@domain
45+
* @param listener Listener notified when records are read and whenever they are updated.
46+
* @param seq the sequence number of the root record. If the root record seq is higher, proceed
47+
* with visit.
48+
* @param initialDelay the delay in milliseconds before the first poll of DNS records.
49+
* @param delay the delay in milliseconds at which to poll DNS records. If negative or zero, it
50+
* runs only once.
51+
* @param dnsServer the DNS server to use for DNS query. If null, the default DNS server will be
52+
* used.
53+
*/
54+
public DNSDaemon(
55+
final String enrLink,
56+
final DNSDaemonListener listener,
57+
final long seq,
58+
final long initialDelay,
59+
final long delay,
60+
final String dnsServer) {
61+
this.enrLink = enrLink;
62+
this.listener = Optional.ofNullable(listener);
63+
this.seq = seq;
64+
this.initialDelay = initialDelay;
65+
this.delay = delay;
66+
this.dnsServer = Optional.ofNullable(dnsServer);
67+
}
68+
69+
/** Starts the DNSDaemon. */
70+
@Override
71+
public void start() {
72+
if (vertx == null) {
73+
throw new IllegalStateException("DNSDaemon must be deployed as a vertx verticle.");
74+
}
75+
76+
LOG.info("Starting DNSDaemon for {}, using {} DNS host.", enrLink, dnsServer.orElse("default"));
77+
dnsResolver = new DNSResolver(vertx, enrLink, seq, dnsServer);
78+
if (delay > 0) {
79+
periodicTaskId = Optional.of(vertx.setPeriodic(initialDelay, delay, this::refreshENRRecords));
80+
} else {
81+
// do one-shot resolution
82+
refreshENRRecords(0L);
83+
}
84+
}
85+
86+
/** Stops the DNSDaemon. */
87+
@Override
88+
public void stop() {
89+
LOG.info("Stopping DNSDaemon for {}", enrLink);
90+
periodicTaskId.ifPresent(vertx::cancelTimer);
91+
dnsResolver.close();
92+
}
93+
94+
/**
95+
* Refresh enr records by calling dnsResolver and updating the listeners.
96+
*
97+
* @param taskId the task id of the periodic task
98+
*/
99+
void refreshENRRecords(final Long taskId) {
100+
LOG.debug("Refreshing DNS records");
101+
final long startTime = System.nanoTime();
102+
final List<EthereumNodeRecord> ethereumNodeRecords = dnsResolver.collectAll();
103+
final long endTime = System.nanoTime();
104+
LOG.debug("Time taken to DNSResolver.collectAll: {} ms", (endTime - startTime) / 1_000_000);
105+
listener.ifPresent(it -> it.newRecords(dnsResolver.sequence(), ethereumNodeRecords));
106+
}
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
16+
17+
import java.util.List;
18+
19+
import org.apache.tuweni.devp2p.EthereumNodeRecord;
20+
21+
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
22+
/** Callback listening to updates of the DNS records. */
23+
@FunctionalInterface
24+
public interface DNSDaemonListener {
25+
/**
26+
* Callback called when the seq is updated on the DNS server
27+
*
28+
* @param seq the update identifier of the records
29+
* @param records the records stored on the server
30+
*/
31+
void newRecords(long seq, List<EthereumNodeRecord> records);
32+
}

0 commit comments

Comments
 (0)