public void updateNodeRecord() {
    if (!config.isEnabled()) {
      return;
    }

    final NodeRecordFactory nodeRecordFactory = NodeRecordFactory.DEFAULT;
    final Optional<NodeRecord> existingNodeRecord =
        variablesStorage.getLocalEnrSeqno().map(nodeRecordFactory::fromBytes);

    final Bytes addressBytes = Bytes.of(InetAddresses.forString(advertisedAddress).getAddress());
    final Optional<EnodeURL> maybeEnodeURL = localNode.map(DiscoveryPeer::getEnodeURL);
    final Integer discoveryPort = maybeEnodeURL.flatMap(EnodeURL::getDiscoveryPort).orElse(0);
    final Integer listeningPort = maybeEnodeURL.flatMap(EnodeURL::getListeningPort).orElse(0);
    final String forkIdEnrField = "eth";
    final NodeRecord newNodeRecord =
        existingNodeRecord
            .filter(
                nodeRecord ->
                    id.equals(nodeRecord.get(EnrField.PKEY_SECP256K1))
                        && addressBytes.equals(nodeRecord.get(EnrField.IP_V4))
                        && discoveryPort.equals(nodeRecord.get(EnrField.UDP))
                        && listeningPort.equals(nodeRecord.get(EnrField.TCP))
                        && forkIdSupplier.get().equals(nodeRecord.get(forkIdEnrField)))
            .orElseGet(
                () -> {
                  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(
                              SIGNATURE_ALGORITHM.get().getCurveName(),
                              SIGNATURE_ALGORITHM
                                  .get()
                                  .compressPublicKey(
                                      SIGNATURE_ALGORITHM.get().createPublicKey(id))),
                          new EnrField(EnrField.IP_V4, addressBytes),
                          new EnrField(EnrField.TCP, listeningPort),
                          new EnrField(EnrField.UDP, discoveryPort),
                          new EnrField(
                              forkIdEnrField, Collections.singletonList(forkIdSupplier.get())));
                  nodeRecord.setSignature(
                      nodeKey
                          .sign(Hash.keccak256(nodeRecord.serializeNoSignature()))
                          .encodedBytes()
                          .slice(0, 64));

                  LOG.info("Writing node record to disk. {}", nodeRecord);
                  final var variablesUpdater = variablesStorage.updater();
                  variablesUpdater.setLocalEnrSeqno(nodeRecord.serialize());
                  variablesUpdater.commit();

                  return nodeRecord;
                });
    localNode
        .orElseThrow(() -> new IllegalStateException("Local node should be set here"))
        .setNodeRecord(newNodeRecord);
  }
The peer discovery agent is the network component that sends and receives peer discovery messages
via UDP.
ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java