Skip to content

Commit

Permalink
Create/update/store ethereum node record(ENR) (hyperledger#1680)
Browse files Browse the repository at this point in the history
* hyperledger#1561 - Create/store/update ENR when local node is created

Signed-off-by: David Mechler <david.mechler@consensys.net>

* hyperledger#1561 - spotlessApply

Signed-off-by: David Mechler <david.mechler@consensys.net>

* Update discovery library to prod version 0.4.1

Signed-off-by: David Mechler <david.mechler@consensys.net>
  • Loading branch information
David Mechler authored Dec 9, 2020
1 parent e365938 commit 8497b32
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ public void startNode(final BesuNode node) {
.collect(Collectors.toList()))
.besuPluginContext(new BesuPluginContextImpl())
.autoLogBloomCaching(false)
.storageProvider(storageProvider)
.build();

runner.start();
Expand Down
8 changes: 8 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.hyperledger.besu.ethereum.permissioning.node.NodePermissioningController;
import org.hyperledger.besu.ethereum.permissioning.node.PeerPermissionsAdapter;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionObserver;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.stratum.StratumServer;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
Expand Down Expand Up @@ -167,6 +168,7 @@ public class RunnerBuilder {
private BesuPluginContextImpl besuPluginContext;
private boolean autoLogBloomCaching = true;
private boolean randomPeerPriority;
private StorageProvider storageProvider;

public RunnerBuilder vertx(final Vertx vertx) {
this.vertx = vertx;
Expand Down Expand Up @@ -333,6 +335,11 @@ public RunnerBuilder autoLogBloomCaching(final boolean autoLogBloomCaching) {
return this;
}

public RunnerBuilder storageProvider(final StorageProvider storageProvider) {
this.storageProvider = storageProvider;
return this;
}

public Runner build() {

Preconditions.checkNotNull(besuController);
Expand Down Expand Up @@ -418,6 +425,7 @@ public Runner build() {
.supportedCapabilities(caps)
.natService(natService)
.randomPeerPriority(randomPeerPriority)
.storageProvider(storageProvider)
.build();

final NetworkRunner networkRunner =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,7 @@ private void synchronize(
.autoLogBloomCaching(autoLogBloomCachingEnabled)
.ethstatsUrl(unstableEthstatsOptions.getEthstatsUrl())
.ethstatsContact(unstableEthstatsOptions.getEthstatsContact())
.storageProvider(keyStorageProvider(keyValueStorageName))
.build();

addShutdownHook(runner);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;

Expand Down Expand Up @@ -119,6 +120,7 @@ public void enodeUrlShouldHaveAdvertisedHostWhenDiscoveryDisabled() {
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(vertx)
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.build();
runner.start();

Expand Down
3 changes: 2 additions & 1 deletion besu/src/test/java/org/hyperledger/besu/RunnerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesi
.p2pListenPort(0)
.maxPeers(3)
.metricsSystem(noOpMetricsSystem)
.staticNodes(emptySet());
.staticNodes(emptySet())
.storageProvider(new InMemoryStorageProvider());

Runner runnerBehind = null;
final Runner runnerAhead =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ public void initMocks() throws Exception {
when(mockRunnerBuilder.pidPath(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.ethstatsUrl(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.ethstatsContact(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.storageProvider(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);

final Bytes32 keyPairPrvKey =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.blockcreation.EthHashMiningCoordinator;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
Expand Down Expand Up @@ -261,6 +262,7 @@ private P2PNetwork createP2pNetwork() {
.vertx(vertx)
.config(config)
.metricsSystem(new NoOpMetricsSystem())
.storageProvider(new InMemoryStorageProvider())
.build();

p2pNetwork.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
Expand Down Expand Up @@ -166,6 +167,7 @@ public TestNode(
.config(networkingConfiguration)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(capabilities)
.storageProvider(new InMemoryStorageProvider())
.build())
.metricsSystem(new NoOpMetricsSystem())
.build();
Expand Down
1 change: 1 addition & 0 deletions ethereum/p2p/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ dependencies {

annotationProcessor "org.immutables:value"
implementation "org.immutables:value-annotations"
implementation 'tech.pegasys.discovery:discovery'

runtimeOnly 'org.apache.logging.log4j:log4j-core'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.tuweni.bytes.Bytes.wrapBuffer;

import org.hyperledger.besu.crypto.NodeKey;
Expand All @@ -30,8 +31,12 @@
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.ethereum.p2p.peers.PeerId;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.util.NetworkUtility;
import org.hyperledger.besu.util.Subscribers;

Expand All @@ -49,13 +54,20 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt64;
import org.ethereum.beacon.discovery.schema.EnrField;
import org.ethereum.beacon.discovery.schema.IdentitySchema;
import org.ethereum.beacon.discovery.schema.IdentitySchemaInterpreter;
import org.ethereum.beacon.discovery.schema.NodeRecord;
import org.ethereum.beacon.discovery.schema.NodeRecordFactory;

/**
* The peer discovery agent is the network component that sends and receives peer discovery messages
* via UDP.
*/
public abstract class PeerDiscoveryAgent {
private static final Logger LOG = LogManager.getLogger();
private static final String SEQ_NO_STORE_KEY = "local-enr-seqno";

// The devp2p specification says only accept packets up to 1280, but some
// clients ignore that, so we add in a little extra padding.
Expand Down Expand Up @@ -83,12 +95,15 @@ public abstract class PeerDiscoveryAgent {
private boolean isActive = false;
protected final Subscribers<PeerBondedObserver> peerBondedObservers = Subscribers.create();

private final StorageProvider storageProvider;

protected PeerDiscoveryAgent(
final NodeKey nodeKey,
final DiscoveryConfiguration config,
final PeerPermissions peerPermissions,
final NatService natService,
final MetricsSystem metricsSystem) {
final MetricsSystem metricsSystem,
final StorageProvider storageProvider) {
this.metricsSystem = metricsSystem;
checkArgument(nodeKey != null, "nodeKey cannot be null");
checkArgument(config != null, "provided configuration cannot be null");
Expand All @@ -104,6 +119,8 @@ protected PeerDiscoveryAgent(
this.nodeKey = nodeKey;

id = nodeKey.getPublicKey().getEncodedBytes();

this.storageProvider = storageProvider;
}

protected abstract TimerUtil createTimer();
Expand Down Expand Up @@ -144,6 +161,7 @@ public CompletableFuture<Integer> start(final int tcpPort) {
isActive = true;
LOG.info("P2P peer discovery agent started and listening on {}", localAddress);
startController(ourNode);
addLocalNodeRecord(id, advertisedAddress, tcpPort, discoveryPort);
return discoveryPort;
});
} else {
Expand All @@ -152,6 +170,45 @@ public CompletableFuture<Integer> start(final int tcpPort) {
}
}

private void addLocalNodeRecord(
final Bytes nodeId,
final String advertisedAddress,
final Integer tcpPort,
final Integer udpPort) {
final KeyValueStorage keyValueStorage =
storageProvider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.BLOCKCHAIN);
final NodeRecordFactory nodeRecordFactory = new NodeRecordFactory(IdentitySchemaInterpreter.V4);
final Optional<NodeRecord> existingNodeRecord =
keyValueStorage
.get(Bytes.of(SEQ_NO_STORE_KEY.getBytes(UTF_8)).toArray())
.map(Bytes::of)
.flatMap(b -> Optional.of(nodeRecordFactory.fromBytes(b)));

final Bytes addressBytes = Bytes.of(advertisedAddress.getBytes(UTF_8));
if (existingNodeRecord.isEmpty()
|| !existingNodeRecord.get().getNodeId().equals(nodeId)
|| !addressBytes.equals(existingNodeRecord.get().get(EnrField.IP_V4))
|| !tcpPort.equals(existingNodeRecord.get().get(EnrField.TCP))
|| !udpPort.equals(existingNodeRecord.get().get(EnrField.UDP))) {
final UInt64 sequenceNumber =
existingNodeRecord.map(NodeRecord::getSeq).orElse(UInt64.ZERO).add(1);
final NodeRecord nodeRecord =
nodeRecordFactory.createFromValues(
sequenceNumber,
new EnrField(EnrField.ID, IdentitySchema.V4),
new EnrField(EnrField.PKEY_SECP256K1, nodeId),
new EnrField(EnrField.IP_V4, addressBytes),
new EnrField(EnrField.TCP, tcpPort),
new EnrField(EnrField.UDP, udpPort));

final KeyValueStorageTransaction keyValueStorageTransaction =
keyValueStorage.startTransaction();
keyValueStorageTransaction.put(
Bytes.wrap(SEQ_NO_STORE_KEY.getBytes(UTF_8)).toArray(), nodeRecord.serialize().toArray());
keyValueStorageTransaction.commit();
}
}

public void addPeerRequirement(final PeerRequirement peerRequirement) {
this.peerRequirements.add(peerRequirement);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.hyperledger.besu.ethereum.p2p.discovery.internal.TimerUtil;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.VertxTimerUtil;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.plugin.services.MetricsSystem;
Expand Down Expand Up @@ -62,8 +63,9 @@ public VertxPeerDiscoveryAgent(
final DiscoveryConfiguration config,
final PeerPermissions peerPermissions,
final NatService natService,
final MetricsSystem metricsSystem) {
super(nodeKey, config, peerPermissions, natService, metricsSystem);
final MetricsSystem metricsSystem,
final StorageProvider storageProvider) {
super(nodeKey, config, peerPermissions, natService, metricsSystem, storageProvider);
checkArgument(vertx != null, "vertx instance cannot be null");
this.vertx = vertx;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.nat.NatMethod;
import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.nat.core.domain.NatServiceType;
Expand Down Expand Up @@ -439,6 +440,7 @@ public static class Builder {
private boolean randomPeerPriority;

private MetricsSystem metricsSystem;
private StorageProvider storageProvider;

public P2PNetwork build() {
validate();
Expand Down Expand Up @@ -477,13 +479,20 @@ private void validate() {
supportedCapabilities != null && supportedCapabilities.size() > 0,
"Supported capabilities must be set and non-empty.");
checkState(metricsSystem != null, "MetricsSystem must be set.");
checkState(storageProvider != null, "StorageProvider must be set.");
checkState(peerDiscoveryAgent != null || vertx != null, "Vertx must be set.");
}

private PeerDiscoveryAgent createDiscoveryAgent() {

return new VertxPeerDiscoveryAgent(
vertx, nodeKey, config.getDiscovery(), peerPermissions, natService, metricsSystem);
vertx,
nodeKey,
config.getDiscovery(),
peerPermissions,
natService,
metricsSystem,
storageProvider);
}

private RlpxAgent createRlpxAgent(
Expand Down Expand Up @@ -568,5 +577,11 @@ public Builder maintainedPeers(final MaintainedPeers maintainedPeers) {
this.maintainedPeers = maintainedPeers;
return this;
}

public Builder storageProvider(final StorageProvider storageProvider) {
checkNotNull(storageProvider);
this.storageProvider = storageProvider;
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.p2p.discovery.internal;

import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryAgent;
Expand Down Expand Up @@ -49,7 +50,13 @@ public MockPeerDiscoveryAgent(
final PeerPermissions peerPermissions,
final Map<Bytes, MockPeerDiscoveryAgent> agentNetwork,
final NatService natService) {
super(nodeKey, config, peerPermissions, natService, new NoOpMetricsSystem());
super(
nodeKey,
config,
peerPermissions,
natService,
new NoOpMetricsSystem(),
new InMemoryStorageProvider());
this.agentNetwork = agentNetwork;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration;
Expand Down Expand Up @@ -336,6 +337,7 @@ private DefaultP2PNetwork.Builder builder() {
.nodeKey(nodeKey)
.maintainedPeers(maintainedPeers)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Capability.create("eth", 63));
.supportedCapabilities(Capability.create("eth", 63))
.storageProvider(new InMemoryStorageProvider());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryServiceException;
Expand Down Expand Up @@ -158,6 +159,7 @@ private DefaultP2PNetwork.Builder builder() {
.nodeKey(nodeKey)
.config(config)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)));
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryStorageProvider());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration;
Expand Down Expand Up @@ -333,6 +334,7 @@ private DefaultP2PNetwork.Builder builder() {
.config(config)
.nodeKey(NodeKeyUtils.generate())
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)));
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryStorageProvider());
}
}
2 changes: 2 additions & 0 deletions gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,7 @@ dependencyManagement {
dependency 'tech.pegasys.ethsigner.internal:core:0.4.0'
dependency 'tech.pegasys.ethsigner.internal:file-based:0.4.0'
dependency 'tech.pegasys.ethsigner.internal:signing-api:0.4.0'

dependency 'tech.pegasys.discovery:discovery:0.4.1'
}
}

0 comments on commit 8497b32

Please sign in to comment.