Merge branch 'main' into zkbesu

This commit is contained in:
Fabio Di Fabio
2024-06-06 18:16:51 +02:00
54 changed files with 1931 additions and 462 deletions

19
.github/workflows/dco.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: DCO
on: [pull_request]
jobs:
dco_check:
runs-on: ubuntu-latest
name: DCO
if: ${{ github.actor != 'dependabot[bot]' }}
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@198af03565609bb4ed924d1260247b4881f09e7d
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@f2279e6e62d5a7d9115b0cb8e837b777b1b02e21
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}

View File

@@ -3,8 +3,13 @@
## Next Release
### Breaking Changes
- Java 21 has been enforced as minimum version to build and run Besu.
- In profile=ENTERPRISE, use sync-mode=FULL (instead of FAST) and data-storage-format=FOREST (instead of BONSAI) [#7186](https://github.com/hyperledger/besu/pull/7186)
- If this breaks your node, you can reset sync-mode=FAST and data-storage-format=BONSAI
### Additions and Improvements
- Add two counters to DefaultBlockchain in order to be able to calculate TPS and Mgas/s [#7105](https://github.com/hyperledger/besu/pull/7105)
- `admin_nodeInfo` JSON/RPC call returns the currently active EVM version [#7127](https://github.com/hyperledger/besu/pull/7127)
### Bug fixes
- Make `eth_gasPrice` aware of the base fee market [#7102](https://github.com/hyperledger/besu/pull/7102)
@@ -21,6 +26,7 @@
- Default bonsai to use full-flat db and code-storage-by-code-hash [#6984](https://github.com/hyperledger/besu/pull/6894)
- New RPC methods miner_setExtraData and miner_getExtraData [#7078](https://github.com/hyperledger/besu/pull/7078)
- Disconnect peers that have multiple discovery ports since they give us bad neighbours [#7089](https://github.com/hyperledger/besu/pull/7089)
- Port Tuweni dns-discovery into Besu. [#7129](https://github.com/hyperledger/besu/pull/7129)
### Known Issues
- [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)
@@ -28,6 +34,7 @@
### Bug fixes
- Fix parsing `gasLimit` parameter when its value is > `Long.MAX_VALUE` [#7116](https://github.com/hyperledger/besu/pull/7116)
- Skip validation of withdrawals when importing BFT blocks since withdrawals don't apply to BFT chains [#7115](https://github.com/hyperledger/besu/pull/7115)
- Make `v` abd `yParity` match in type 1 and 2 transactions in JSON-RPC and GraphQL [#7139](https://github.com/hyperledger/besu/pull/7139)
### Download Links
https://github.com/hyperledger/besu/releases/tag/24.5.2

19
NOTICE Normal file
View File

@@ -0,0 +1,19 @@
Hyperledger Besu
Copyright contributors to Hyperledger Besu.
This product includes software adapted from Tuweni. (https://tuweni.tmio.io/)
Copyright 2023-2024 The Machine Consultancy LLC
Licensed under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
The following NOTICE file content is provided by Tuweni:
------------------------------------------------------------
This product includes code developed under the Apache Tuweni incubation project.
Copyright 2019-2023 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
In addition, this product includes software developed by
Copyright 2018-2019 ConsenSys, Inc.
------------------------------------------------------------

View File

View File

@@ -1891,7 +1891,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
public BesuControllerBuilder getControllerBuilder() {
pluginCommonConfiguration
.init(dataDir(), dataDir().resolve(DATABASE_PATH), getDataStorageConfiguration())
.withMiningParameters(getMiningParameters())
.withMiningParameters(miningParametersSupplier.get())
.withJsonRpcHttpOptions(jsonRpcHttpOptions);
final KeyValueStorageProvider storageProvider = keyValueStorageProvider(keyValueStorageName);
return controllerBuilderFactory

View File

@@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.cli.config;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
/** Enum for profile names. Each profile corresponds to a configuration file. */
@@ -53,6 +51,6 @@ public enum ProfileName {
@Override
public String toString() {
return StringUtils.capitalize(name().replaceAll("_", " ").toLowerCase(Locale.ROOT));
return StringUtils.capitalize(name().replaceAll("_", " "));
}
}

View File

@@ -42,6 +42,9 @@ public class BlockchainServiceImpl implements BlockchainService {
private ProtocolSchedule protocolSchedule;
private MutableBlockchain blockchain;
/** Instantiates a new Blockchain service implementation. */
public BlockchainServiceImpl() {}
/**
* Instantiates a new Blockchain service.
*

View File

@@ -32,8 +32,8 @@ plugins {
id 'maven-publish'
}
if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
throw new GradleException("Java 17 or later is required to build Besu.\n" +
if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_21)) {
throw new GradleException("Java 21 or later is required to build Besu.\n" +
" Detected version ${JavaVersion.current()}")
}
@@ -110,7 +110,7 @@ allprojects {
version = calculateVersion()
jacoco {
toolVersion = '0.8.8'
toolVersion = '0.8.11'
if (project.tasks.findByName('referenceTests')) {
applyTo referenceTests
}
@@ -129,8 +129,8 @@ allprojects {
tasks.build {
dependsOn 'javadoc'
}
sourceCompatibility = 17
targetCompatibility = 17
sourceCompatibility = 21
targetCompatibility = 21
repositories {
maven {

View File

@@ -1,4 +1,5 @@
sync-mode="FAST"
sync-mode="FULL"
data-storage-format="FOREST"
sync-min-peers=1
remote-connections-limit-enabled=false
tx-pool="SEQUENCED"

View File

@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLContextType;
@@ -248,7 +249,13 @@ public class TransactionAdapter extends AdapterBase {
}
public Optional<BigInteger> getV() {
return Optional.ofNullable(transactionWithMetadata.getTransaction().getV());
BigInteger v = transactionWithMetadata.getTransaction().getV();
return Optional.ofNullable(
v == null
&& (transactionWithMetadata.getTransaction().getType().getEthSerializedType()
< TransactionType.BLOB.getEthSerializedType())
? transactionWithMetadata.getTransaction().getYParity()
: v);
}
public Optional<BigInteger> getYParity() {

View File

@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.ChainHead;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
@@ -47,6 +48,7 @@ public class AdminNodeInfo implements JsonRpcMethod {
private final P2PNetwork peerNetwork;
private final BlockchainQueries blockchainQueries;
private final NatService natService;
private final ProtocolSchedule protocolSchedule;
public AdminNodeInfo(
final String clientVersion,
@@ -54,13 +56,15 @@ public class AdminNodeInfo implements JsonRpcMethod {
final GenesisConfigOptions genesisConfigOptions,
final P2PNetwork peerNetwork,
final BlockchainQueries blockchainQueries,
final NatService natService) {
final NatService natService,
final ProtocolSchedule protocolSchedule) {
this.peerNetwork = peerNetwork;
this.clientVersion = clientVersion;
this.genesisConfigOptions = genesisConfigOptions;
this.blockchainQueries = blockchainQueries;
this.networkId = networkId;
this.natService = natService;
this.protocolSchedule = protocolSchedule;
}
@Override
@@ -126,6 +130,9 @@ public class AdminNodeInfo implements JsonRpcMethod {
"network",
networkId)));
response.put(
"activeFork", protocolSchedule.getByBlockHeader(chainHead.getBlockHeader()).getName());
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response);
}

View File

@@ -126,7 +126,7 @@ public class TransactionCompleteResult implements TransactionResult {
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
? Quantity.create(transaction.getV())
? Quantity.create(transaction.getYParity())
: null;
}
this.value = Quantity.create(transaction.getValue());

View File

@@ -116,7 +116,7 @@ public class TransactionPendingResult implements TransactionResult {
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
? Quantity.create(transaction.getV())
? Quantity.create(transaction.getYParity())
: null;
}
this.value = Quantity.create(transaction.getValue());

View File

@@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.PluginsReloadConfiguration;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.nat.NatService;
@@ -48,6 +49,7 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final Map<String, BesuPlugin> namedPlugins;
private final EthPeers ethPeers;
private final Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
private final ProtocolSchedule protocolSchedule;
public AdminJsonRpcMethods(
final String clientVersion,
@@ -58,7 +60,8 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
final Map<String, BesuPlugin> namedPlugins,
final NatService natService,
final EthPeers ethPeers,
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration,
final ProtocolSchedule protocolSchedule) {
this.clientVersion = clientVersion;
this.networkId = networkId;
this.genesisConfigOptions = genesisConfigOptions;
@@ -68,6 +71,7 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.natService = natService;
this.ethPeers = ethPeers;
this.enodeDnsConfiguration = enodeDnsConfiguration;
this.protocolSchedule = protocolSchedule;
}
@Override
@@ -86,7 +90,8 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
genesisConfigOptions,
p2pNetwork,
blockchainQueries,
natService),
natService,
protocolSchedule),
new AdminPeers(ethPeers),
new AdminChangeLogLevel(),
new AdminGenerateLogBloomCache(blockchainQueries),

View File

@@ -97,7 +97,8 @@ public class JsonRpcMethodsFactory {
namedPlugins,
natService,
ethPeers,
enodeDnsConfiguration),
enodeDnsConfiguration,
protocolSchedule),
new DebugJsonRpcMethods(
blockchainQueries,
protocolContext,

View File

@@ -73,7 +73,7 @@ public class PendingTransactionDetailResult implements JsonRpcResult {
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
? Quantity.create(tx.getV())
? Quantity.create(tx.getYParity())
: null;
}
this.value = Quantity.create(tx.getValue());

View File

@@ -155,8 +155,8 @@ public class GraphQLHttpServiceHostWhitelistTest {
@Test
public void requestWithMalformedHostIsRejected() throws IOException {
graphQLConfig.setHostsAllowlist(hostsWhitelist);
Assertions.assertThat(doRequest("ally:friend")).isEqualTo(403);
Assertions.assertThat(doRequest("ally:123456")).isEqualTo(403);
Assertions.assertThat(doRequest("ally:friend:1234")).isEqualTo(403);
Assertions.assertThat(doRequest("ally:friend")).isEqualTo(400);
Assertions.assertThat(doRequest("ally:123456")).isEqualTo(400);
Assertions.assertThat(doRequest("ally:friend:1234")).isEqualTo(400);
}
}

View File

@@ -206,8 +206,8 @@ public class JsonRpcHttpServiceHostAllowlistTest {
@Test
public void requestWithMalformedHostIsRejected() throws IOException {
jsonRpcConfig.setHostsAllowlist(hostsAllowlist);
assertThat(doRequest("ally:friend")).isEqualTo(403);
assertThat(doRequest("ally:123456")).isEqualTo(403);
assertThat(doRequest("ally:friend:1234")).isEqualTo(403);
assertThat(doRequest("ally:friend")).isEqualTo(400);
assertThat(doRequest("ally:123456")).isEqualTo(400);
assertThat(doRequest("ally:friend:1234")).isEqualTo(400);
}
}

View File

@@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@@ -33,6 +34,8 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.ChainHead;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
@@ -67,6 +70,8 @@ public class AdminNodeInfoTest {
@Mock private BlockchainQueries blockchainQueries;
@Mock private NatService natService;
@Mock private BlockHeader blockHeader;
@Mock private ProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
private AdminNodeInfo method;
@@ -93,6 +98,8 @@ public class AdminNodeInfoTest {
when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.EMPTY));
when(blockchain.getChainHead()).thenReturn(testChainHead);
when(natService.queryExternalIPAddress(anyString())).thenReturn("1.2.3.4");
when(protocolSpec.getName()).thenReturn("London");
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
method =
new AdminNodeInfo(
"testnet/1.0/this/that",
@@ -100,7 +107,8 @@ public class AdminNodeInfoTest {
genesisConfigOptions,
p2pNetwork,
blockchainQueries,
natService);
natService,
protocolSchedule);
}
@Test
@@ -110,6 +118,7 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map<String, Object> expected = new HashMap<>();
expected.put("activeFork", "London");
expected.put(
"enode",
"enode://0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807@1.2.3.4:30303?discport=7890");
@@ -161,6 +170,7 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map<String, Object> expected = new HashMap<>();
expected.put("activeFork", "London");
expected.put(
"enode",
"enode://0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807@3.4.5.6:8081?discport=8080");
@@ -207,6 +217,7 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map<String, Object> expected = new HashMap<>();
expected.put("activeFork", "London");
expected.put(
"enode",
"enode://0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807@1.2.3.4:0");
@@ -253,6 +264,7 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map<String, Object> expected = new HashMap<>();
expected.put("activeFork", "London");
expected.put(
"enode",
"enode://0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807@1.2.3.4:0?discport=7890");
@@ -299,6 +311,7 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map<String, Object> expected = new HashMap<>();
expected.put("activeFork", "London");
expected.put(
"enode",
"enode://0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807@1.2.3.4:7890?discport=0");
@@ -387,7 +400,8 @@ public class AdminNodeInfoTest {
genesisClassicConfigOptions,
p2pNetwork,
blockchainQueries,
natService);
natService,
protocolSchedule);
final JsonRpcRequestContext request = adminNodeInfo();

View File

@@ -196,9 +196,9 @@ public class WebSocketHostAllowlistTest {
public void httpRequestWithMalformedHostIsRejected() throws Throwable {
webSocketConfiguration.setAuthenticationEnabled(false);
webSocketConfiguration.setHostsAllowlist(hostsAllowlist);
doHttpRequestAndVerify(testContext, "ally:friend", 403);
doHttpRequestAndVerify(testContext, "ally:123456", 403);
doHttpRequestAndVerify(testContext, "ally:friend:1234", 403);
doHttpRequestAndVerify(testContext, "ally:friend", 400);
doHttpRequestAndVerify(testContext, "ally:123456", 400);
doHttpRequestAndVerify(testContext, "ally:friend:1234", 400);
}
private void doHttpRequestAndVerify(

View File

@@ -0,0 +1,29 @@
{
"request": "{block (number: 32) { difficulty extraData miner { address } mixHash nonce stateRoot totalDifficulty transactions { gasPrice type yParity v r s} }} ",
"response": {
"data": {
"block": {
"difficulty": "0x207c0",
"extraData": "0x",
"miner": {
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1"
},
"mixHash": "0x4edd77bfff565659bb0ae09421918e4def65d938a900eb94230eb01f5ce80c99",
"nonce": "0xdb063000b00e8026",
"stateRoot": "0xf65f3dd13f72f5fa5607a5224691419969b4f4bae7a00a6cdb853f2ca9eeb1be",
"totalDifficulty": "0x427c00",
"transactions": [
{
"gasPrice": "0x1",
"type": "0x0",
"yParity": null,
"v": "0x1b",
"r": "0x705b002a7df60707d33812e0298411721be20ea5a2f533707295140d89263b79",
"s": "0x78024390784f24160739533b3ceea2698289a02afd9cc768581b4aa3d5f4b105"
}
]
}
}
},
"statusCode": 200
}

View File

@@ -1,5 +1,5 @@
{
"request": "{block (number : 33) { baseFeePerGas difficulty extraData miner { address } mixHash nonce stateRoot totalDifficulty withdrawalsRoot withdrawals { address amount index validator } }} ",
"request": "{block (number : 33) { baseFeePerGas difficulty extraData miner { address } mixHash nonce stateRoot totalDifficulty transactions { r s v yParity } withdrawalsRoot withdrawals { address amount index validator } }} ",
"response": {
"data": {
"block": {
@@ -13,6 +13,14 @@
"nonce": "0x0000000000000000",
"stateRoot": "0x0d3c456bb68669bad05da3a1a766daab236c9df1da8f74edf5ebe9383f00084c",
"totalDifficulty": "0x427c00",
"transactions": [
{
"r": "0x8abbfbd4c5f2a13a8d5ed394ac50bac7d678f83a23f645818492f76e8ee17ab3",
"s": "0x7bd38c6929235f775d68b45bd7dea7981264f9a265b6bea97b070e15be88389c",
"v": "0x0",
"yParity": "0x0"
}
],
"withdrawalsRoot": "0x37945ab58d2712a26df2a38d217e822694927e29b30d5993d7a53ccea618d1f3",
"withdrawals": [
{

View File

@@ -17,7 +17,7 @@
"type": "0x2",
"status": "0x1",
"yParity": "0x0",
"v": "0x25"
"v": "0x0"
}
}
},

View File

@@ -58,7 +58,7 @@
"type": "0x2",
"value": "0x0",
"yParity": "0x0",
"v" : "0x25",
"v" : "0x0",
"r": "0x8abbfbd4c5f2a13a8d5ed394ac50bac7d678f83a23f645818492f76e8ee17ab3",
"s": "0x7bd38c6929235f775d68b45bd7dea7981264f9a265b6bea97b070e15be88389c"
}

View File

@@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import org.hyperledger.besu.util.InvalidConfigurationException;
import org.hyperledger.besu.util.Subscribers;
@@ -83,6 +84,9 @@ public class DefaultBlockchain implements MutableBlockchain {
private final Optional<Cache<Hash, List<TransactionReceipt>>> transactionReceiptsCache;
private final Optional<Cache<Hash, Difficulty>> totalDifficultyCache;
private final Counter gasUsedCounter;
private final Counter numberOfTransactionsCounter;
private DefaultBlockchain(
final Optional<Block> genesisBlock,
final BlockchainStorage blockchainStorage,
@@ -117,6 +121,7 @@ public class DefaultBlockchain implements MutableBlockchain {
"blockchain_height",
"The current height of the canonical chain",
this::getChainHeadBlockNumber);
metricsSystem.createGauge(
BesuMetricCategory.BLOCKCHAIN,
"difficulty_total",
@@ -135,6 +140,10 @@ public class DefaultBlockchain implements MutableBlockchain {
"Gas used by the current chain head block",
() -> getChainHeadHeader().getGasUsed());
gasUsedCounter =
metricsSystem.createCounter(
BesuMetricCategory.BLOCKCHAIN, "chain_head_gas_used_counter", "Counter for Gas used");
metricsSystem.createLongGauge(
BesuMetricCategory.BLOCKCHAIN,
"chain_head_gas_limit",
@@ -147,6 +156,12 @@ public class DefaultBlockchain implements MutableBlockchain {
"Number of transactions in the current chain head block",
() -> chainHeadTransactionCount);
numberOfTransactionsCounter =
metricsSystem.createCounter(
BesuMetricCategory.BLOCKCHAIN,
"chain_head_transaction_count_counter",
"Counter for the number of transactions");
metricsSystem.createIntegerGauge(
BesuMetricCategory.BLOCKCHAIN,
"chain_head_ommer_count",
@@ -524,6 +539,10 @@ public class DefaultBlockchain implements MutableBlockchain {
updater.setChainHead(newBlockHash);
indexTransactionForBlock(
updater, newBlockHash, blockWithReceipts.getBlock().getBody().getTransactions());
gasUsedCounter.inc(blockWithReceipts.getHeader().getGasUsed());
numberOfTransactionsCounter.inc(
blockWithReceipts.getBlock().getBody().getTransactions().size());
return BlockAddedEvent.createForHeadAdvancement(
blockWithReceipts.getBlock(),
LogWithMetadata.generate(

View File

@@ -495,14 +495,10 @@ public class Transaction
@Override
public BigInteger getV() {
if (transactionType != null
&& transactionType != TransactionType.FRONTIER
&& transactionType != TransactionType.ACCESS_LIST
&& transactionType != TransactionType.EIP1559) {
// Newer transaction type lacks V, so return null
if (transactionType != null && transactionType != TransactionType.FRONTIER) {
// EIP-2718 typed transaction, use yParity:
return null;
} else {
// Mandatory for legacy, optional for EIP-2930 and EIP-1559 TXes, prohibited for all others.
final BigInteger recId = BigInteger.valueOf(signature.getRecId());
return chainId
.map(bigInteger -> recId.add(REPLAY_PROTECTED_V_BASE).add(TWO.multiply(bigInteger)))

View File

@@ -45,7 +45,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@@ -364,27 +363,28 @@ public abstract class DiffBasedWorldStateUpdateAccumulator<ACCOUNT extends DiffB
return;
}
final TreeSet<Map.Entry<UInt256, UInt256>> entries =
new TreeSet<>(Map.Entry.comparingByKey());
entries.addAll(updatedAccount.getUpdatedStorage().entrySet());
// parallel stream here may cause database corruption
entries.forEach(
storageUpdate -> {
final UInt256 keyUInt = storageUpdate.getKey();
final StorageSlotKey slotKey =
new StorageSlotKey(hashAndSaveSlotPreImage(keyUInt), Optional.of(keyUInt));
final UInt256 value = storageUpdate.getValue();
final DiffBasedValue<UInt256> pendingValue = pendingStorageUpdates.get(slotKey);
if (pendingValue == null) {
pendingStorageUpdates.put(
slotKey,
new DiffBasedValue<>(
updatedAccount.getOriginalStorageValue(keyUInt), value));
} else {
pendingValue.setUpdated(value);
}
});
updatedAccount
.getUpdatedStorage()
.entrySet()
.forEach(
storageUpdate -> {
final UInt256 keyUInt = storageUpdate.getKey();
final StorageSlotKey slotKey =
new StorageSlotKey(
hashAndSaveSlotPreImage(keyUInt), Optional.of(keyUInt));
final UInt256 value = storageUpdate.getValue();
final DiffBasedValue<UInt256> pendingValue =
pendingStorageUpdates.get(slotKey);
if (pendingValue == null) {
pendingStorageUpdates.put(
slotKey,
new DiffBasedValue<>(
updatedAccount.getOriginalStorageValue(keyUInt), value));
} else {
pendingValue.setUpdated(value);
}
});
updatedAccount.getUpdatedStorage().clear();

View File

@@ -102,7 +102,8 @@ public class TimestampValidationRuleTest {
final BlockHeader parent = headerBuilder.buildHeader();
// Create header for validation with a timestamp in the future (1 second too far away)
headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift + 1);
// (+1 to avoid spurious failures)
headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift + 2);
final BlockHeader header = headerBuilder.buildHeader();
assertThat(uut00.validate(header, parent)).isFalse();
@@ -124,7 +125,7 @@ public class TimestampValidationRuleTest {
TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS));
final BlockHeader parent = headerBuilder.buildHeader();
// Create header for validation with a timestamp in the future (1 second too far away)
// Create header for validation with a timestamp an acceptable amount in the future
// (-1) to prevent spurious failures
headerBuilder.timestamp(parent.getTimestamp() + acceptableClockDrift - 1);
final BlockHeader header = headerBuilder.buildHeader();

View File

@@ -189,7 +189,7 @@ public class BackwardSyncAlgSpec {
completionCaptor.getValue().onInitialSyncCompleted();
voidCompletableFuture.get(500, TimeUnit.MILLISECONDS);
voidCompletableFuture.get(800, TimeUnit.MILLISECONDS);
assertThat(voidCompletableFuture).isCompleted();
verify(context.getSyncState()).unsubscribeTTDReached(88L);

View File

@@ -50,9 +50,6 @@ dependencies {
implementation('io.tmio:tuweni-devp2p') {
exclude group:'ch.qos.logback', module:'logback-classic'
}
implementation('io.tmio:tuweni-dns-discovery'){
exclude group:'ch.qos.logback', module:'logback-classic'
}
implementation 'io.tmio:tuweni-io'
implementation 'io.tmio:tuweni-rlp'
implementation 'io.tmio:tuweni-units'
@@ -84,6 +81,7 @@ dependencies {
}
testImplementation 'io.vertx:vertx-codegen'
testImplementation 'io.vertx:vertx-unit'
testImplementation 'io.vertx:vertx-junit5'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter'

View File

@@ -0,0 +1,107 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import java.util.List;
import java.util.Optional;
import io.vertx.core.AbstractVerticle;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/**
* Resolves DNS records over time, refreshing records. This is written as a Vertx Verticle which
* allows to run outside the Vertx event loop
*/
public class DNSDaemon extends AbstractVerticle {
private static final Logger LOG = LoggerFactory.getLogger(DNSDaemon.class);
private final String enrLink;
private final long seq;
private final long initialDelay;
private final long delay;
private final Optional<DNSDaemonListener> listener;
private final Optional<String> dnsServer;
private Optional<Long> periodicTaskId = Optional.empty();
private DNSResolver dnsResolver;
/**
* Creates a new DNSDaemon.
*
* @param enrLink the ENR link to start with, of the form enrtree://PUBKEY@domain
* @param listener Listener notified when records are read and whenever they are updated.
* @param seq the sequence number of the root record. If the root record seq is higher, proceed
* with visit.
* @param initialDelay the delay in milliseconds before the first poll of DNS records.
* @param delay the delay in milliseconds at which to poll DNS records. If negative or zero, it
* runs only once.
* @param dnsServer the DNS server to use for DNS query. If null, the default DNS server will be
* used.
*/
public DNSDaemon(
final String enrLink,
final DNSDaemonListener listener,
final long seq,
final long initialDelay,
final long delay,
final String dnsServer) {
this.enrLink = enrLink;
this.listener = Optional.ofNullable(listener);
this.seq = seq;
this.initialDelay = initialDelay;
this.delay = delay;
this.dnsServer = Optional.ofNullable(dnsServer);
}
/** Starts the DNSDaemon. */
@Override
public void start() {
if (vertx == null) {
throw new IllegalStateException("DNSDaemon must be deployed as a vertx verticle.");
}
LOG.info("Starting DNSDaemon for {}, using {} DNS host.", enrLink, dnsServer.orElse("default"));
dnsResolver = new DNSResolver(vertx, enrLink, seq, dnsServer);
if (delay > 0) {
periodicTaskId = Optional.of(vertx.setPeriodic(initialDelay, delay, this::refreshENRRecords));
} else {
// do one-shot resolution
refreshENRRecords(0L);
}
}
/** Stops the DNSDaemon. */
@Override
public void stop() {
LOG.info("Stopping DNSDaemon for {}", enrLink);
periodicTaskId.ifPresent(vertx::cancelTimer);
dnsResolver.close();
}
/**
* Refresh enr records by calling dnsResolver and updating the listeners.
*
* @param taskId the task id of the periodic task
*/
void refreshENRRecords(final Long taskId) {
LOG.debug("Refreshing DNS records");
final long startTime = System.nanoTime();
final List<EthereumNodeRecord> ethereumNodeRecords = dnsResolver.collectAll();
final long endTime = System.nanoTime();
LOG.debug("Time taken to DNSResolver.collectAll: {} ms", (endTime - startTime) / 1_000_000);
listener.ifPresent(it -> it.newRecords(dnsResolver.sequence(), ethereumNodeRecords));
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import java.util.List;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/** Callback listening to updates of the DNS records. */
@FunctionalInterface
public interface DNSDaemonListener {
/**
* Callback called when the seq is updated on the DNS server
*
* @param seq the update identifier of the records
* @param records the records stored on the server
*/
void newRecords(long seq, List<EthereumNodeRecord> records);
}

View File

@@ -0,0 +1,279 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static org.hyperledger.besu.ethereum.p2p.discovery.dns.KVReader.readKV;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.crypto.SECP256K1;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
import org.apache.tuweni.io.Base32;
import org.apache.tuweni.io.Base64URLSafe;
import org.bouncycastle.math.ec.ECPoint;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/** Intermediate format to write DNS entries */
public interface DNSEntry {
/**
* Read a DNS entry from a String.
*
* @param serialized the serialized form of a DNS entry
* @return DNS entry if found
* @throws IllegalArgumentException if the record cannot be read
*/
static DNSEntry readDNSEntry(final String serialized) {
final String record = trimQuotes(serialized);
final String prefix = getPrefix(record);
return switch (prefix) {
case "enrtree-root" -> new ENRTreeRoot(readKV(record));
case "enrtree-branch" -> new ENRTree(record.substring(prefix.length() + 1));
case "enr" -> new ENRNode(readKV(record));
case "enrtree" -> new ENRTreeLink(record);
default ->
throw new IllegalArgumentException(
serialized + " should contain enrtree-branch, enr, enrtree-root or enrtree");
};
}
private static String trimQuotes(final String str) {
if (str.startsWith("\"") && str.endsWith("\"")) {
return str.substring(1, str.length() - 1);
}
return str;
}
private static String getPrefix(final String input) {
final String[] parts = input.split(":", 2);
return parts.length > 0 ? parts[0] : "";
}
/** Represents a node in the ENR record. */
class ENRNode implements DNSEntry {
private final EthereumNodeRecord nodeRecord;
/**
* Constructs ENRNode with the given attributes.
*
* @param attrs the attributes of the node
*/
public ENRNode(final Map<String, String> attrs) {
if (attrs == null) {
throw new IllegalArgumentException("ENRNode attributes cannot be null");
}
nodeRecord =
Optional.ofNullable(attrs.get("enr"))
.map(Base64URLSafe::decode)
.map(EthereumNodeRecord::fromRLP)
.orElseThrow(() -> new IllegalArgumentException("Invalid ENR record"));
}
/**
* Ethereum node record.
*
* @return the instance of EthereumNodeRecord
*/
public EthereumNodeRecord nodeRecord() {
return nodeRecord;
}
@Override
public String toString() {
return nodeRecord.toString();
}
}
/** Root of the ENR tree */
class ENRTreeRoot implements DNSEntry {
private final String version;
private final Long seq;
private final SECP256K1.Signature sig;
private final String enrRoot;
private final String linkRoot;
/**
* Creates a new ENRTreeRoot
*
* @param attrs The attributes of the root
*/
public ENRTreeRoot(final Map<String, String> attrs) {
if (attrs == null) {
throw new IllegalArgumentException("ENRNode attributes cannot be null");
}
version =
Optional.ofNullable(attrs.get("enrtree-root"))
.orElseThrow(() -> new IllegalArgumentException("Missing attribute enrtree-root"));
seq =
Optional.ofNullable(attrs.get("seq"))
.map(Long::parseLong)
.orElseThrow(() -> new IllegalArgumentException("Missing attribute seq"));
sig =
Optional.ofNullable(attrs.get("sig"))
.map(Base64URLSafe::decode)
.map(
sigBytes ->
SECP256K1.Signature.fromBytes(
Bytes.concatenate(
sigBytes, Bytes.wrap(new byte[Math.max(0, 65 - sigBytes.size())]))))
.orElseThrow(() -> new IllegalArgumentException("Missing attribute sig"));
enrRoot =
Optional.ofNullable(attrs.get("e"))
.orElseThrow(() -> new IllegalArgumentException("Missing attribute e"));
linkRoot =
Optional.ofNullable(attrs.get("l"))
.orElseThrow(() -> new IllegalArgumentException("Missing attribute l"));
}
/**
* Gets sequence
*
* @return sequence
*/
public Long seq() {
return seq;
}
/**
* Link root.
*
* @return the link root.
*/
public String linkRoot() {
return linkRoot;
}
/**
* ENR root.
*
* @return the enr root.
*/
public String enrRoot() {
return enrRoot;
}
/**
* Signature.
*
* @return SECP256K1 signature
*/
public SECP256K1.Signature sig() {
return sig;
}
@Override
public String toString() {
return String.format(
"enrtree-root:%s e=%s l=%s seq=%d sig=%s",
version, enrRoot, linkRoot, seq, Base64URLSafe.encode(sig.bytes()));
}
/**
* Returns the signed content of the root
*
* @return the signed content
*/
public String signedContent() {
return String.format("enrtree-root:%s e=%s l=%s seq=%d", version, enrRoot, linkRoot, seq);
}
}
/** Represents a branch in the ENR record. */
class ENRTree implements DNSEntry {
private final List<String> entries;
/**
* Constructs ENRTree with the given entries.
*
* @param entriesAsString the entries of the branch
*/
public ENRTree(final String entriesAsString) {
entries =
Arrays.stream(entriesAsString.split("[,\"]"))
.filter(it -> it.length() > 4)
.collect(Collectors.toList());
}
/**
* Entries of the branch.
*
* @return the entries of the branch
*/
public List<String> entries() {
return entries;
}
@Override
public String toString() {
return "enrtree-branch:" + String.join(",", entries);
}
}
/** Class representing an ENR Tree link */
class ENRTreeLink implements DNSEntry {
private final String domainName;
private final String encodedPubKey;
private final SECP256K1.PublicKey pubKey;
/**
* Creates a new ENRTreeLink
*
* @param enrTreeLink The URI representing ENR Tree link
*/
public ENRTreeLink(final String enrTreeLink) {
final URI uri = URI.create(enrTreeLink);
this.domainName = uri.getHost();
this.encodedPubKey = uri.getUserInfo();
this.pubKey = fromBase32(encodedPubKey);
}
private static SECP256K1.PublicKey fromBase32(final String base32) {
final byte[] keyBytes = Base32.decodeBytes(base32);
final ECPoint ecPoint = SECP256K1.Parameters.CURVE.getCurve().decodePoint(keyBytes);
return SECP256K1.PublicKey.fromBytes(Bytes.wrap(ecPoint.getEncoded(false)).slice(1));
}
/**
* Decoded SECP256K1 public key.
*
* @return derived SECP256K1.PublicKey
*/
public SECP256K1.PublicKey publicKey() {
return pubKey;
}
/**
* Domain name.
*
* @return the domain name
*/
public String domainName() {
return domainName;
}
@Override
public String toString() {
return String.format("enrtree://%s@%s", encodedPubKey, domainName);
}
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSEntry.ENRNode;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSEntry.ENRTreeLink;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSEntry.ENRTreeRoot;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import com.google.common.base.Splitter;
import io.vertx.core.Vertx;
import io.vertx.core.dns.DnsClient;
import io.vertx.core.dns.DnsClientOptions;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.crypto.SECP256K1;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/** Resolves a set of ENR nodes from a host name. */
public class DNSResolver implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(DNSResolver.class);
private final ExecutorService rawTxtRecordsExecutor = Executors.newSingleThreadExecutor();
private final String enrLink;
private long seq;
private final DnsClient dnsClient;
/**
* Creates a new DNSResolver.
*
* @param vertx Vertx instance which is used to create DNS Client
* @param enrLink the ENR link to start with, of the form enrtree://PUBKEY@domain
* @param seq the sequence number of the root record. If the root record seq is higher, proceed
* with visit.
* @param dnsServer the DNS server to use for DNS query. If empty, the default DNS server will be
* used.
*/
public DNSResolver(
final Vertx vertx, final String enrLink, final long seq, final Optional<String> dnsServer) {
this.enrLink = enrLink;
this.seq = seq;
final DnsClientOptions dnsClientOptions =
dnsServer.map(DNSResolver::buildDnsClientOptions).orElseGet(DnsClientOptions::new);
dnsClient = vertx.createDnsClient(dnsClientOptions);
}
private static DnsClientOptions buildDnsClientOptions(final String server) {
final List<String> hostPort = Splitter.on(":").splitToList(server);
final DnsClientOptions dnsClientOptions = new DnsClientOptions();
dnsClientOptions.setHost(hostPort.get(0));
if (hostPort.size() > 1) {
try {
int port = Integer.parseInt(hostPort.get(1));
dnsClientOptions.setPort(port);
} catch (NumberFormatException e) {
LOG.trace("Invalid port number {}, ignoring", hostPort.get(1));
}
}
return dnsClientOptions;
}
/**
* Convenience method to read all ENRs, from a top-level record.
*
* @return all ENRs collected
*/
public List<EthereumNodeRecord> collectAll() {
final List<EthereumNodeRecord> nodes = new ArrayList<>();
final DNSVisitor visitor = nodes::add;
visitTree(new ENRTreeLink(enrLink), visitor);
if (!nodes.isEmpty()) {
LOG.debug("Resolved {} nodes from DNS for enr link {}", nodes.size(), enrLink);
} else {
LOG.debug("No nodes resolved from DNS");
}
return Collections.unmodifiableList(nodes);
}
/**
* Sequence number of the root record.
*
* @return the current sequence number of the root record
*/
public long sequence() {
return seq;
}
/**
* Reads a complete tree of record, starting with the top-level record.
*
* @param link the ENR link to start with
* @param visitor the visitor that will look at each record
*/
private void visitTree(final ENRTreeLink link, final DNSVisitor visitor) {
Optional<DNSEntry> optionalEntry = resolveRecord(link.domainName());
if (optionalEntry.isEmpty()) {
LOG.debug("No DNS record found for {}", link.domainName());
return;
}
final DNSEntry dnsEntry = optionalEntry.get();
if (!(dnsEntry instanceof ENRTreeRoot treeRoot)) {
LOG.debug("Root entry {} is not an ENR tree root", dnsEntry);
return;
}
if (!checkSignature(treeRoot, link.publicKey(), treeRoot.sig())) {
LOG.debug("ENR tree root {} failed signature check", link.domainName());
return;
}
if (treeRoot.seq() <= seq) {
LOG.debug("ENR tree root seq {} is not higher than {}, aborting", treeRoot.seq(), seq);
return;
}
seq = treeRoot.seq();
internalVisit(treeRoot.enrRoot(), link.domainName(), visitor);
internalVisit(treeRoot.linkRoot(), link.domainName(), visitor);
}
private boolean internalVisit(
final String entryName, final String domainName, final DNSVisitor visitor) {
final Optional<DNSEntry> optionalDNSEntry = resolveRecord(entryName + "." + domainName);
if (optionalDNSEntry.isEmpty()) {
LOG.debug("No DNS record found for {}", entryName + "." + domainName);
return true;
}
final DNSEntry entry = optionalDNSEntry.get();
if (entry instanceof ENRNode node) {
// TODO: this always return true because the visitor is reference to list.add
return visitor.visit(node.nodeRecord());
} else if (entry instanceof DNSEntry.ENRTree tree) {
for (String e : tree.entries()) {
// TODO: When would this ever return false?
boolean keepGoing = internalVisit(e, domainName, visitor);
if (!keepGoing) {
return false;
}
}
} else if (entry instanceof ENRTreeLink link) {
visitTree(link, visitor);
} else {
LOG.debug("Unsupported type of node {}", entry);
}
return true;
}
/**
* Resolves one DNS record associated with the given domain name.
*
* @param domainName the domain name to query
* @return the DNS entry read from the domain. Empty if no record is found.
*/
Optional<DNSEntry> resolveRecord(final String domainName) {
return resolveRawRecord(domainName).map(DNSEntry::readDNSEntry);
}
/**
* Resolves the first TXT record for a domain name and returns it.
*
* @param domainName the name of the DNS domain to query
* @return the first TXT entry of the DNS record. Empty if no record is found.
*/
Optional<String> resolveRawRecord(final String domainName) {
// vertx-dns is async, kotlin coroutines allows us to await, similarly Java 21 new thread
// model would also allow us to await. For now, we will use CountDownLatch to block the
// current thread until the DNS resolution is complete.
LOG.debug("Resolving TXT records on domain: {}", domainName);
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Optional<String>> record = new AtomicReference<>(Optional.empty());
rawTxtRecordsExecutor.submit(
() -> {
dnsClient
.resolveTXT(domainName)
.onComplete(
ar -> {
if (ar.succeeded()) {
LOG.trace(
"TXT record resolved on domain {}. Result: {}", domainName, ar.result());
record.set(ar.result().stream().findFirst());
} else {
LOG.trace(
"TXT record not resolved on domain {}, because: {}",
domainName,
ar.cause().getMessage());
}
latch.countDown();
});
});
try {
// causes the worker thread to wait. Once we move to Java 21, this can be simplified.
latch.await();
} catch (InterruptedException e) {
LOG.debug("Interrupted while waiting for DNS resolution");
}
return record.get();
}
private boolean checkSignature(
final ENRTreeRoot root, final SECP256K1.PublicKey pubKey, final SECP256K1.Signature sig) {
Bytes32 hash =
Hash.keccak256(Bytes.wrap(root.signedContent().getBytes(StandardCharsets.UTF_8)));
return SECP256K1.verifyHashed(hash, sig, pubKey);
}
@Override
public void close() {
rawTxtRecordsExecutor.shutdown();
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/**
* Reads ENR (Ethereum Node Records) entries passed in from DNS. The visitor may decide to stop the
* visit by returning false.
*/
public interface DNSVisitor {
/**
* Visit a new ENR record.
*
* @param enr the ENR record read from DNS
* @return true to continue visiting, false otherwise
*/
boolean visit(final EthereumNodeRecord enr);
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
// Adapted from https://github.com/tmio/tuweni and licensed under Apache 2.0
/** Read Key value pairs from a DNS record */
public class KVReader {
private KVReader() {}
/**
* Read a key value pair from a DNS record
*
* @param record the record to read
* @return the key value pair
*/
public static Map<String, String> readKV(final String record) {
return Arrays.stream(record.split("\\s+"))
.map(
it -> {
// if it contains an = or :, split into Map.entry from the first occurrence
if (it.contains("=")) {
return it.split("=", 2);
} else if (it.contains(":")) {
return it.split(":", 2);
} else {
// this should not happen, as the record should be well-formed
return new String[] {it};
}
})
.filter(kv -> kv.length == 2)
.collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
}
}

View File

@@ -27,6 +27,8 @@ import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryAgent;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus;
import org.hyperledger.besu.ethereum.p2p.discovery.VertxPeerDiscoveryAgent;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSDaemon;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.DNSDaemonListener;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerTable;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeerPrivileges;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
@@ -69,17 +71,20 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.annotations.VisibleForTesting;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Future;
import io.vertx.core.ThreadingModel;
import io.vertx.core.Vertx;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.devp2p.EthereumNodeRecord;
import org.apache.tuweni.discovery.DNSDaemon;
import org.apache.tuweni.discovery.DNSDaemonListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -147,7 +152,8 @@ public class DefaultP2PNetwork implements P2PNetwork {
private final CountDownLatch shutdownLatch = new CountDownLatch(2);
private final Duration shutdownTimeout = Duration.ofSeconds(15);
private final Vertx vertx;
private DNSDaemon dnsDaemon;
private final AtomicReference<Optional<Pair<String, DNSDaemon>>> dnsDaemonRef =
new AtomicReference<>(Optional.empty());
/**
* Creates a peer networking service for production purposes.
@@ -227,15 +233,26 @@ public class DefaultP2PNetwork implements P2PNetwork {
LOG.info(
"Starting DNS discovery with DNS Server override {}", dnsServer));
dnsDaemon =
final DNSDaemon dnsDaemon =
new DNSDaemon(
disco,
createDaemonListener(),
0L,
1000L, // start after 1 second
600000L,
config.getDnsDiscoveryServerOverride().orElse(null),
vertx);
dnsDaemon.start();
config.getDnsDiscoveryServerOverride().orElse(null));
// TODO: Java 21, we can move to Virtual Thread model
final DeploymentOptions options =
new DeploymentOptions()
.setThreadingModel(ThreadingModel.WORKER)
.setInstances(1)
.setWorkerPoolSize(1);
final Future<String> deployId = vertx.deployVerticle(dnsDaemon, options);
final String dnsDaemonDeployId =
deployId.toCompletionStage().toCompletableFuture().join();
dnsDaemonRef.set(Optional.of(Pair.of(dnsDaemonDeployId, dnsDaemon)));
});
final int listeningPort = rlpxAgent.start().join();
@@ -282,7 +299,9 @@ public class DefaultP2PNetwork implements P2PNetwork {
return;
}
getDnsDaemon().ifPresent(DNSDaemon::close);
// since dnsDaemon is a vertx verticle, vertx.close will undeploy it.
// However, we can safely call stop as well.
dnsDaemonRef.get().map(Pair::getRight).ifPresent(DNSDaemon::stop);
peerConnectionScheduler.shutdownNow();
peerDiscoveryAgent.stop().whenComplete((res, err) -> shutdownLatch.countDown());
@@ -339,7 +358,7 @@ public class DefaultP2PNetwork implements P2PNetwork {
@VisibleForTesting
Optional<DNSDaemon> getDnsDaemon() {
return Optional.ofNullable(dnsDaemon);
return dnsDaemonRef.get().map(Pair::getRight);
}
@VisibleForTesting

View File

@@ -0,0 +1,121 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.security.Security;
import java.util.concurrent.atomic.AtomicInteger;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.ThreadingModel;
import io.vertx.core.Vertx;
import io.vertx.junit5.Checkpoint;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(VertxExtension.class)
class DNSDaemonTest {
private static final String holeskyEnr =
"enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.holesky.ethdisco.net";
// private static MockDNSServer mockDNSServer;
private final MockDnsServerVerticle mockDnsServerVerticle = new MockDnsServerVerticle();
private DNSDaemon dnsDaemon;
@BeforeAll
static void setup() throws IOException {
Security.addProvider(new BouncyCastleProvider());
}
@BeforeEach
@DisplayName("Deploy Mock Dns Server Verticle")
void prepare(final Vertx vertx, final VertxTestContext vertxTestContext) {
vertx.deployVerticle(mockDnsServerVerticle, vertxTestContext.succeedingThenComplete());
}
@Test
@DisplayName("Test DNS Daemon with a mock DNS server")
void testDNSDaemon(final Vertx vertx, final VertxTestContext testContext)
throws InterruptedException {
final Checkpoint checkpoint = testContext.checkpoint();
dnsDaemon =
new DNSDaemon(
holeskyEnr,
(seq, records) -> checkpoint.flag(),
0,
0,
0,
"localhost:" + mockDnsServerVerticle.port());
final DeploymentOptions options =
new DeploymentOptions().setThreadingModel(ThreadingModel.WORKER).setWorkerPoolSize(1);
vertx.deployVerticle(dnsDaemon, options);
}
@Test
@DisplayName("Test DNS Daemon with periodic lookup to a mock DNS server")
void testDNSDaemonPeriodic(final Vertx vertx, final VertxTestContext testContext)
throws InterruptedException {
// checkpoint should be flagged twice
final Checkpoint checkpoint = testContext.checkpoint(2);
final AtomicInteger pass = new AtomicInteger(0);
dnsDaemon =
new DNSDaemon(
holeskyEnr,
(seq, records) -> {
switch (pass.incrementAndGet()) {
case 1:
testContext.verify(
() -> {
assertThat(seq).isEqualTo(932);
assertThat(records).hasSize(115);
});
break;
case 2:
testContext.verify(
() -> {
assertThat(seq).isEqualTo(932);
assertThat(records).isEmpty();
});
break;
default:
testContext.failNow("Third pass is not expected");
}
checkpoint.flag();
},
0,
1, // initial delay
300, // second lookup after 300 ms (due to Mock DNS server, we are very quick).
"localhost:" + mockDnsServerVerticle.port());
final DeploymentOptions options =
new DeploymentOptions().setThreadingModel(ThreadingModel.WORKER).setWorkerPoolSize(1);
vertx.deployVerticle(dnsDaemon, options);
}
@AfterEach
@DisplayName("Check that the vertx worker verticle is still there")
void lastChecks(final Vertx vertx) {
assertThat(vertx.deploymentIDs()).isNotEmpty().hasSize(2);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static org.assertj.core.api.Assertions.assertThat;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class DNSEntryTest {
@BeforeAll
static void setup() {
Security.addProvider(new BouncyCastleProvider());
}
@Test
void enrTreeRootIsParsed() {
final String txtRecord =
"\"enrtree-root:v1 e=KVKZLGARGADDZSMCF65QQMEWLE l=FDXN3SN67NA5DKA4J2GOK7BVQI seq=919 sig=braPmdwMk-g65lQxums6hEy553s3bWMoecW0QQ0IdykIoM9i3We0bxFT0IDONPaFcRePcN-yaOpt8GBfeQ4qDAE\"";
final DNSEntry entry = DNSEntry.readDNSEntry(txtRecord);
assertThat(entry).isInstanceOf(DNSEntry.ENRTreeRoot.class);
final DNSEntry.ENRTreeRoot enrTreeRoot = (DNSEntry.ENRTreeRoot) entry;
assertThat(enrTreeRoot.enrRoot()).isEqualTo("KVKZLGARGADDZSMCF65QQMEWLE");
assertThat(enrTreeRoot.linkRoot()).isEqualTo("FDXN3SN67NA5DKA4J2GOK7BVQI");
assertThat(enrTreeRoot.seq()).isEqualTo(919);
}
@Test
void enrTreeBranchIsParsed() {
final String txtRecord =
"\"enrtree-branch:HVKDJGU7SZMOAMNLBJYQBSKZTM,PVSVWO3NLKHTBAIWOY2NB67RFI,"
+ "6TCKCNWXNGBMNFTGSRKNRO4ERA,37NSKCRJVI5XRRHWLTHW4A6OX4,NV3IJMKDVQHHALY6MAVMPYN6ZU,"
+ "SZCFDMTYOERMIVOUXEWXSGDVEY,FZ26UT4LSG7D2NRX7SV6P3S6BI,7TWNYLCOQ7FEM4IG65WOTL4MVE,"
+ "6OJXGI7NJUESOLL2OZPS4B\" \"EC6Q,437FN4NSGMGFQLAXYWPX5JNACI,FCA7LN6NCO5IAWPG5FH7LX6XJA,"
+ "EYBOZ2NZSHDWDSNHV66XASXOHM,FUVRJMMMKJMCL4L4EBEOWCSOFA\"";
final DNSEntry entry = DNSEntry.readDNSEntry(txtRecord);
assertThat(entry).isInstanceOf(DNSEntry.ENRTree.class);
assertThat(((DNSEntry.ENRTree) entry).entries())
.containsExactly(
"HVKDJGU7SZMOAMNLBJYQBSKZTM",
"PVSVWO3NLKHTBAIWOY2NB67RFI",
"6TCKCNWXNGBMNFTGSRKNRO4ERA",
"37NSKCRJVI5XRRHWLTHW4A6OX4",
"NV3IJMKDVQHHALY6MAVMPYN6ZU",
"SZCFDMTYOERMIVOUXEWXSGDVEY",
"FZ26UT4LSG7D2NRX7SV6P3S6BI",
"7TWNYLCOQ7FEM4IG65WOTL4MVE",
"6OJXGI7NJUESOLL2OZPS4B",
"437FN4NSGMGFQLAXYWPX5JNACI",
"FCA7LN6NCO5IAWPG5FH7LX6XJA",
"EYBOZ2NZSHDWDSNHV66XASXOHM",
"FUVRJMMMKJMCL4L4EBEOWCSOFA")
.doesNotContain("EC6Q");
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Map;
import org.junit.jupiter.api.Test;
public class KVReaderTest {
// copied from `dig all.holesky.ethdisco.net txt`
private static final String txtRecord =
"enrtree-root:v1 e=KVKZLGARGADDZSMCF65QQMEWLE l=FDXN3SN67NA5DKA4J2GOK7BVQI seq=919 sig=braPmdwMk-g65lQxums6hEy553s3bWMoecW0QQ0IdykIoM9i3We0bxFT0IDONPaFcRePcN-yaOpt8GBfeQ4qDAE";
@Test
void parseTXTRecord() {
final Map<String, String> kv = KVReader.readKV(txtRecord);
assertThat(kv)
.containsEntry("enrtree-root", "v1")
.containsEntry("e", "KVKZLGARGADDZSMCF65QQMEWLE")
.containsEntry("l", "FDXN3SN67NA5DKA4J2GOK7BVQI")
.containsEntry("seq", "919")
.containsEntry(
"sig",
"braPmdwMk-g65lQxums6hEy553s3bWMoecW0QQ0IdykIoM9i3We0bxFT0IDONPaFcRePcN-yaOpt8GBfeQ4qDAE");
}
}

View File

@@ -0,0 +1,205 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.p2p.discovery.dns;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import com.google.common.base.Splitter;
import com.google.common.io.Resources;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.datagram.DatagramPacket;
import io.vertx.core.datagram.DatagramSocket;
import io.vertx.core.datagram.DatagramSocketOptions;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Mock DNS server verticle. */
public class MockDnsServerVerticle extends AbstractVerticle {
private static final Logger LOG = LoggerFactory.getLogger(MockDnsServerVerticle.class);
private final Map<String, String> txtRecords = new HashMap<>();
private int dnsPort;
@Override
public void start(final Promise<Void> startPromise) throws Exception {
final DatagramSocket datagramSocket = vertx.createDatagramSocket(new DatagramSocketOptions());
datagramSocket.handler(packet -> handleDatagramPacket(datagramSocket, packet));
final String dnsEntriesJsonPath =
Path.of(Resources.getResource("discovery/dns/dns-records.json").toURI()).toString();
LOG.debug("Reading DNS entries from: {}", dnsEntriesJsonPath);
vertx
.fileSystem()
.readFile(dnsEntriesJsonPath)
.compose(
buffer -> {
final JsonObject dnsEntries = new JsonObject(buffer.toString());
final Map<String, Object> jsonMap = dnsEntries.getMap();
jsonMap.forEach((key, value) -> txtRecords.put(key, value.toString()));
// start the server
return datagramSocket.listen(0, "127.0.0.1");
})
.onComplete(
res -> {
if (res.succeeded()) {
LOG.info("Mock Dns Server is now listening {}", res.result().localAddress());
dnsPort = res.result().localAddress().port();
startPromise.complete();
} else {
startPromise.fail(res.cause());
}
});
}
@Override
public void stop() {
LOG.info("Stopping Mock DNS Server");
}
private void handleDatagramPacket(final DatagramSocket socket, final DatagramPacket packet) {
LOG.debug("Packet Received");
Buffer data = packet.data();
final short queryId = getQueryId(data);
final String queryName = extractQueryName(data.getBytes());
final Buffer response;
if (txtRecords.containsKey(queryName)) {
LOG.debug("Query name found {}", queryName);
response = createTXTResponse(queryId, queryName, txtRecords.get(queryName));
} else {
LOG.debug("Query name not found: {}", queryName);
response = createErrorResponse(queryId, queryName);
}
socket.send(response, packet.sender().port(), packet.sender().host());
}
private String extractQueryName(final byte[] buffer) {
StringBuilder queryName = new StringBuilder();
int index = 12; // Skip the DNS header
while (index < buffer.length) {
int labelLength = buffer[index] & 0xFF;
if (labelLength == 0) {
break;
}
index++;
for (int i = 0; i < labelLength; i++) {
char c = (char) (buffer[index + i] & 0xFF);
queryName.append(c);
}
index += labelLength;
if (index < buffer.length && buffer[index] != 0) {
queryName.append(".");
}
}
return queryName.toString();
}
private Buffer createTXTResponse(
final short queryId, final String queryName, final String txtRecord) {
final Buffer buffer = Buffer.buffer();
// Write DNS header
buffer.appendShort(queryId); // Query Identifier
buffer.appendShort((short) 0x8180); // Flags (Standard query response, No error)
buffer.appendShort((short) 1); // Questions count
buffer.appendShort((short) 1); // Answers count
buffer.appendShort((short) 0); // Authority RRs count
buffer.appendShort((short) 0); // Additional RRs count
// Write query name
final Iterable<String> queryLabels = Splitter.on(".").split(queryName);
for (String label : queryLabels) {
buffer.appendByte((byte) label.length());
buffer.appendString(label);
}
buffer.appendByte((byte) 0); // End of query name
// Write query type and class
buffer.appendShort((short) 16); // Type (TXT)
buffer.appendShort((short) 1); // Class (IN)
// Write answer
for (String label : queryLabels) {
buffer.appendByte((byte) label.length());
buffer.appendString(label.toLowerCase(Locale.ROOT));
}
buffer.appendByte((byte) 0); // End of answer name
buffer.appendShort((short) 16); // TXT record type
buffer.appendShort((short) 1); // Class (IN)
buffer.appendInt(60); // TTL (60 seconds)
int txtRecordsLength = txtRecord.getBytes(UTF_8).length;
buffer.appendShort((short) (txtRecordsLength + 1)); // Data length
buffer.appendByte((byte) txtRecordsLength); // TXT record length
buffer.appendString(txtRecord);
return buffer;
}
private Buffer createErrorResponse(final short queryId, final String queryName) {
Buffer buffer = Buffer.buffer();
// Write DNS header
buffer.appendShort(queryId); // Query Identifier
buffer.appendShort((short) 0x8183); // Flags (Standard query response, NXDOMAIN error)
buffer.appendShort((short) 1); // Questions count
buffer.appendShort((short) 0); // Answers count
buffer.appendShort((short) 0); // Authority RRs count
buffer.appendShort((short) 0); // Additional RRs count
// Write query name
for (String label : Splitter.on(".").split(queryName)) {
buffer.appendByte((byte) label.length());
buffer.appendString(label);
}
buffer.appendByte((byte) 0); // End of query name
// Write query type and class
buffer.appendShort((short) 16); // Type (TXT)
buffer.appendShort((short) 1); // Class (IN)
return buffer;
}
private short getQueryId(final Buffer queryData) {
return (short) ((queryData.getByte(0) & 0xff) << 8 | (queryData.getByte(1) & 0xff));
}
/**
* Mock server local port
*
* @return server port
*/
public int port() {
return dnsPort;
}
}

View File

@@ -57,9 +57,7 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import io.vertx.core.Context;
import io.vertx.core.Vertx;
import io.vertx.core.dns.DnsClient;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.crypto.SECP256K1;
import org.assertj.core.api.Assertions;
@@ -335,16 +333,21 @@ public final class DefaultP2PNetworkTest {
final NetworkingConfiguration dnsConfig =
when(spy(config).getDiscovery()).thenReturn(disco).getMock();
Vertx vertx = mock(Vertx.class);
when(vertx.createDnsClient(any())).thenReturn(mock(DnsClient.class));
when(vertx.getOrCreateContext()).thenReturn(mock(Context.class));
final Vertx vertx = Vertx.vertx(); // use real instance
// spy on DefaultP2PNetwork
final DefaultP2PNetwork testClass =
(DefaultP2PNetwork) builder().vertx(vertx).config(dnsConfig).build();
testClass.start();
assertThat(testClass.getDnsDaemon()).isPresent();
try {
// the actual lookup won't work because of mock discovery url, however, a valid DNSDaemon
// should be created.
assertThat(testClass.getDnsDaemon()).isPresent();
} finally {
testClass.stop();
vertx.close();
}
}
@Test
@@ -358,17 +361,19 @@ public final class DefaultP2PNetworkTest {
doReturn(disco).when(dnsConfig).getDiscovery();
doReturn(Optional.of("localhost")).when(dnsConfig).getDnsDiscoveryServerOverride();
Vertx vertx = mock(Vertx.class);
when(vertx.createDnsClient(any())).thenReturn(mock(DnsClient.class));
when(vertx.getOrCreateContext()).thenReturn(mock(Context.class));
Vertx vertx = Vertx.vertx(); // use real instance
final DefaultP2PNetwork testClass =
(DefaultP2PNetwork) builder().config(dnsConfig).vertx(vertx).build();
testClass.start();
// ensure we used the dns server override config when building DNSDaemon:
assertThat(testClass.getDnsDaemon()).isPresent();
verify(dnsConfig, times(2)).getDnsDiscoveryServerOverride();
try {
assertThat(testClass.getDnsDaemon()).isPresent();
verify(dnsConfig, times(2)).getDnsDiscoveryServerOverride();
} finally {
testClass.stop();
vertx.close();
}
}
private DefaultP2PNetwork network() {

View File

@@ -0,0 +1,137 @@
{
"all.holesky.ethdisco.net" : "enrtree-root:v1 e=QXOF2GWVHBKMKW57Y2KSKWYNFQ l=FDXN3SN67NA5DKA4J2GOK7BVQI seq=932 sig=DuA35BkYo9-FBwJ6MPxdNnYfcGMSGunAKUyfNN2gYQhYDBCPFZkr_cfe40Wspl2Vl76w6Ccs-B8ZrXpI_YymrAA",
"I56MJYJBMXTZZEPBQR6HWNAH7A.all.holesky.ethdisco.net" : "enr:-KO4QCTGqfxu7eEfe6M83e3bQLUgkKWGCdv6Ib5D0gCuQkkvbq1D0CN8UmHgpsddZNKHa2iBl3EIiGhaLBs_NKTxGQuGAYranLv7g2V0aMfGhJsZKtCAgmlkgnY0gmlwhCKH3xKJc2VjcDI1NmsxoQMHuEvotUinJNm_8Vz7412P1yKZ6r5iz9EcYj-9v3weRYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"IPSUCB6CICZIW6SERKZL7FFTIM.all.holesky.ethdisco.net" : "enr:-KO4QD47Vx9bnFcvE6JNAhrLz6GGgPk9GaJtP95ogjSOFHxlcZjnrT5TQzW9Jyx99XO9rzhK6WSvgdFoA9_54QPQcUaGAYxBy9opg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIe1TLKJc2VjcDI1NmsxoQKMO6bMfiH5DnJNFZgSqUEi6uHNnH2_bMh7hwVXRWTMl4RzbmFwwIN0Y3CCdqmDdWRwgnap",
"QJM2RVJT7USPDSI5VVFGGDW6JM.all.holesky.ethdisco.net" : "enr:-Ji4QHWntDnLOi4S9GKmF4HY7WrnJuJGaIBrnM3Y75G-8EUpZExnUkaZJtlmzOeJs6WAcYsissKSybUG5rSEiad0s86ByoNldGjHxoSbGSrQgIJpZIJ2NIJpcISLY0UEiXNlY3AyNTZrMaED5hLZweFA_nvWEc-Q7Vxqf2lIYxScF-F4ORxs-rVyHZKDdGNwgtn5g3VkcILZ-Q",
"C7SDD5OPASV7B2XUOXF5NLBBKU.all.holesky.ethdisco.net" : "enr:-KO4QLo95TIKo_axZA9xafYgl9jQ2ZTDFCQ29znjUwp-6zPUe6o8L9NO3X3n3uMZH8bFGnRmoIhyHLxNoOp2BU6O7xGGAYwoJEiug2V0aMfGhJsZKtCAgmlkgnY0gmlwhKEjElWJc2VjcDI1NmsxoQPIffRacW7k1QukSBfJ8leopO1M5wOv89G06m0SAQDB8oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"AUQGHXRAP7J3AGI6TUOQVYTYLY.all.holesky.ethdisco.net" : "enr:-KO4QGuiAZHlxH7T5XPcPpRTovca50B0pzDLkgJ-zaxkjT_PO6zsAWQezB-b53yAnqx01Jdj5tQWsvWoaNVfiFw3iw6GAY1nSgXzg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEp2jJuJc2VjcDI1NmsxoQMTiH7XteYOVAHiXAZoacUjo5JYLhQINeFMbPbEY9sA84RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"WLME2JINTIQACAMD5WZUQ4PRJI.all.holesky.ethdisco.net" : "enr:-J24QIMYTLuDOO1F5w8AL_WGXU6CZmzi05W35Rz8PuVT8b6vUqmUatifQtzuL2Q7REuRY5kYNurUbLHscGx3j1zjTmmGAYrbbtBig2V0aMfGhJsZKtCAgmlkgnY0gmlwhETp6VKJc2VjcDI1NmsxoQKrwy6w-9JGp3dagVeXMZEd3iZGff-rEVTqd4gmkhBRBIN0Y3CCdl-DdWRwgnZf",
"5JAERI2BPJN45X7IK6SWZOZ2FI.all.holesky.ethdisco.net" : "enr:-KO4QEsCIXXCDLUsTbUOT3ILg3rpga0gZXaG9_YT9_kFk97iRwu_Pr4RlhDvdkg4Y4bl9SBVzP9bFtL7H9AU7QxE7OeGAY1lbo59g2V0aMfGhJsZKtCAgmlkgnY0gmlwhA3Xl1-Jc2VjcDI1NmsxoQPsZi79eOcjTI3Xa2GCBiXRCgtm7wFo19cVlmhQSZ-i64RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"J7ZIDKH7CKVIYY244QVU6RMPDM.all.holesky.ethdisco.net" : "enr:-KO4QN942TWYsHn5c2-vZhoeXwELvI2zVg2eHk6nzoyTN8Cwcb8n-4_cwQPIU5p7DsuOehtu-raiGxYm4vE_6WUhT6yGAY1ClkGgg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJBbb1yJc2VjcDI1NmsxoQKemKJgEuvyzZofyTm82rbw716cyTA2hf6zSJ73kzl_ZIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"FFM67SMD4N3SK4ZQTY2HOMU4F4.all.holesky.ethdisco.net" : "enr:-KO4QG4O1MBSzBHtShtqoXXeAycBqcDpuBK2BBwIuK_Qppz5OpJC6Ga3-qDEQJQOtbEYm0yXMhenb50Get_H6Bu9SbGGAY16lghqg2V0aMfGhJsZKtCAgmlkgnY0gmlwhA_rV76Jc2VjcDI1NmsxoQJ1vrJ4fwXiDAhSqIJwbELp2ktd9A0zRLws1li91-aBmoRzbmFwwIN0Y3CCdmCDdWRwgnZg",
"GZVG4EONSAY6M7SMLJXDCFUF5Q.all.holesky.ethdisco.net" : "enr:-KO4QErAUNKF003oZAYn8UUocPIuq2MTpxHV3gHfrNkThYPbZ366m-mlvXezUX5JDA5iJE-LTWWEPh8JqjEDah5kVimGAYxA2nMcg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFtWv2Jc2VjcDI1NmsxoQMCgMWZQXkPyMKdwnzdBxQe6rcs25guZtULvfzDjhE71oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"3AVV65MYCJ7AGFUCKXT2UX2DSQ.all.holesky.ethdisco.net" : "enr:-KO4QEaesvQ1kySNS_mnQfiBr4DZQmkhHmqKEGRQvgyd5K3lNDm3vjs9cMMVTY9FgENpP1o0UGBsapNNfvXIN2gaudGGAY3ulUKIg2V0aMfGhJsZKtCAgmlkgnY0gmlwhDIjTkmJc2VjcDI1NmsxoQNVbUX0SvjLX7d7psFtTTNkKT7x_zHl3f4bSVQrkbK1YoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"QDCV4SQTQAGHHA3DRA2TR4LNMY.all.holesky.ethdisco.net" : "enr:-KO4QFVXTftQWqwggnKZlVzFmnQz-U5jzIx37kQSltdvU5kuYQHT1mboaEBh92lS0BUvn-aBzLmHu7wX6hhs2xdGw-6GAYrk72-Hg2V0aMfGhJsZKtCAgmlkgnY0gmlwhCJSHduJc2VjcDI1NmsxoQNGPGIxN3h_R3TiUe0Ud2WazTigmsK028DXXuVLna9rtoRzbmFwwIN0Y3CCdTWDdWRwgnU1",
"366Y3UIIKK2G5CUS7CHNPZMPEM.all.holesky.ethdisco.net" : "enr:-KO4QK1ecw-CGrDDZ4YwFrhgqctD0tWMHKJhUVxsS4um3aUFe3yBHRtVL9uYKk16DurN1IdSKTOB1zNCvjBybjZ_KAqGAYtJ5U8wg2V0aMfGhJsZKtCAgmlkgnY0gmlwhA_MtDmJc2VjcDI1NmsxoQNXD7fj3sscyOKBiHYy14igj1vJYWdKYZH7n3T8qRpIcYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"LHFO3FXNRHB5B3YSTKUALGMEAI.all.holesky.ethdisco.net" : "enr:-KO4QEuoZibAJnKlhcAENpJiju6nVH5J2or_xnVnX_eputCuTHBVtNJmoRKgDBU0idG4kbxFPPKaWRQ3TdYeIbsAAV-GAYrax-PMg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKIOJc2VjcDI1NmsxoQNCYX5kXJqI2deaVOtsTmUQka7dIocapHSAfnNn_CTL2YRzbmFwwIN0Y3CCdmCDdWRwgnZg",
"3PMAED3BC2HUS7AMEPGJDKENQY.all.holesky.ethdisco.net" : "enr:-KO4QFMsKiZk64UQsyLVHrxTpTpmdZYzuI-Xgy0gut5NgLulRvbrgQDmdrAT2PQuxK8K9AiplRzJ_i8CtseBD_d2bwGGAYx9HQirg2V0aMfGhJsZKtCAgmlkgnY0gmlwhLBn3miJc2VjcDI1NmsxoQJSdj6d-7J6YsK6vZwRl_zzMSCKauLadYxL8zfjjzOQZYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"4PFOQY7RKTNLRPXQXKKXD3K6LY.all.holesky.ethdisco.net" : "enr:-KO4QJ8BuQCt7gBXU_26FNx8waHuCzCkG54mErQoBAJrYaw_bdUJT0yQA0vG8gr-dUoS77OX0D4tD-R6e30832ncLMaGAYrbEjQ3g2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEV4tiJc2VjcDI1NmsxoQJHEsWJ3CoSi-1JgkeSogpyRqYvBaJI77-soOcbmB_nyYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"GUBLA7OPRPBMYMQ76EXDMB7BHY.all.holesky.ethdisco.net" : "enr:-KO4QIFA0MiYPPyzvlUqi5j1dL1RGz6MdFhhLN30iXeNc1JfCS1QqTJciby7ZhlQYwFdVMuk_ptgu530WxiQR-UmZpWGAY2ia8cWg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEt3l4OJc2VjcDI1NmsxoQJRcQCiMhxUex-gtsxf2IWJ6nGita_F8BaPZxTwE310WIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"VN7EWW4RMUZM6KUOQ43GJ33DWM.all.holesky.ethdisco.net" : "enr:-KO4QI3OPqietyANJtQ9_RUOU6ELbwDgTn39MufjLJ9BEzkwTxEgDcgYekeisrchGWzrzTC8T_2zowbuQhZlTkqNXB2GAY39ItF5g2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFsBbiJc2VjcDI1NmsxoQLa2k_Jy-sjrZ-0305yX_F1ZxDNNfCKIImoL5tyDN3cEYRzbmFwwIN0Y3CCdl6DdWRwgnZe",
"FDXN3SN67NA5DKA4J2GOK7BVQI.all.holesky.ethdisco.net" : "enrtree-branch:",
"QDMF4HIR2UEXRJVOX4UJPJTPKA.all.holesky.ethdisco.net" : "enr:-KO4QCeMBK9Ur5AHbkdov7TdALRsHzc48RXNtvR861fcmcxPYH59PthmWiT_pQHfVOH3x9-HK2bG8_h2jm46sZyJ6UeGAY2ZCasag2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFs7nOJc2VjcDI1NmsxoQLT22lM9abRweZb93jeMd4jvuRsXnjQFT2oY5a0rb0cvoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"3JSDZJCCWKIEBGPH5EI5VZF4RQ.all.holesky.ethdisco.net" : "enrtree-branch:4PFOQY7RKTNLRPXQXKKXD3K6LY,3AVV65MYCJ7AGFUCKXT2UX2DSQ,5JAERI2BPJN45X7IK6SWZOZ2FI,YUZZDZD57PTNEIB5QL3FEXK2ZA,TMY2W2YBNCXUUNA3Y7QXWVQLRE,MJB42632KKOPGJ2KNY3GPKP66I,QXRV67JYJNOYJDPC5CTKUVG76M,QJM2RVJT7USPDSI5VVFGGDW6JM,I33RZWBACJHNDEXG2RRXMX",
"A63OP4WTCB3HGDZE4NGDEID6Z4.all.holesky.ethdisco.net" : "enrtree-branch:QXKEJG4XZEQSXNUY7JJYCATPEI,HIDVATDVB36L2MASAWA7SBJAII,CHFGCI2RQS3XFN2MKFP6G2ZM4U,GSONRYZILMGUJEN3PYQXYD6GYQ,OSHAABXYJSRWW35VOMYHZUKJXU,RUJF27NEYDBNQAFMI6K6SKDVRY,TXAFU343ACQLSVIMT5LYG3W2AE,R6EQA5KQEQM77JJXB4BHHTDF6Y,CF25LCQ452FBTR24CZU4C2",
"N7HAL5M6HNZBGTWM3LWFDRX4WU.all.holesky.ethdisco.net" : "enr:-Je4QI2f2MAXFFi0Q3--GhXVZwNP-jI-G6XwmiDXxT-iobTTKOBJCyWUPk5WSoTtRS2ABqJmTAK8jflXBWLHuY7AueRFg2V0aMfGhP1PAWuAgmlkgnY0gmlwhDmAXJmJc2VjcDI1NmsxoQIc4YD6HsNIoj2HVJJDzr3cSfNtcEBRLtk5kgwXNH0q8YN0Y3CCXoeDdWRwgl6H",
"QXOF2GWVHBKMKW57Y2KSKWYNFQ.all.holesky.ethdisco.net" : "enrtree-branch:A63OP4WTCB3HGDZE4NGDEID6Z4,PL27G47LAASBPPAMXUDIJ3OCRQ",
"23B5UFB3JWETLIKE5Q6B2B5MWA.all.holesky.ethdisco.net" : "enr:-KO4QGjsmd6RDlGYHJu2JnI-Lf4TZ8s1yJtLDvvtp_Kw6xIwNn7_Ti_FmEHfWbaSyy0Icl4jlErvH-LrEmi9PCzB27uGAY0MEI03g2V0aMfGhJsZKtCAgmlkgnY0gmlwhNXvxn6Jc2VjcDI1NmsxoQOzxdn7S7O58IiaWGk4n3MsiB816GGv_bAd_PM9FkWeZIRzbmFwwIN0Y3CCVTyDdWRwglU8",
"TXAFU343ACQLSVIMT5LYG3W2AE.all.holesky.ethdisco.net" : "enrtree-branch:3EMD3PTQYRFVNFBQ73BYFL4AEQ,PMLO73ISEK4Z6IRPOSWIUUKF64,5NHWEAJHKSAO5DIIYAZ7MQJVSE,LNO6EN3Y2LJA5YOJMEMODAJFWM,23B5UFB3JWETLIKE5Q6B2B5MWA,HQ5S2EHH762PSKVTHWNQ6346NI,O25DXMPE4UEZ6SFMQRBGL2E2I4,2WHIXLN5QX3JEK3SSH7MXKTJMU,WQDLDQ7U74Y2HM5LHVCOCY",
"PMLO73ISEK4Z6IRPOSWIUUKF64.all.holesky.ethdisco.net" : "enr:-KO4QBxZ1JFNQEopzO-wMumFIw4fGHkuPZkuCLvgcz0X8L8yKWUkQ-UiS7-KHBCjGOby7yjR6m7m9dqoQvlHejBncSWGAYv2B0KZg2V0aMfGhJsZKtCAgmlkgnY0gmlwhA_ML-SJc2VjcDI1NmsxoQMEi6SKsKUVTnxDWKc1Go6ZG8o5nEapNJBaWAd_YC26R4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"CDXRYZFKH6OUWTA2IJ2MYIMYPM.all.holesky.ethdisco.net" : "enr:-KO4QExy2s5Uh2eTEJtsODBEOcPZZN-CYY0WEr_8nA_uK43QV3iqmFzfXJ-29zootm5F-E-DrjzTObp2tw_klTXPRu-GAY2ZtbV8g2V0aMfGhJsZKtCAgmlkgnY0gmlwhBJ2VQmJc2VjcDI1NmsxoQJuk1X-4JUVQT-mguV7dSGSUC-RoxdnTyOmD-VrfRFQyYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"CTDMY3ALJA7FRKVS4MCTAJRRH4.all.holesky.ethdisco.net" : "enrtree-branch:UIGSNQMHERWJIZCP2OLUXSZ3KM,I56MJYJBMXTZZEPBQR6HWNAH7A,IZNO6JEFTYHQWWF3LJ2M66P7II",
"GSONRYZILMGUJEN3PYQXYD6GYQ.all.holesky.ethdisco.net" : "enrtree-branch:V4A7I7I2SFVUDFFH7AGPFXACBA,67FFSS5IYEYRGUYFEWGIJDIMII,NXU6DU7HEM2L4DN6G2VHHFT72I,3T4CNEKYCJP2PJ3EQVJSFKHH44,KYTZHQX2PSOGY6RQTCVTUKTS7E,GUBLA7OPRPBMYMQ76EXDMB7BHY,HGROZTZI7YPDW5F37QVUPQEBG4,AB27AIPX5Q5J6UAXQ6C2QFTYZA,7UIVPNORDS3RPPTLSNGYAN",
"IPU725BUGL4HIOTSOIH3KZG5ZA.all.holesky.ethdisco.net" : "enr:-KO4QLf3R97a5p3pRgY1AeN1DisWZUTnHbIMt2aPh0zvq8QIZguS9EiujNa71YXqJgxw7ztz3YmwJMWuPuhfWqSkxqWGAYrayxVYg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKIOJc2VjcDI1NmsxoQIHu5vOuFNLO8814yybwdh03yUQzfPTTyeK_X44Gz5jx4RzbmFwwIN0Y3CCdn6DdWRwgnZ-",
"V5LTO36DCXU2JCCSSJ76E35OFU.all.holesky.ethdisco.net" : "enr:-KO4QMLA20nV5gEPR5ugJWkqHSkU89wLsjSVlpdbjuXGueHRY_VJ7gfCBuPbnyxN3Y0rYJThJU7b7IAA1yBfcRx6Uo-GAYrbDOlPg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKGuJc2VjcDI1NmsxoQNZKgK-Lr-g81vUAH_bV24PDyOwNQaNPgAOBEA3qV3JxYRzbmFwwIN0Y3CCdnSDdWRwgnZ0",
"2SA643JTHJ75ZVPFHAKLXI2WXQ.all.holesky.ethdisco.net" : "enr:-KO4QEPFY3aDBt5F3VQU5qcGZED8Xr-J9v1Fi4CcGpx7q_fydrJM8h0RqAXSdcJbr03b7ysPaOR4mNUTRou4kjPsu7yGAY4QKOX4g2V0aMfGhJsZKtCAgmlkgnY0gmlwhCO4xmuJc2VjcDI1NmsxoQKaOskToHERfimE_ei_VPRsh3fimBlYooVb80PVt0k-aIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"V52J3WKNVGG56JFRKYDLSZREJY.all.holesky.ethdisco.net" : "enr:-KO4QMC1Y7Fl44QyBr8KDFTyd1IQ_h0w67Igms87RDJeZJuXbc74aIVNkOeK0t3_zEJAT2spttSVu8tKDeV-cdiPE42GAY3KEqdCg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFsGDWJc2VjcDI1NmsxoQN24zvy5pQRtLA5_iKLgnTwXjI3T1KldFTOyp7Dk6dCRoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"3PYSNKXWWSRBWV377EFNYINHSA.all.holesky.ethdisco.net" : "enr:-KO4QODvXk9lfhLNmdyttodPJQOIYQM36Rl9OZsFBZ4vMjaJcoJUXxTQCMqGLNTWmFh-1oEy0XoYKgPy4tywLZZcB8CGAYsolPILg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIe1OV6Jc2VjcDI1NmsxoQPj1f0OOW-g_vRGcihewV9-kcsQZdwXBHy4r8vwinurzoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"ZV5CYUMJPF4XSTFHOG65622KEE.all.holesky.ethdisco.net" : "enr:-KO4QDd2Ia2HHxIk_v5zyXOs6LIkR7a3wVUmipLZnQTJJMZtTNVY5PnRonxr_GAQ3nqG5R8f-eiyoYprxN1XjsfRlnyGAY2jAkZPg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJ7cbM2Jc2VjcDI1NmsxoQLx82Y08wCtO72z_znVjHxPl3hBz1YBlPokUpsLFKRHJ4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"DQYYUE7KVEXGEYBH4V2QHI6P7M.all.holesky.ethdisco.net" : "enr:-KO4QBhk9j1k2tfVrwV4yVRS9jn2zwS9KKADlhqvMsZsqdXFZiz0s-vCAnqtkDfszY9peGDBiWulLdNe6KFuvqgxgy6GAYtHL5rAg2V0aMfGhJsZKtCAgmlkgnY0gmlwhDmBAQqJc2VjcDI1NmsxoQLXrL6FtBz248tpC2_DxJs2HsvtHdSoNsZIBwth_MMu94RzbmFwwIN0Y3CCdmqDdWRwgnZq",
"MZGQKIQKIOFO3W2GJURJUXVYMQ.all.holesky.ethdisco.net" : "enr:-KO4QI7ESDG0rx7lEU_FFFFkALgNr9roSDrKDOzmEdxTHwsxKj5ozskjEjwFPrShowZbzTTYCp-NRhhw3uhcmKCYy0GGAY1lomwig2V0aMfGhJsZKtCAgmlkgnY0gmlwhCUbQPGJc2VjcDI1NmsxoQMV_yyKYF25xvgoJARC1swzb0S0llZJEmMLRHoINSR81YRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"MJB42632KKOPGJ2KNY3GPKP66I.all.holesky.ethdisco.net" : "enr:-KO4QEBK_p981nqXnme4a2sYvHW2FOz_OwLwstllVRvE8w-dVnDBrHxVZg7XSQwseErDQpfUgYMnBPMzpsx_bDUui5eGAY09OSoRg2V0aMfGhJsZKtCAgmlkgnY0gmlwhLzWgw-Jc2VjcDI1NmsxoQM2fE-8xAAaBUMu7dwviv_y8osp0rYMaKtaGBnbUba_J4RzbmFwwIN0Y3CCdl2DdWRwgnZd",
"QY2XP6FTX7QKFNP6TNZ2MOHZKQ.all.holesky.ethdisco.net" : "enr:-KO4QFsIg8OnqK5HJhhCaEuUTJ7RkLcTAXnUOOcaK63Ra2Kya2HsYSRgM1jRyr9utt3ib83q4fsU_IOg7kuR1jf2u2SGAYray1Tfg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKI2Jc2VjcDI1NmsxoQJiD81UDxWESi3paPaopKxnoF5vf0GAxlroaPr6bSIykIRzbmFwwIN0Y3CCdn6DdWRwgnZ-",
"3A6T36TYZJBFLOHMJOJGL5SPXA.all.holesky.ethdisco.net" : "enr:-KO4QEVn1fwLQuOHSsRVS6bBIv7Nhr39Ze03wqUhwdgEn0IUeEB9TZAx6d9E-C0tBkQdEnbwld1YxEsB9gRY0Od13nGGAYzxMuKBg2V0aMfGhJsZKtCAgmlkgnY0gmlwhAW9up-Jc2VjcDI1NmsxoQKNkgm76tKKtumISB2-1oGEHv_mZtMVh7JGrSmvlX5qqYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"WRRS22MCKTZ4YS3ZLPUJEUAHUI.all.holesky.ethdisco.net" : "enr:-KO4QG6_DN_yg3WbcE7jc_tGXK9dLJPplfz0cbzCRwT8v5o6BBk_e_ER73cttVRyYkkvBDyw-akwTHYxjCe2Jp7OWuiGAYrbEiVVg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEV49OJc2VjcDI1NmsxoQKYHwvu1PazCFKpleCUgYvxialsHK6_iLwC_R2i3J70fYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"BAY6SKB2RTQCM7RTSHAFQ6TTBQ.all.holesky.ethdisco.net" : "enr:-KO4QIo--Wic2Dyk2II8x2uTPNOFY3CRZ8wmABP5qOhmZv4LXvAfbdISPp7HDrJwrejs032LHH5rhUY5l8bj9-M-_u2GAY3GDGQWg2V0aMfGhJsZKtCAgmlkgnY0gmlwhI6E2M-Jc2VjcDI1NmsxoQM46NJn0fjSRwgGkB0G1n7QQ9VyBDwiPXPX_xgM25tDOIRzbmFwwIN0Y3CCfEyDdWRwgnxM",
"5AOSND63QKPVT6EWNMALKAFC4I.all.holesky.ethdisco.net" : "enr:-KO4QKn6DlOQ0ybfLAfyPlyPssuWtP0Zu5FEUEgr3015XppiCP4yr9SeMgnpN90AVHJA5C61F3677GiO0N-JIXGfN2uGAYra2k7ag2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKJOJc2VjcDI1NmsxoQKgKJovbRS4hL3ugMVrevOCUGDS-ixgByq_tbh4T9oihIRzbmFwwIN0Y3CCdmCDdWRwgnZg",
"PL27G47LAASBPPAMXUDIJ3OCRQ.all.holesky.ethdisco.net" : "enrtree-branch:3JSDZJCCWKIEBGPH5EI5VZF4RQ,XTJ3PFTPBB3ATDDWAA6W7RRKMY,FTTHOFPRPIHMJNZA3VZUAW5TIM,DAVKEW6RQ5YTYHKCJ2A2J5GVCI,TGKURK5IPVCPXS4QPS2KZJCP3Q,RWRV55FT3DKDVGZK7AEU2DR77Y,CTDMY3ALJA7FRKVS4MCTAJRRH4",
"HQ5S2EHH762PSKVTHWNQ6346NI.all.holesky.ethdisco.net" : "enr:-KO4QK883RN_CIppuOvhzi0O3Qg-XzHUZsdKIEqLdvZMLN5BCV5QTqqxRzJjtXa7NZjBi22UQJUUlsrQ_3g3Uavv92aGAY1BRdWag2V0aMfGhJsZKtCAgmlkgnY0gmlwhFJkOnSJc2VjcDI1NmsxoQNAyMtRruAQcNn10ZReZiiZtPnk35o_oJEhabuBKi1gLoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"XPTWTOASNO4WEBXH74WCQ5EYTQ.all.holesky.ethdisco.net" : "enr:-KO4QEk3I50HU8omZLCYgSwXs1caXS-q06lC_GnJT30gbzlIEDWBldaoC83sg9aWTQ9DdkQStosOuYEb13gxTwp4tSKGAY5DOiDfg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEVX7SJc2VjcDI1NmsxoQPCijWe7yQtKeDfuj6WXiJZ6CZ88FGXKj6DGSWdq0E0qYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"HOXANHAMPVCFA2QR54VEMWCWPE.all.holesky.ethdisco.net" : "enr:-KO4QELWztCXUz9MCxD8zbh65aa6LwP3wubhdXJVdlyrl7QzFJkUXosDXndbQqtAT2qD5nXAFpBnz5MeUSZf_GfjkI-GAY16vTc2g2V0aMfGhJsZKtCAgmlkgnY0gmlwhCZhyOSJc2VjcDI1NmsxoQMGwfOevbfZOGp3bL_2AH1SBdx3zn2_l56uG_4CWDf66YRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"BBNHIHYBPXVQTDZQ4JXK4QYDMM.all.holesky.ethdisco.net" : "enr:-KO4QCMGWCueZIoaBJyNAqOo_1wJ-QmbQ-qlTQx_rfz0gzKjF8VqFc99Q3ZMcfpK2qdLtWZHoRoiCkstH9_rWAU49DaGAYrbEkgdg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEVzHeJc2VjcDI1NmsxoQIy6rguhP2KemBUH2HJyW-GPo8prt6Ay9gjX3GugxLuGIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"LHFTDS37XFOEXQKTWJGKWRLFWM.all.holesky.ethdisco.net" : "enr:-KO4QB0RN-qZSymbzZA-AlKT8213I60xJjVVwN-AWwjW9W9aLk-2aq8jW_jbgKnJY3c_wU26oBzYFBpOVcYKIV_nd16GAYwlWhtPg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMPJ9bKJc2VjcDI1NmsxoQKlc1OTSAanfHEsPtrKjZvkgQUuHFZon2GtnCRHlDRV7oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"67FFSS5IYEYRGUYFEWGIJDIMII.all.holesky.ethdisco.net" : "enr:-KO4QHY48cNs9Lauv6W3XCDcuBvhJbmL-0MAASBah_V-jG6iODMGVIZ9xv4K3MHSqQQht3Fc39CjU5zoYROe6D8uOq2GAY2UXNmdg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMb0yKiJc2VjcDI1NmsxoQNjc7k9S4kjTIwltOf7EH2ZmK3vZiEBpxxNqondpU3qV4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"MOBGCDYGQA4CNBQZDPN52JC5E4.all.holesky.ethdisco.net" : "enr:-KO4QDuar8SHEX1o_kUIKB0IajdUqcRb3ZkZdr5_MIxT1BUkLVk8AelLTv-_ioVGRAwNIJTzT4m8nyzV1VbsjjpeZ0yGAYrXy6Pag2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKEeJc2VjcDI1NmsxoQLy0OM9Ze8JjVHZhLQg7XejbI5iedlSDZNRmtQdTy_X8oRzbmFwwIN0Y3CCdn6DdWRwgnZ-",
"ERETBCE2BAPJRSWIEUQV3QPP7M.all.holesky.ethdisco.net" : "enr:-KO4QJY9GUtSCCXanmC9p7LYAfqk7jOUF-zxl7zd2ce5lD_aSNk9KfzBbh-Hii3qMzv-2x4a0Xal7RQMzQv9BqCkUMeGAYw1cGzgg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEVR7SJc2VjcDI1NmsxoQPQjk4qnGis3WKuSQDD20H-9n9xKFTbnLsB1DhAteyYk4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"5AHKPN5NN5IHEH365X6OYZDHDE.all.holesky.ethdisco.net" : "enr:-KO4QM-W42wfRYcTwaegJy3SfjlCkZsQU8LhGcluTdxtFjqXOwsEE5kUewkPMe7qIQpwb2MAo5xTeRpnijbdYTaG37-GAYtxMJdhg2V0aMfGhJsZKtCAgmlkgnY0gmlwhKh3IxmJc2VjcDI1NmsxoQNDrMpeyQI2aO_yoNP41RAf_BHtckptN1l2QIWxgDKOC4RzbmFwwIN0Y3CCdl-DdWRwgnZi",
"FEORTRPBZJSNRB3XCLK7KCMACQ.all.holesky.ethdisco.net" : "enr:-KO4QDO4oH5cjhncisJSk1SyGmwJ5VFjNetXw4OSSqDKc0NMDGXYYl6wUjbhcvzADYDpE1Br3lRG-1xV6iA1OAyXSAqGAY1W3CQQg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEVfkOJc2VjcDI1NmsxoQKkjEwDL0wuG0AH3RWw1wRrYHdPa8OOL1Ko4DYcZeQjQoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"AB27AIPX5Q5J6UAXQ6C2QFTYZA.all.holesky.ethdisco.net" : "enr:-KO4QNZrQF9iyry46odExoUh3kkHjWWHS0iEEjc8n2R4Orq8Rov4Ar3ozsyWt9Z-dmBtpTfmAo3UYspLFcvtHNzwjPmGAYwWbywRg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFtbbyJc2VjcDI1NmsxoQLD-zctKWrecek1fu3o2IKHUY9rkd0BYeQHrzpqElk_1oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"NHLNHXPRKOALUKH4MZ7CIVDONU.all.holesky.ethdisco.net" : "enr:-Je4QBgb-GKZRRjU2TAE_9KyBHC8ImLYDPG8KShRKx8gbKF3F-gpoHiyeprH42weMNSg6i8GeG-n0SxwWJRe6zyXj88og2V0aMfGhJsZKtCAgmlkgnY0gmlwhCV4sKqJc2VjcDI1NmsxoQNuVgNhx7pgtJotEBq56F9YFom-6szZ97gCkea35_lDkoN0Y3CCdl-DdWRwgnZf",
"XPX2T64BHDYLVGT5UC4GVIQIVY.all.holesky.ethdisco.net" : "enr:-KO4QMlMC7rvmM9tvHXvwo2Vj5x5FePlyvH_6lBSCgZHN8HcWqtppk1peQlK9Ge79ma4j3gx_zX0hgJvprIy1ehjXXCGAY3Mer4jg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIe1FCCJc2VjcDI1NmsxoQL3IIF3eENfSsr5tih2ebcm3dWL-otLdZYqUvfJ-5_9U4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"NZCRGKUE7ZXSIS4MIQ4WUS76BA.all.holesky.ethdisco.net" : "enr:-Je4QDqwqlm7UBywmVlR5UkkrQrg5B3UpkFexP7ucg4RAsdlMiJ4J1S5jT8jp6je6igMZ3OOnggdpd6l7QtQeNBICycDg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFs6LuJc2VjcDI1NmsxoQMgMreR2XspGJphg3fToxGKcMwWPE3e0gyxcqiQNLQXNIN0Y3CCdTuDdWRwgnU7",
"OF3GRGFZUAJTH3T2R2EXSYAZOU.all.holesky.ethdisco.net" : "enr:-KO4QDPbolwwOMTwV02zqyVgJFxko-HI8UWOT_K9sDcWgHG9fRDWkbSbTw_l3bcIA2-q3054lrJ9cbkHABlMZbQskUKGAY1y5VBWg2V0aMfGhJsZKtCAgmlkgnY0gmlwhKI3BbaJc2VjcDI1NmsxoQP9bM-ylBjwT9ujG09A__0to5F3Qw4QSvY4_vgyQ0A7j4RzbmFwwIN0Y3CCVTyDdWRwglU8",
"7QEPEVJFOCL5A63GZLZ4IZNMOI.all.holesky.ethdisco.net" : "enr:-KO4QNGh--C3ckyCMlUP4u86lt292CLHOQ3YIwk5Jqzz5x3OID_7BfRn5qN-ZBoBY80XOhFyHuo4eKDCIowQgYMvVY6GAY5S1aoSg2V0aMfGhJsZKtCAgmlkgnY0gmlwhFhjBqqJc2VjcDI1NmsxoQKZpCZSQgSun9pLzGrdfLboslJbD-JxtTsR4JF860eZYYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"Z5DOK3IB5X3IBOVVIK5MQCDYNA.all.holesky.ethdisco.net" : "enr:-KO4QJjEv14HV0BgdPwIa0iO-xrrwoi9k9LJRw3utIUVib5dF6s_b3y8z0NP2VyUGsJDFOwuVQq6OC6hb5_hFUqnf1yGAY12fbSog2V0aMfGhJsZKtCAgmlkgnY0gmlwhCU8-mOJc2VjcDI1NmsxoQIT2maaVlQBw4oD4loM1Q7gygn42pTQn1Sydo74LtZAZYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"CHFGCI2RQS3XFN2MKFP6G2ZM4U.all.holesky.ethdisco.net" : "enrtree-branch:XIOWDM2BTMANILG2M4LCMO7W3M,4LPHENNNENCUT7P3MWTB5IFRTY,5NQ4MKTYBPBMTGUT5IKUAXEGBE,CVK4DBIVPD2JPJOPQJQX77ZAWU,WLME2JINTIQACAMD5WZUQ4PRJI,DQYYUE7KVEXGEYBH4V2QHI6P7M,45V6KFI4NL43JFTJHL77KP6MQA,QDMF4HIR2UEXRJVOX4UJPJTPKA,BMVEIV6PNSN6RK5XEU4R4K",
"3EMD3PTQYRFVNFBQ73BYFL4AEQ.all.holesky.ethdisco.net" : "enr:-Je4QFiHIu4B3YbbG75mlr58JRaqpGUQij1n1pN3zaHoWbGrShq8aYqipbkPLaINPTX02YBfchyACgLHgH9cMarIUapQg2V0aMfGhJsZKtCAgmlkgnY0gmlwhDNRao6Jc2VjcDI1NmsxoQJHJlekJODLxBDPwpVLBtTMizLq5o9JtXkD8MQpqAIUYoN0Y3CC2fmDdWRwgtn5",
"IZNO6JEFTYHQWWF3LJ2M66P7II.all.holesky.ethdisco.net" : "enr:-KO4QLmjLLs27xB9n9N2TNC32EhbxjdiR32rroemDty1dQJsBSZQOawi3-HGqWDRifXce49pv2WewtuzF5j54iiUfbaGAYrbEiX_g2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEV5riJc2VjcDI1NmsxoQO4pbsV79dSOLkBaOX5vcv6Amy9rH2xg1wW3OsKxVA7PoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"OA4ZFFGZNFUC3LIYCUDJOPVR6U.all.holesky.ethdisco.net" : "enr:-KO4QFuTcCcZkhGlEZ9YjHVURcwzRDKDu_o8RBID9eF5lmG9fb9ZHBHnz0E-tXO4TcPfwxEtefRAaAVPj9Ycdi3OeXuGAYraylBgg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKFKJc2VjcDI1NmsxoQJRTkcLLW6c3J6kd1b1siWyumgXACvQK7ViQjsgMFx0c4RzbmFwwIN0Y3CCdn6DdWRwgnZ-",
"ZCAW4EMBOL5EH4MSMW7FY6JMEE.all.holesky.ethdisco.net" : "enr:-KO4QHc4CzkY6KkiTGR6hTovOeJ8VJuUtjkq2-UMXwUijiKvAZOFVS_Nn_GHMVZ8Ppsu31rSLYAEFRu0tMJ-LIDdSjOGAY2sYroCg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIrJyaeJc2VjcDI1NmsxoQN7HHah7WnGluJb0mqKelBJ8rpvKlBb9t7848BwJ4qau4RzbmFwwIN0Y3CCIB-DdWRwgiAf",
"CVK4DBIVPD2JPJOPQJQX77ZAWU.all.holesky.ethdisco.net" : "enr:-KO4QH3RGFoO4KTuq8gxJC_mjnPBqNaDvoX_xsuYbDOqvJA4CPJs6nifZuqE2sTB3O-kHvEI0dbFJ87FoWkKhgmXYuOGAYrbEhVBg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEEV7HyJc2VjcDI1NmsxoQM1AMXary_Hiw-yesOw24q7GwMH_DmNHHitFPU46foJ24RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"O4SSPZG3DFA7PHZ5L42DVOPWDM.all.holesky.ethdisco.net" : "enr:-KO4QMrNy68H-dYJbPM7snJ1UrV-TPXA012sdna6WktkfksMED9fE3g-kzp7gBgOFEdFi1KIiEv5MXXAoOt1KOMVc1eGAYw66STEg2V0aMfGhJsZKtCAgmlkgnY0gmlwhF_ZxOCJc2VjcDI1NmsxoQJUhK-aKtl-Gc3ZnfF2k7oLFXmpGCHEi1_fBxAEfc1P54RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"TGKURK5IPVCPXS4QPS2KZJCP3Q.all.holesky.ethdisco.net" : "enrtree-branch:E4GGBOZ5L2UFPAKJIPLNBA2MKA,OF3GRGFZUAJTH3T2R2EXSYAZOU,D4GT5QUSIVDVPURCUOLE4WITZI,O6EQKGUJOO2BQGMADYZHOSZXLA,WRRS22MCKTZ4YS3ZLPUJEUAHUI,3A6T36TYZJBFLOHMJOJGL5SPXA,XPTWTOASNO4WEBXH74WCQ5EYTQ,2XMYGJOCRIHHMHAFVRH3OES5QY,FYJOHHN6LBARRNNLI6SK42",
"UIGSNQMHERWJIZCP2OLUXSZ3KM.all.holesky.ethdisco.net" : "enr:-KO4QEvn7KsE7UDJ5F3HwtSmGNSy0JSYDLfp9uJRtq5WfSsuOdkfq3V7GVSDo7IfCTXYAtQfRwT9q88II0sajv-m_CKGAYulV6JLg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMwQ9ISJc2VjcDI1NmsxoQNVsiSzpuxjNDgNToi4u48-5kCgvsjuoUsvlG9VrnEjhoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"3T4CNEKYCJP2PJ3EQVJSFKHH44.all.holesky.ethdisco.net" : "enr:-KO4QKNzTVC-wa7whLxFFss7NzEFDdVuAjgEebNGGK9xTWKjHTjqmMNfY4_h90iqlSYM_LoGyH2FFXhbHT05zKyALMSGAYuqLQ8Sg2V0aMfGhJsZKtCAgmlkgnY0gmlwhA360gaJc2VjcDI1NmsxoQPSUi99W8lkrquAhLsmslwXU4-dxxVfied-w_yqYEXpU4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"5ZWIGTGKMFAFF4LAODABANSBOQ.all.holesky.ethdisco.net" : "enr:-KO4QFP5g9U1YtBLeJi56xoBll8E4eUJeAAYMoEg1l0xPXRybh0OYNZfteBjkHMwbucccNdGB0amzNR4XtxmAfjoFWKGAYrbEjd8g2V0aMfGhJsZKtCAgmlkgnY0gmlwhF_YY_eJc2VjcDI1NmsxoQJb-JLk8MFQQPMz3QI2ya4FtZdHqZ1Nm0xD4MtOYc9ifYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"7J7D5R4SH6LVDCFZ5ELOP46IP4.all.holesky.ethdisco.net" : "enr:-KO4QArnrdy9hfW8KHAwokQf-x0LbdoDQ4WoK0H2dXqhP4D-TflLF_Ywf2lh4ybXao8jjNSxC53MzmFPUI9A8k06XDqGAY2KrTRtg2V0aMfGhJsZKtCAgmlkgnY0gmlwhLWkyzGJc2VjcDI1NmsxoQKSAHhJOTtkBlasBECB1mrukuL6jqOEtxWkpH-PfDp8h4RzbmFwwIN0Y3CCequDdWRwgnqr",
"5NHWEAJHKSAO5DIIYAZ7MQJVSE.all.holesky.ethdisco.net" : "enr:-KO4QMiOfa0JolrO470F-mRKslpq85BBGRz_JjoAOOnLuUdxBObP7579igrB-YGSdaUtb3Ih9QXBHRAl0PWYmE5NW32GAYtIvzSsg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMF6nk2Jc2VjcDI1NmsxoQI57ZbbGPYfl0DtrsmjeKDosRG14eV2qLI8AE6FsP2oy4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"OGKXEQEVGNJ574WCU7KFNTXNQI.all.holesky.ethdisco.net" : "enr:-KO4QH_WNLhz4qmL-EOMCQFfhE3QOOvyG5uyX0RR77gYrsdcJnUxS5OBQWyMqhRQLO2P9htXeBxJ4kR9ez13qQRiBp6GAY3m5RB8g2V0aMfGhJsZKtCAgmlkgnY0gmlwhIj0RveJc2VjcDI1NmsxoQJFRRKo2aP4qXB8sZnA6_rJqKgo8FZGT2i3ipEzwXCayYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"D4GT5QUSIVDVPURCUOLE4WITZI.all.holesky.ethdisco.net" : "enr:-J24QAgjCyFyNsDJHJwpo6uy0l7yqJD5r6WF58M1T7_PqsyKC0t6y1iTsQX4Crz6iv5Ijc8LqPZIC6vhA_F5GqkdkgSGAYtfbIIbg2V0aMfGhJsZKtCAgmlkgnY0gmlwhCvIu-OJc2VjcDI1NmsxoQKq0Xs_18RfgehL1rawMx2B3VMaH9d-YNCY5kmHuaCnqYN0Y3CCdl-DdWRwgnZf",
"OOQAXEUVKR5EJ722HM2UANT3R4.all.holesky.ethdisco.net" : "enr:-KO4QBU5Jlmco2sEPOXNEctSfBJfxdgANrWXVLS-BVDQYrU3N_oaeceDQIH82zZ6BSi_F-FQpSKhEVYtPDxI1BA4OW-GAY5bg91Qg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIrJH32Jc2VjcDI1NmsxoQMXPocPKx0wRocEEzASwUfzDLKd1f-Jifv2pyIu2M8vaIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"ZJOONJUDYAQ53XOJU4KG5W4ATM.all.holesky.ethdisco.net" : "enr:-KO4QBGQGqvIoSv3C7d-bCiMst5GGEvIQaQ5pAHs5On0MeNfcVjcZgd72l2UUoqf13HoKHUnVG37cmHw-11H4Y59F6iGAYrbEhVng2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFtO36Jc2VjcDI1NmsxoQJ3QRuoMLUn6djLfYCFTKSV8kUWRQTOethOOhLDW6ezdYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"INA5QYTPU6WIOBT7IC7U3WGDIY.all.holesky.ethdisco.net" : "enr:-KO4QDpTzc6voIJiaQO1T8cbJvPej2OvifSuuDkQVrAcC3imJXT9J9zt5DelQaMAeu_uk11kFFgYJHBAE88J2cvxYGqGAY1olkLcg2V0aMfGhJsZKtCAgmlkgnY0gmlwhLnRsD6Jc2VjcDI1NmsxoQKfdroTKrg5QqtuIyfF7LivDR4GjeBnA8xQrAg5ma4pzYRzbmFwwIN0Y3CCy_KDdWRwgsvy",
"HTMBFBAIZBACDG3EZZ4JVANCAY.all.holesky.ethdisco.net" : "enr:-KO4QHHstlNCTI8xMnZ5mcIRvd8lfo9YoVeyv4pqvhtkxGI5PhYqDDqu1W5XqHWCMcTt8fpVgu9KojZHcyi7fhQhPdyGAY2_zUcvg2V0aMfGhJsZKtCAgmlkgnY0gmlwhL5czy-Jc2VjcDI1NmsxoQJpsTl5abUECWCfSno785tWBNPiVCJ7GG4eQTf2Cf1qBIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"KEC4722NVHE3KX3IYNZC34C7NY.all.holesky.ethdisco.net" : "enr:-KO4QMjtE87kVQpcuRPXV31w7fsvyit4Fw995wyZ_h6uK8atWGOhXpsi3xXsBQLgJFBWmNHgTw-V4JvZNFZkFHLU_8mGAY5hRoXMg2V0aMfGhJsZKtCAgmlkgnY0gmlwhC1Mp4CJc2VjcDI1NmsxoQPETNdXN5Cshfr8-rIIMev6E_MGqD-jzqcXW2yfzT3C54RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"LNO6EN3Y2LJA5YOJMEMODAJFWM.all.holesky.ethdisco.net" : "enr:-KO4QMIX_--Ar7-XnFcUVlJpBBUfZdfNOftELgvHhCGvbLGTMT_Yqs2M15BCG0qoHsYkVBP5b4wd2wqNyNIfFaTtQ7qGAYrXxOTEg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKEeJc2VjcDI1NmsxoQKG05NXftvaats582r82_zpOi2C54WjSeYwxKfSNeSJaoRzbmFwwIN0Y3CCdmqDdWRwgnZq",
"R6EQA5KQEQM77JJXB4BHHTDF6Y.all.holesky.ethdisco.net" : "enrtree-branch:5AOSND63QKPVT6EWNMALKAFC4I,WAU46WR54TX2VBK4QM7NFTA73Y,BBNHIHYBPXVQTDZQ4JXK4QYDMM,OA4ZFFGZNFUC3LIYCUDJOPVR6U,KMY5HFBGCUDWN2ZXE6QNUQHGYY,OGKXEQEVGNJ574WCU7KFNTXNQI,CDXRYZFKH6OUWTA2IJ2MYIMYPM,IPU725BUGL4HIOTSOIH3KZG5ZA,G4MENE2MCGXFPYEBF7SQEU",
"45V6KFI4NL43JFTJHL77KP6MQA.all.holesky.ethdisco.net" : "enr:-Je4QEedukMKHefwNNtNam8wvx8_0GMFHLC9nA-TWWPMTZ9FD4C1CrjqFxLNruZPGL4T1ApKPtes_ApKbwwOEc4dNxIDg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIrJ_vOJc2VjcDI1NmsxoQIKnge3StO67CequDTr_QwD_V_qhS7TnGO-tgE472AFroN0Y3CCdl-DdWRwgnZf",
"5RYAVZN3SSZZQ2KISUO7XDBPE4.all.holesky.ethdisco.net" : "enr:-KO4QGMFa1U36mwISUTSlJN8q2EKJSw4WHa6PAMrHkhL9-naVdAWmGuwfpel1E5_NBSnPWRsG8FzmmUH61iq8fodXcKGAYrbEkT3g2V0aMfGhJsZKtCAgmlkgnY0gmlwhEFtb_iJc2VjcDI1NmsxoQJ62Txw9OKK7DTE_CZRC6tX_223dks-FcinnSL1uXUbTYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"KMY5HFBGCUDWN2ZXE6QNUQHGYY.all.holesky.ethdisco.net" : "enr:-KO4QLBXgetH_VHZgzalnkfF-iibF4km3OCLzY1TK27U-yG0ZA7Z4C8DL-da5x65khpgvOBa8c2CXffZBdTtD2BZQCqGAYrg47Ahg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJT7RHyJc2VjcDI1NmsxoQKeRdcysv01DZ_Mzk9t1jcWW-YTjP1fPIrHVpw9hc_Q_oRzbmFwwIN0Y3CCdn-DdWRwgnZ_",
"YUZZDZD57PTNEIB5QL3FEXK2ZA.all.holesky.ethdisco.net" : "enr:-KO4QKuFVKbKbtK1djMy6q3TLuAWYDAjoC20cYPdhcOk7PhUdA67TXr9vTGfZZ9AO7ivmQZyRW4w9TFk-29_xP72bkKGAY2EAMvIg2V0aMfGhJsZKtCAgmlkgnY0gmlwhF_ZKGKJc2VjcDI1NmsxoQN4FBojS_W4gviNwaTDsIXiBEGXaQMtUzxQHwKWDmMR74RzbmFwwIN0Y3CCequDdWRwgnqr",
"2XMYGJOCRIHHMHAFVRH3OES5QY.all.holesky.ethdisco.net" : "enr:-KO4QAMrUvclx-EHZrO6x4K6fWTwaKh2zS5oWJzVU6oZuzZ2GG5xdQky8tIrpUUSKGB6XGvr8TvmiS7Dimvxx9Hb1OOGAYy06xQvg2V0aMfGhP1PAWuAgmlkgnY0gmlwhEFsSLGJc2VjcDI1NmsxoQJiz0q4ywyhHvmXBrWbFykzflq_J6cmLFIbepO9PLBwhoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"5NQ4MKTYBPBMTGUT5IKUAXEGBE.all.holesky.ethdisco.net" : "enr:-Ke4QLrsveUYt2tacm5EZETFc1F3EyvNYfRRkRhljyeLMIzccRlPI1kKmBWuELQs5iAIRZgv92P3Fxx_zJ3xyUbN3muGAY0x7p4Ng2V0aMvKhMYaYJiEZRbqwIJpZIJ2NIJpcIRU94PXiXNlY3AyNTZrMaEDBxF5W6guB9qZoR-c_zuDUE1UHyaH0FMjJKHC9Jq4ji6Ec25hcMCDdGNwgnZfg3VkcIJ2Xw",
"6WAXAZL7FYKEJBZOPWIHCI4F6E.all.holesky.ethdisco.net" : "enr:-KO4QCagHy1Q7UED3AJfgVHxFKOn_DRS8UTUg0okE7fW8VTcDCW7wlzWufdWCtdUwHpnaf3EZpRn2YRuo9u4LS-Oh3qGAYrayS-wg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKI2Jc2VjcDI1NmsxoQJYC74L06jkGeWkmh1aSjeBYVvzDCWEvtbd111Vu8WiG4RzbmFwwIN0Y3CCdmqDdWRwgnZq",
"ZRVWX74UFHUWOPCC7LOPLYGIZA.all.holesky.ethdisco.net" : "enr:-KO4QBfm8BEr7OIRv6UT1t5mhE2szefodQuIIBKMFnyvbky_K-wff-l6pqLwfLyUblqFNxqM6Xtcnari4ItzO9236DuGAY08Swa9g2V0aMfGhJsZKtCAgmlkgnY0gmlwhC7r5ZiJc2VjcDI1NmsxoQIH5RAmLOvYi50mYcMnglYJlz-EC0E2YsetPVUzvbs5BYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"2WHIXLN5QX3JEK3SSH7MXKTJMU.all.holesky.ethdisco.net" : "enr:-KO4QF2wWLadNPZ_qwOIZkLxPEJjj3N23892JKdtSOeeC-X-V0bZsjQ3QqpidJviGT0WrBakFANcbSa9IqFSOslJLV6GAYrayMEMg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKIGJc2VjcDI1NmsxoQKQ_STV3aCaM5we4KxMPMpdG63xPZieKw8A36OR2tuouIRzbmFwwIN0Y3CCdmqDdWRwgnZq",
"I2Q5U7BDYSM7O3O2IKIRL3KTZY.all.holesky.ethdisco.net" : "enr:-KO4QIvQh_txoF6gwXTRsMzzvHPdwQrkCHQYt4egwTWqUNQiMQh1yJ71U8UXs8b9pP9R1mUDTaiQ7-e0eB2Zbvouyb-GAYvSz8f0g2V0aMfGhP1PAWuAgmlkgnY0gmlwhJVmk6SJc2VjcDI1NmsxoQIuT88b-jLJBI40hV4VY3YeJnmYT65v2QPjyzuNG5dyF4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"NQHD4WNRRGE5JHHX6IDKGIF7KU.all.holesky.ethdisco.net" : "enr:-KO4QMTq7zJT6fLS-LY7n3hWmcwJqxRJraGJcM60U9Cej2lRRE-u_KhOd9r712IBEOI39uiVQEXGdBZvc-dJIESUcOOGAY2dUsseg2V0aMfGhJsZKtCAgmlkgnY0gmlwhFD5eBSJc2VjcDI1NmsxoQO-UyE5ad7DaM-f7fZi4QEwjfxIR6HS-l-lTSlv4ZLdB4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"PX6K4ZETH5UX56IKHKL5TNOOMU.all.holesky.ethdisco.net" : "enr:-KO4QJqslvj0RYuX2CI61yCK7VuyY9Ik3c5EHtpkKehriXyqchhCDMx4sRuewcCAiWO_frsUevV9GXMPnsO2nzCrgFGGAY25poLHg2V0aMfGhJsZKtCAgmlkgnY0gmlwhKfrsZeJc2VjcDI1NmsxoQOe9l9K5UW0RAuQTH1q6CwG_UzbJyKLGSt4lUt5_tVmyIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"CK3HQLGRQATDVF5CEGHX4DVQRE.all.holesky.ethdisco.net" : "enr:-KO4QJy9FHDJZfMqgGGIVGn-j0rHI6JDjTWEo7sN1mBkzO68ZId8jkRQfgZ5dJkv4GGm2rsvrWk6OJYF0td7n0Ve9GqGAYu0QPj0g2V0aMfGhJsZKtCAgmlkgnY0gmlwhHTK4wuJc2VjcDI1NmsxoQIYyd-9-wdwfPPu6uRcnTKkQaCekdhR7488-2pxl36AZ4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"IDXHFSATDDENJYOYJC2TUSUYOY.all.holesky.ethdisco.net" : "enr:-KO4QNWpVQT5pw-oUuoa7JDOVs1KheGaPRAR_fIarAflnc1yHawwEpptaB5JWkRXgh-wJtk2KlHE5zGICXefHD23Z4qGAY2-EYHHg2V0aMfGhJsZKtCAgmlkgnY0gmlwhK35GlyJc2VjcDI1NmsxoQPV0hDwmz1HaZ4pLm1hzee38NMugxA_7j3v6hbxP_LRCIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"UYESJQUB2BHP2MSJNUSDRGXQ34.all.holesky.ethdisco.net" : "enr:-KO4QB9gKzGbKvqoPJZymq3AiwZvWSHOup-36D8ec3CwNZDFRoEmp64UmWaP0St3OXDIV4Q2Rm0MnelRnAjvn3HRfyyGAY5EPB9Jg2V0aMfGhJsZKtCAgmlkgnY0gmlwhIrJ3_qJc2VjcDI1NmsxoQKHt6N7ehDnwT8_lFh-C4KgqUplYwDvYy6rOP6DFRO8lYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"76OAILAEE52CRVMYFBIBMSEUXE.all.holesky.ethdisco.net" : "enr:-KO4QDRyM88zIGJ2P0Ya1W8fucbp8kRTbVzV8k_2eawB0W3ZHMQ3o0HlbXVw3j1rMgN167LmsaMt1iO015HMVKGT2GqGAY0rjdqhg2V0aMfGhP1PAWuAgmlkgnY0gmlwhKFhcJuJc2VjcDI1NmsxoQJ2emahe6-2fq_hQqxm99rgYi4TSzQ1ky4utO3Tcpe-yYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"NLYAF5XVTTQUOMK4LYUF3FXNPE.all.holesky.ethdisco.net" : "enr:-KO4QMiia-4vyLiHQQhxlbmCKdOTRqOiZin-BdAdi18LxNqqHEiuIQQ-F1dZu8sKi63vEk9zwr5gfMnxXQZCThEaiDSGAY2UmHG4g2V0aMfGhJsZKtCAgmlkgnY0gmlwhMb0_ESJc2VjcDI1NmsxoQLb1ZwjPQw7AjCvlHQpt9bmePVD85rbHbnFZ0naOB1RNYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"QXRV67JYJNOYJDPC5CTKUVG76M.all.holesky.ethdisco.net" : "enr:-KO4QN1MRyJdifSbU3Mg_GUI0_ApfQQ_BcPgDV0FXjVvk4iEWX6EgMjXkI62H1S0DFnyWeHnvr-caabqiKtlvbIBICyGAY5Cyclbg2V0aMfGhJsZKtCAgmlkgnY0gmlwhK9jhAaJc2VjcDI1NmsxoQL8tsMGtv3EuJfUdI8AzGBxYynVj2HlNoz4wi3COC4TTYRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"4LPHENNNENCUT7P3MWTB5IFRTY.all.holesky.ethdisco.net" : "enr:-KO4QF8nbKqJkOeYlF-akOVBYzusVwSjI_ra_t7TmM52mEisQLCwNAjujSSc9-6ECErhss-gVTgBDzhY5QmVcF0PuZOGAY3Li2SUg2V0aMfGhJsZKtCAgmlkgnY0gmlwhCL__BOJc2VjcDI1NmsxoQLHimHBtxJxch5bc20e_O8OdeN3UQx6TQQWqaYfyi66OYRzbmFwwIN0Y3CCdW-DdWRwgnVv",
"5FNWKKKVUPIHRKWZY5P33A7E74.all.holesky.ethdisco.net" : "enr:-KO4QMD5jLnGVTSO75tQPB1JOCFKmtSPRi5pmE7wMwjDRfVKdwpZJvr8qfv1WmfRnJFzH5qV2sfC187nT9mp-xE_-gGGAYupHwgxg2V0aMfGhJsZKtCAgmlkgnY0gmlwhE6KPgeJc2VjcDI1NmsxoQP9YVLocwkml9Z9YNDRpmzVceRY-Ts45qiPOBC1OsxuUIRzbmFwwIN0Y3CCdmmDdWRwgnZp",
"HIDVATDVB36L2MASAWA7SBJAII.all.holesky.ethdisco.net" : "enrtree-branch:N7HAL5M6HNZBGTWM3LWFDRX4WU,PX6K4ZETH5UX56IKHKL5TNOOMU,I2Q5U7BDYSM7O3O2IKIRL3KTZY,O4SSPZG3DFA7PHZ5L42DVOPWDM,Z5DOK3IB5X3IBOVVIK5MQCDYNA,ZJOONJUDYAQ53XOJU4KG5W4ATM,NLYAF5XVTTQUOMK4LYUF3FXNPE,XPX2T64BHDYLVGT5UC4GVIQIVY,AHB67R6KGAKWRSBL7CRAO3",
"FTTHOFPRPIHMJNZA3VZUAW5TIM.all.holesky.ethdisco.net" : "enrtree-branch:V52J3WKNVGG56JFRKYDLSZREJY,ZCAW4EMBOL5EH4MSMW7FY6JMEE,2SA643JTHJ75ZVPFHAKLXI2WXQ,5RYAVZN3SSZZQ2KISUO7XDBPE4,366Y3UIIKK2G5CUS7CHNPZMPEM,7J7D5R4SH6LVDCFZ5ELOP46IP4,7QEPEVJFOCL5A63GZLZ4IZNMOI,OOWRWZXNDJVJUCDDOJFOY4YB2Y,H6XMM4W6QZEQDAPVXGHJSU",
"O6EQKGUJOO2BQGMADYZHOSZXLA.all.holesky.ethdisco.net" : "enr:-KO4QAg_or5YgVU8ScSgcgvNmLMISW0LA4L5GtRLxmyVUlGRR4GNuEZ9q_tKtZdAbLH5B-FN2ie8hp0U6P90d39xtyWGAY3d9Tplg2V0aMfGhJsZKtCAgmlkgnY0gmlwhAMRsEKJc2VjcDI1NmsxoQJ7STjsgZvt1OOj5krr2l2iAwlY5AGl-dgTziPZsCd9qIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"XIOWDM2BTMANILG2M4LCMO7W3M.all.holesky.ethdisco.net" : "enr:-Je4QCvStdCVA-jcYsFoXmDXjXlp-Cd_9sSMdi9Y1LM3tGH2C3k49yrWy-Y2Jg93ikASYljvD9qVUES0T9q5htcbL60ag2V0aMfGhJsZKtCAgmlkgnY0gmlwhLkIa-2Jc2VjcDI1NmsxoQKcjBIYl8vFVYVBs5trEl-Zn3IE7u1ZiiV986p0QCrAL4N0Y3CCdl2DdWRwgnZd",
"OL6KYVYI7SGS7U34FW3RFBA76A.all.holesky.ethdisco.net" : "enr:-KO4QIlf7XLihA1hw9d44SB0ENJ40RT1RmF2KrT9a2kRZfZoWPdO1jRi3GNnNSCLDxLo-aFc6uaGi3zxhCD8lg1aZgSGAYuoht2-g2V0aMfGhJsZKtCAgmlkgnY0gmlwhDNR0MWJc2VjcDI1NmsxoQKFvOHK4c-F1tHwdgsUa2yru5RrWyiVP9kRLnrw1kXcd4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"NXU6DU7HEM2L4DN6G2VHHFT72I.all.holesky.ethdisco.net" : "enr:-KO4QLbrxgLUdY0NhpBPVfilpwn4d3gPFIEqoq62P1piOkVmGwh5qpbKtor5FfE4FM_eezlzMdeCM7bzau8ciKZU1GiGAY0-AhsZg2V0aMfGhJsZKtCAgmlkgnY0gmlwhEp2iPuJc2VjcDI1NmsxoQOGZRfYj6RgBYWulaw90MVPDt_9F-oM3PzevNe-RS6KyoRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"RUQLNXP5XBWPAOEKRUEBAQXXXU.all.holesky.ethdisco.net" : "enr:-KO4QPpoyIf1DfiiOW8Tt34tBuA68Qd55cyWcqGOCFJtcHKtcqYr373NJPyQVd8ktsuqZU8L_ERSRAfKesEwdBARg3OGAY45u3jEg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJRxo0WJc2VjcDI1NmsxoQKhMTQ31q7EAIHkisiA02KVyFZZLq2Q9w4_jgmiYCsF_oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"RUJF27NEYDBNQAFMI6K6SKDVRY.all.holesky.ethdisco.net" : "enrtree-branch:OOQAXEUVKR5EJ722HM2UANT3R4,HOXANHAMPVCFA2QR54VEMWCWPE,INA5QYTPU6WIOBT7IC7U3WGDIY,3PMAED3BC2HUS7AMEPGJDKENQY,VJJPHI6PWJ7NFBTW2XJH3JMMNY,5ZWIGTGKMFAFF4LAODABANSBOQ,UYESJQUB2BHP2MSJNUSDRGXQ34,CK3HQLGRQATDVF5CEGHX4DVQRE,AYB76YY6WPJVIBLRB5U7L5",
"ZM7CMNKKBVIXY7WGMB7GHYUXMA.all.holesky.ethdisco.net" : "enr:-KO4QNhl-I-sZux_gBOVLLbMdw8kMK9fSEBBNYukE2r95hDLJ9rOuhZgJO2dvNU_vCcuiqJNJHj8N3olsc7srxryuuCGAY0cB7Qsg2V0aMfGhP1PAWuAgmlkgnY0gmlwhJ7caOWJc2VjcDI1NmsxoQIyp37cpS7gvrKk0f3VxW4D9Jx7mOvSAQ6vOaQppsYp2oRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"FKSM7XWAT4KW3TDLRHWSXZPMKQ.all.holesky.ethdisco.net" : "enr:-Ke4QNDn6wmnaZU1IYGb9lX8zb2QFUpa_yen8vFTnuXpW3_iah53AKPZX1D05HE23bw-UtR6zXOpCquB9XDdxvGhZrGGAY4oYEAkg2V0aMvKhMYaYJiEZRbqwIJpZIJ2NIJpcIQlPPlxiXNlY3AyNTZrMaEDiVRaEbnUMSPCtpxluUoBgOy3Loaa6SaVW9QK8BGTFJiEc25hcMCDdGNwgnZ9g3VkcIJ2fQ",
"QXKEJG4XZEQSXNUY7JJYCATPEI.all.holesky.ethdisco.net" : "enrtree-branch:FEORTRPBZJSNRB3XCLK7KCMACQ,2M2GRZYAFKAVHHU5HTLUHPYHCM,KEC4722NVHE3KX3IYNZC34C7NY,NZCRGKUE7ZXSIS4MIQ4WUS76BA,3PYSNKXWWSRBWV377EFNYINHSA,C7SDD5OPASV7B2XUOXF5NLBBKU,QY2XP6FTX7QKFNP6TNZ2MOHZKQ,76OAILAEE52CRVMYFBIBMSEUXE,2QHFEUHLG6Q35B5LUS5BF3",
"OSHAABXYJSRWW35VOMYHZUKJXU.all.holesky.ethdisco.net" : "enrtree-branch:LHFO3FXNRHB5B3YSTKUALGMEAI,5FNWKKKVUPIHRKWZY5P33A7E74,NHLNHXPRKOALUKH4MZ7CIVDONU,BAY6SKB2RTQCM7RTSHAFQ6TTBQ,ERETBCE2BAPJRSWIEUQV3QPP7M,MFPFKTJREYMESD7STJJOFYDVV4,MOBGCDYGQA4CNBQZDPN52JC5E4,RUQLNXP5XBWPAOEKRUEBAQXXXU,NJCWGLUAGBNZQYPU752O5L",
"WAU46WR54TX2VBK4QM7NFTA73Y.all.holesky.ethdisco.net" : "enr:-KO4QE70KmVYr_jd9JOMBFTIJomf3oliyhugCm4kFnzYD7dcJk3y7dVYyakJdlWHBuk1t4hDjW05BzeVf2f-V0LQ-r6GAY0-Aab1g2V0aMfGhJsZKtCAgmlkgnY0gmlwhCUbP0KJc2VjcDI1NmsxoQMQLfyyzC-YY6A53fEu5a8tP-JWCUM3vkX-c7nRyu28d4RzbmFwwIN0Y3CCequDdWRwgnqr",
"CZ7ESLY5ZH4ULXKQ54XIFDCOUI.all.holesky.ethdisco.net" : "enr:-KO4QOQjO7c9J74CpllRngkrEXHLw-W8VqtJXxkLWPRIXC1CFL4TCjEM4ZfRW6MFlqXERaY3h9mztZXLAo1lf1DAS1qGAY2D0c0_g2V0aMfGhJsZKtCAgmlkgnY0gmlwhC06cBWJc2VjcDI1NmsxoQN8oyz6RCujPq6Hj9N8dBn3EeJ4A69HYeYnyLRiXLZ1UIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"5HSHHSS4QV3FKCNDETO7CEXMZM.all.holesky.ethdisco.net" : "enr:-KO4QAOJNWWAbN0bM51WFaFZimloFw1eBc7Pi3x7uMejmIToDZxBoAVtvdwTg3p6T0Mwmvuot6uT7PG2OjGxkk3P-iGGAY5cIO3Hg2V0aMfGhJsZKtCAgmlkgnY0gmlwhLAJA5uJc2VjcDI1NmsxoQPdRE5vPW9Wj-HRwzubnKAA-1n0p6CAOGLP-E-GzE9EnIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"DAVKEW6RQ5YTYHKCJ2A2J5GVCI.all.holesky.ethdisco.net" : "enrtree-branch:6WAXAZL7FYKEJBZOPWIHCI4F6E,OL6KYVYI7SGS7U34FW3RFBA76A,FKSM7XWAT4KW3TDLRHWSXZPMKQ,5HSHHSS4QV3FKCNDETO7CEXMZM,CZ7ESLY5ZH4ULXKQ54XIFDCOUI,ZRVWX74UFHUWOPCC7LOPLYGIZA,FFM67SMD4N3SK4ZQTY2HOMU4F4,IPSUCB6CICZIW6SERKZL7FFTIM,7XE2DGFKCGOST6BJ46JPNK",
"ELYMU6HPEMGLIYO2UO4YNUI7CQ.all.holesky.ethdisco.net" : "enr:-KO4QOWLzzuDHlwrEZhdOmeHEuFi87mX6iwJ_V820RsBL0mCLngiBaLbhumS1Q8zIc6YPzCYN07nigSMr-OXf19z3WSGAYra1TQYg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKFGJc2VjcDI1NmsxoQO4QASxyNUTDVIRkvEDQejetqJ4roUtGDD6U8CoI9wm-YRzbmFwwIN0Y3CCdnSDdWRwgnZ0",
"VNVQZHCW3CS7ELWR3ANLO7RFBA.all.holesky.ethdisco.net" : "enr:-Ji4QBY7W0c9-rsM9r3yeBngIOe0LFJx8wew3ZatidckbRSzAbXbvc5ahmadpUcrPG2oDm9ziwxw7maQtzEs4J2AnWeBr4NldGjHxoSbGSrQgIJpZIJ2NIJpcISU--s8iXNlY3AyNTZrMaECwwCgmDrePUxVSsOZqgS0USzkXwzkqF0-QK7a59EsnrCDdGNwgnX7g3VkcIJ1-w",
"MFPFKTJREYMESD7STJJOFYDVV4.all.holesky.ethdisco.net" : "enr:-KO4QJfXFSQOpwMtEgz0BSB0gJ0zXQZ6yMzoBfXYCK3ATxulM_mkkQhMWUHsrNyNH9cQYfxRbN_hEGfP3id3IfLiv7KGAY5iEk-hg2V0aMfGhJsZKtCAgmlkgnY0gmlwhGQmekqJc2VjcDI1NmsxoQOoFPqpQmRhcIfVINZ0knq8hxe2tUYnTSLEC-6Xoly7jIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"HGROZTZI7YPDW5F37QVUPQEBG4.all.holesky.ethdisco.net" : "enr:-KO4QI3-xQxY2u-misXaxFtpfezZr0Fk0jiL6U7ZAbwV4yCRcWxgNVOxLifoUOm9uMUqH4wlGxIYL7onmzlavqRIjDGGAYs5av4dg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJRxqGeJc2VjcDI1NmsxoQPc4dhahamqQVxv9D89fNMO9DOP_YaPJRQ3EmT2XantU4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"VJJPHI6PWJ7NFBTW2XJH3JMMNY.all.holesky.ethdisco.net" : "enr:-KO4QHCu9ZPe68fKUXeUzje0Jwv0D8UCrAQ_K5W9KHrIpTdUYWIGwbzyl8heZ1cxijlyUhN1WB0HZpEBThUmrdm-uLiGAYra3Fk3g2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKJOJc2VjcDI1NmsxoQP0AAgBs1kDG4XBe55HY0J4F7GjHiwQVUY-xFKYXOB594RzbmFwwIN0Y3CCdnSDdWRwgnZ0",
"2M2GRZYAFKAVHHU5HTLUHPYHCM.all.holesky.ethdisco.net" : "enr:-KO4QIPWnAyt-tyaS1cnMwEJaFdvDd-MpwEcVv26cfaZ3Ffkc4WCpHqzPmd_SifEsxQf7ontOz9a1EPjbxlsu_V1XZqGAY1UHtm_g2V0aMfGhJsZKtCAgmlkgnY0gmlwhCU85MWJc2VjcDI1NmsxoQNyzc5NiamRt8y5TQ9Qj-EZAYeCb7ZaclF5sOdPrErpbIRzbmFwwIN0Y3CCdl-DdWRwgnZf",
"OOWRWZXNDJVJUCDDOJFOY4YB2Y.all.holesky.ethdisco.net" : "enr:-KO4QBKCkXrhG-hN-IY-O03b5A4JHaweb5xuuSZP4OdJ4uSSZ7E1-yioWl_0WSF8ShOfNU_7wgSCIwBPg0d4RD4w4sOGAY4oBl8og2V0aMfGhJsZKtCAgmlkgnY0gmlwhFJB7YiJc2VjcDI1NmsxoQL-RfOTNeu0SmlCfWAVQaQBUXF0WDEUCyGXv1LWC2_xqoRzbmFwwIN0Y3CCequDdWRwgnqr",
"E4GGBOZ5L2UFPAKJIPLNBA2MKA.all.holesky.ethdisco.net" : "enr:-Ke4QD_Gz-YGWvzpAe-a1l2KHz2pxG_nPUYTcHQDN1Wuvkk7TrEDq-HKIXtA_mbPukz9qLLW5sfkJH5mYda9eDssvkSGAY1Mq2nIg2V0aMvKhMYaYJiEZRbqwIJpZIJ2NIJpcIQf3GvbiXNlY3AyNTZrMaECyosSeovqxsDXTua8c47z7EK--WogcD_FCwDX6tHvVQSEc25hcMCDdGNwgnZfg3VkcIJ2Xw",
"KYTZHQX2PSOGY6RQTCVTUKTS7E.all.holesky.ethdisco.net" : "enr:-KO4QJn2ahKcTeE2karHSHOiJgE9b2BJWo54NS3nzjjCDnsvZ1JjDl8yulvzn8qQA48zCtHkiVMEVNHtdf_LM_N0Cs6GAYxElMbzg2V0aMfGhJsZKtCAgmlkgnY0gmlwhJ3m3GOJc2VjcDI1NmsxoQJzs6KencrR0_ylBVNGuZaknO_zQUYOrq4rjj_FmTlHN4RzbmFwwIN0Y3CCdl-DdWRwgnZf",
"O25DXMPE4UEZ6SFMQRBGL2E2I4.all.holesky.ethdisco.net" : "enr:-KO4QLC4qJt9OIKLkxROeQMNcj4ZuH_QZsVcS1v-NhzBGAf8B-5xF3GYqtMp40n6nwDg8o1yUs7xEx0kgf6wBJF-AuqGAYrbCvwJg2V0aMfGhJsZKtCAgmlkgnY0gmlwhMIhKGuJc2VjcDI1NmsxoQPogWsyNFpt9VYFYrsdUS4dxK2BMeL4FY41ZzgBjeEGRoRzbmFwwIN0Y3CCdmCDdWRwgnZg",
"RWRV55FT3DKDVGZK7AEU2DR77Y.all.holesky.ethdisco.net" : "enrtree-branch:ZV5CYUMJPF4XSTFHOG65622KEE,QDCV4SQTQAGHHA3DRA2TR4LNMY,MZGQKIQKIOFO3W2GJURJUXVYMQ,V5LTO36DCXU2JCCSSJ76E35OFU,NQHD4WNRRGE5JHHX6IDKGIF7KU,ELYMU6HPEMGLIYO2UO4YNUI7CQ,VN7EWW4RMUZM6KUOQ43GJ33DWM,J7ZIDKH7CKVIYY244QVU6RMPDM,QSK67XVHDPEQH7Q54HACQS",
"TMY2W2YBNCXUUNA3Y7QXWVQLRE.all.holesky.ethdisco.net" : "enr:-Ke4QEsOrFCJqnbVXiuSh3DKjvS3RlUoOrrLRlKp2mAqmCuJQBVLFREqABNWRvZfLOxDPEtvcRzDtDW2juSa1vd2xj6GAY025-JNg2V0aMvKhP1PAWuEZcNqwIJpZIJ2NIJpcIRU961viXNlY3AyNTZrMaECoqR94LV1BQMpEDbmfJdd8adEPWHV7qP09nePPVm9nLqEc25hcMCDdGNwgnZfg3VkcIJ2Xw",
"XTJ3PFTPBB3ATDDWAA6W7RRKMY.all.holesky.ethdisco.net" : "enrtree-branch:5AHKPN5NN5IHEH365X6OYZDHDE,AUQGHXRAP7J3AGI6TUOQVYTYLY,IDXHFSATDDENJYOYJC2TUSUYOY,GZVG4EONSAY6M7SMLJXDCFUF5Q,LHFTDS37XFOEXQKTWJGKWRLFWM,HTMBFBAIZBACDG3EZZ4JVANCAY,ZM7CMNKKBVIXY7WGMB7GHYUXMA,VNVQZHCW3CS7ELWR3ANLO7RFBA,PA4IN34FHBJOUK2MS7YRA3",
"V4A7I7I2SFVUDFFH7AGPFXACBA.all.holesky.ethdisco.net" : "enr:-KO4QMIHR0XgkMyX4E9Xh8Fw3rFr-QWyH49lpFmrEhx1Cc_WMxm6atHPm0g-bXmzradBORfb0S9_6dyi-GnQbtlm7GOGAYr8tSZLg2V0aMfGhJsZKtCAgmlkgnY0gmlwhA_MQUKJc2VjcDI1NmsxoQMrgP3au96duBa9PQzAFPhlQ7ikkA96YWAkrItcm5zCxIRzbmFwwIN0Y3CCdl-DdWRwgnZf"
}

View File

@@ -84,7 +84,13 @@ public class AccountLocalConfigPermissioningController implements TransactionPer
private void readAccountsFromConfig(final LocalPermissioningConfiguration configuration) {
if (configuration != null && configuration.isAccountAllowlistEnabled()) {
if (!configuration.getAccountAllowlist().isEmpty()) {
addAccounts(configuration.getAccountAllowlist());
AllowlistOperationResult result = addAccounts(configuration.getAccountAllowlist());
if (result != AllowlistOperationResult.SUCCESS) {
throw new IllegalStateException(
String.format(
"Error reloading permissions file. Invalid accounts allowlist, validation failed due to \"%s\"",
result));
}
}
}
}

View File

@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.permissioning;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -108,6 +109,40 @@ public class AccountLocalConfigPermissioningControllerTest {
.containsExactly("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73");
}
@Test
public void whenLoadingDuplicateAccountsFromConfigShouldThrowError() {
when(permissioningConfig.isAccountAllowlistEnabled()).thenReturn(true);
when(permissioningConfig.getAccountAllowlist())
.thenReturn(
List.of(
"0xcb88953e60948e3a76fa658d65b7c2d5043c6409",
"0xdd76406b124f9e3ae9fbeb47e4d8dc0ab143902d",
"0x432132e8561785c33afe931762cf8eeb9c80e3ad",
"0xcb88953e60948e3a76fa658d65b7c2d5043c6409"));
assertThrows(
IllegalStateException.class,
() -> {
controller =
new AccountLocalConfigPermissioningController(
permissioningConfig, allowlistPersistor, metricsSystem);
});
}
@Test
public void whenLoadingInvalidAccountsFromConfigShouldThrowError() {
when(permissioningConfig.isAccountAllowlistEnabled()).thenReturn(true);
when(permissioningConfig.getAccountAllowlist()).thenReturn(List.of("0x0", "0xzxy"));
assertThrows(
IllegalStateException.class,
() -> {
controller =
new AccountLocalConfigPermissioningController(
permissioningConfig, allowlistPersistor, metricsSystem);
});
}
@Test
public void whenPermConfigContainsEmptyListOfAccountsContainsShouldReturnFalse() {
when(permissioningConfig.isAccountAllowlistEnabled()).thenReturn(true);

View File

@@ -50,8 +50,7 @@ import org.apache.tuweni.units.bigints.UInt64;
* word, a method like {@link #readLongScalar()} does not expect an encoded value of exactly 8 bytes
* (by opposition to {@link #readLong}), but rather one that is "up to" 8 bytes.
*
* @see BytesValueRLPInput for a {@link RLPInput} that decode an RLP encoded value stored in a
* {@link Bytes}.
* @see BytesValueRLPInput
*/
public interface RLPInput {

View File

@@ -1427,6 +1427,9 @@ public class MessageFrame {
private Optional<List<VersionedHash>> versionedHashes = Optional.empty();
/** Instantiates a new Builder. */
public Builder() {}
/**
* The "parent" message frame. When present some fields will be populated from the parent and
* ignored if passed in via builder

View File

@@ -1664,12 +1664,12 @@
<sha256 value="3bda417f3cbe8526948e758d67674634f983349b86b82cabb96fafab9e3ddda2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-all" version="4.1.104.Final">
<artifact name="netty-all-4.1.104.Final.jar">
<sha256 value="11933ecbc6c1de67908afa3ea469a7cd104c50bce4f3a5cd909c2f208c97a044" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-all" version="4.1.110.Final">
<artifact name="netty-all-4.1.110.Final.jar">
<sha256 value="f081b992c828c2fc750c360c34b7fd64572a3466b3601ad8127d2010d4a14f4a" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-all-4.1.104.Final.pom">
<sha256 value="0bd88bfd57d11f3fd4d4469565406ec8ff0f2bc4cfe253f36bf5664e4accf251" origin="Generated by Gradle"/>
<artifact name="netty-all-4.1.110.Final.pom">
<sha256 value="217ce2497d10d5e4d3606314048a1414fa2af9849eb3ba69b70b5355ccdab360" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-bom" version="4.1.104.Final">
@@ -1677,9 +1677,9 @@
<sha256 value="5a65e06a159d20d3b4800624a570c646dbee710b2b539b3449a268558c289e9c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-bom" version="4.1.107.Final">
<artifact name="netty-bom-4.1.107.Final.pom">
<sha256 value="c36997558bfb4e11f200dda6ee2e41a45f2df9e1aef678eda08e79dd8938c210" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-bom" version="4.1.110.Final">
<artifact name="netty-bom-4.1.110.Final.pom">
<sha256 value="a49be1a4ad1f8bf170c1dc1628b1181b51e6d9cf2a25645aa722994095bb9bff" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-bom" version="4.1.86.Final">
@@ -1687,64 +1687,44 @@
<sha256 value="12716c1fe64cf5bdaa7044d37d13aae3a88821b91d4798420c46a74769178afd" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-buffer" version="4.1.104.Final">
<artifact name="netty-buffer-4.1.104.Final.pom">
<sha256 value="9cf38fd1f6c61a8c9a2a6e342f74289d26a1123a216511b2d6813f8aed396e78" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-buffer" version="4.1.110.Final">
<artifact name="netty-buffer-4.1.110.Final.jar">
<sha256 value="46d74e79125aacc055c31f18152fdc5d4a569aa8d60091203d0baa833973ac3c" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-buffer-4.1.110.Final.pom">
<sha256 value="710ac19cc01cd80df6be9a3faad3c222b4a1a32f4b55137be07b6099d5da3562" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-buffer" version="4.1.107.Final">
<artifact name="netty-buffer-4.1.107.Final.jar">
<sha256 value="04eb1231c86a7011c48cd443a25dc2f397137e5ee0aac2f12f1c503f11f09e2a" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec" version="4.1.110.Final">
<artifact name="netty-codec-4.1.110.Final.jar">
<sha256 value="9eccce9a8d827bb8ce84f9c3183fec58bd1c96a51010cf711297746034af3701" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-buffer-4.1.107.Final.pom">
<sha256 value="fcaf25420ba99a6701cf74718677411498fdb1fad4d75734d35fd8ef4a6ee945" origin="Generated by Gradle"/>
<artifact name="netty-codec-4.1.110.Final.pom">
<sha256 value="a806bb536bb323665baff7cd1223f2b272a2d4717ab4f9b12361086daae5df3e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec" version="4.1.104.Final">
<artifact name="netty-codec-4.1.104.Final.pom">
<sha256 value="6c23829e4fcde1aee21283ec9c7ee9238cb09b8fb4e7f3067aaa349b63134041" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-dns" version="4.1.110.Final">
<artifact name="netty-codec-dns-4.1.110.Final.jar">
<sha256 value="5dc73e50004e3ae9fac93cd4bf1c4185e32539b4b08801dc4fa3b5108adcf5f9" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-dns-4.1.110.Final.pom">
<sha256 value="1e1a0ec010b7ec85fe4db152b2370ec0b51030f8519d468b13e006c5c36a699b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec" version="4.1.107.Final">
<artifact name="netty-codec-4.1.107.Final.jar">
<sha256 value="3a1f361b405f9ea30fe6aabe1907d719c0c99fe30c03932fee558214dbd638cc" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-haproxy" version="4.1.110.Final">
<artifact name="netty-codec-haproxy-4.1.110.Final.jar">
<sha256 value="82234e66dc2dc675589270dcb572931d98350d870840839eeb6f329781b4835b" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-4.1.107.Final.pom">
<sha256 value="f6fc4019ce6e5c75d9ced34a6b6dccf23f283b9bb3622e14d9826d62bbeef71c" origin="Generated by Gradle"/>
<artifact name="netty-codec-haproxy-4.1.110.Final.pom">
<sha256 value="068f1f7d1ee4710ee81a6f8235c4fc7c91ca7fe9bfcf059bf8e6bbd20b477f7a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-dns" version="4.1.104.Final">
<artifact name="netty-codec-dns-4.1.104.Final.pom">
<sha256 value="27d51461bf8b9d674ca6b2cea4ec5c2830e3b41bcd2cbf60c6349386f83fcbac" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-http" version="4.1.110.Final">
<artifact name="netty-codec-http-4.1.110.Final.jar">
<sha256 value="dc0d6af5054630a70ff0ef354f20aa7a6e46738c9fc5636ed3d4fe77e38bd48d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-dns" version="4.1.107.Final">
<artifact name="netty-codec-dns-4.1.107.Final.jar">
<sha256 value="6014ce28b4cd32c23bd03b57823c3d682b83dc47c3fdaf4c5cef258b436accda" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-dns-4.1.107.Final.pom">
<sha256 value="f1d2cf9523c8812ed401b9d154b2d29aeb6c30ac7b4fc00a26370ec62bd69ab4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-haproxy" version="4.1.104.Final">
<artifact name="netty-codec-haproxy-4.1.104.Final.jar">
<sha256 value="8eb111359e6baac20553fde0a53366fb202a4d0dda9a24bbe5c2945eb9cecb2c" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-haproxy-4.1.104.Final.pom">
<sha256 value="954f6a83b7e7de6b0b1b62a0ee47f80172025afb3bd811f996c5ffc9078bca68" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http" version="4.1.104.Final">
<artifact name="netty-codec-http-4.1.104.Final.pom">
<sha256 value="a7de23f077b96a2e733a99b067ae9a3e5819197d9a6aa624a54a81402f9cdcd0" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http" version="4.1.107.Final">
<artifact name="netty-codec-http-4.1.107.Final.jar">
<sha256 value="0f35f57ecc11e1227d0c65d65582adc1075474a30a8fd3cff0f6e9a66c9e2a74" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-http-4.1.107.Final.pom">
<sha256 value="af8cad175654ef86695d5134fffa11b3a03fed1f011ca9ce0c6091bd9d4d9a90" origin="Generated by Gradle"/>
<artifact name="netty-codec-http-4.1.110.Final.pom">
<sha256 value="51ae990af14a321db6d3d6884b917b7d4363eb60dddc0f1493b18021a142e7ad" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http2" version="4.1.100.Final">
@@ -1752,104 +1732,84 @@
<sha256 value="e22328e926737886cc5b57840b91a2aed68fde813a1f579f9ab59117a28b99bc" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http2" version="4.1.104.Final">
<artifact name="netty-codec-http2-4.1.104.Final.pom">
<sha256 value="b98644ad4d3a7b14af269cbb84d88f92f5b45ebaac95910009b38601e8a6f4fe" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-http2" version="4.1.110.Final">
<artifact name="netty-codec-http2-4.1.110.Final.jar">
<sha256 value="b546c75445a487bb7bcd5a94779caecce33582cf7be31b8b39fc0e65b1ee26fc" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-http2-4.1.110.Final.pom">
<sha256 value="29d2f6c26c3cca9fe8393671707fe8ef9c3e31020a2dfe06b82c426499c25837" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http2" version="4.1.107.Final">
<artifact name="netty-codec-http2-4.1.107.Final.jar">
<sha256 value="5d83fe14a537ea6ddecc782df256da23ee49754044a4cacc2d8ec5225f338c72" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-memcache" version="4.1.110.Final">
<artifact name="netty-codec-memcache-4.1.110.Final.jar">
<sha256 value="0bd553dbf09a2d0aa53e9ee81cd462852d9b1d5c93ab9b8576c0ba1d4bcf76d9" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-http2-4.1.107.Final.pom">
<sha256 value="4f4a1939f69fd8ea04e0da24c5b77f957be9f21defee16bc4e197a0f8f4e2817" origin="Generated by Gradle"/>
<artifact name="netty-codec-memcache-4.1.110.Final.pom">
<sha256 value="9131e89ab26990901c6ad070a4baa8011d572614ca09eb77071e03da94d13833" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-memcache" version="4.1.104.Final">
<artifact name="netty-codec-memcache-4.1.104.Final.jar">
<sha256 value="1f91f4c0f82fb3eec6d34242b108453dc1b18f74b96eaaabf064a705d45c14a7" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-mqtt" version="4.1.110.Final">
<artifact name="netty-codec-mqtt-4.1.110.Final.jar">
<sha256 value="bfc5c93f9c85f8eb22f253f04ee26214003364d0a44fb7901729ce79c78bd7d6" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-memcache-4.1.104.Final.pom">
<sha256 value="19cafac5e5cb619dbd4f0cc2a80183d5ffdf36d99a5ad8b7f1a59f51280ecd84" origin="Generated by Gradle"/>
<artifact name="netty-codec-mqtt-4.1.110.Final.pom">
<sha256 value="d7cc40a85113b39bca721ae9a525c0e9cb4114b2ed9a231e3f423fa9f0fd4678" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-mqtt" version="4.1.104.Final">
<artifact name="netty-codec-mqtt-4.1.104.Final.jar">
<sha256 value="b19bcc87092bb085341f37c291dca9605b0cf256f54677921a4bcca20e1596f9" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-redis" version="4.1.110.Final">
<artifact name="netty-codec-redis-4.1.110.Final.jar">
<sha256 value="12bc1facf90438d2a3ca940689b6f799ead2ea9d422343a6484ffd94d82218f8" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-mqtt-4.1.104.Final.pom">
<sha256 value="60060ef63a0bbc32c2583c325b886a1612969d604d1fe0e891eee16a3f599473" origin="Generated by Gradle"/>
<artifact name="netty-codec-redis-4.1.110.Final.pom">
<sha256 value="d1786c9b11f659668c62cc5c21c7b95e6b9616332356a16f251482c72cab7ba3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-redis" version="4.1.104.Final">
<artifact name="netty-codec-redis-4.1.104.Final.jar">
<sha256 value="fd8d7f78500375081dcac29b2fcc184ac7c125475b48f05d9659b98524f77738" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-smtp" version="4.1.110.Final">
<artifact name="netty-codec-smtp-4.1.110.Final.jar">
<sha256 value="4e489d43bc9393710f7ea3423ebad3597567257823b4d972db3f602a25af5696" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-redis-4.1.104.Final.pom">
<sha256 value="84a29c1bdf0c671c571941bd81857cb8d910072d0ba83271ce89a5a896560882" origin="Generated by Gradle"/>
<artifact name="netty-codec-smtp-4.1.110.Final.pom">
<sha256 value="1d10df4a6be768636df217044f7f0ed3f42479c96ea5f6c55bd3e16e863a6d49" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-smtp" version="4.1.104.Final">
<artifact name="netty-codec-smtp-4.1.104.Final.jar">
<sha256 value="e519afe6bb461c2004e5e29a5fdd9bfa2fedd73753163b7ed3c266b5c4695dac" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-socks" version="4.1.110.Final">
<artifact name="netty-codec-socks-4.1.110.Final.jar">
<sha256 value="976052a3c9bb280bc6d99f3a29e6404677cf958c3de05b205093d38c006b880c" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-smtp-4.1.104.Final.pom">
<sha256 value="5bda9421e6e4373a126a677f91baecac2299e8f13a5e8e99a8c0cd15e8ae9cc3" origin="Generated by Gradle"/>
<artifact name="netty-codec-socks-4.1.110.Final.pom">
<sha256 value="ffe57b316191dd4f96bee66c5709c13cbdb4ecab085c010c8db0c6aa809abf6c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-socks" version="4.1.104.Final">
<artifact name="netty-codec-socks-4.1.104.Final.pom">
<sha256 value="eb49e26ac18584d0215b8d7cd12428290973beefa9036968a3ff9a300249321e" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-stomp" version="4.1.110.Final">
<artifact name="netty-codec-stomp-4.1.110.Final.jar">
<sha256 value="9dc9d24f69744ab095b1a5f217e0c67211d3bb03bb3eed6b8e49754c89cfa66b" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-stomp-4.1.110.Final.pom">
<sha256 value="b27e1c48e8e9722d2a11a22c4f9cd3f8d1a7ccc40e501b386ec428f6056fb1c3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-socks" version="4.1.107.Final">
<artifact name="netty-codec-socks-4.1.107.Final.jar">
<sha256 value="7974a03d949fcaf1996c83e5d58f76ec993a9a15b386a5c518114738ed209ab8" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-codec-xml" version="4.1.110.Final">
<artifact name="netty-codec-xml-4.1.110.Final.jar">
<sha256 value="b1522dd2ca492b2d7b41ecc1abb125b61734c7d46d1bb82adc97bd8124387489" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-socks-4.1.107.Final.pom">
<sha256 value="eaf47a66cbc791aa2db24d55b683635dff5950b8724703807572c10a8b544264" origin="Generated by Gradle"/>
<artifact name="netty-codec-xml-4.1.110.Final.pom">
<sha256 value="486a27d05d4a306be6f7fd55b63a76df5ca7893bc5b7e6f8023b1ab47806fdf0" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-stomp" version="4.1.104.Final">
<artifact name="netty-codec-stomp-4.1.104.Final.jar">
<sha256 value="93409a2a0900ca98d2b9ed6af14bc1bb2881a9d055571180990e81cb66704dbb" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-common" version="4.1.110.Final">
<artifact name="netty-common-4.1.110.Final.jar">
<sha256 value="9851ec66548b9e0d41164ce98943cdd4bbe305f68ddbd24eae52e4501a0d7b1a" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-stomp-4.1.104.Final.pom">
<sha256 value="d10ac8fb1cad65e1bba8bc91379a7d003ec63b35a1a4c929e7a4eaeae3445a06" origin="Generated by Gradle"/>
<artifact name="netty-common-4.1.110.Final.pom">
<sha256 value="7d417f5335304dae1ea08a06586038c83fe8ad84c1d35baa15ed11921cef7920" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-xml" version="4.1.104.Final">
<artifact name="netty-codec-xml-4.1.104.Final.jar">
<sha256 value="cfdae681ab1728ead026228bb8f32504800154b19afb6c120ba6155f6edeef87" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-handler" version="4.1.110.Final">
<artifact name="netty-handler-4.1.110.Final.jar">
<sha256 value="d5a08d7de364912e4285968de4d4cce3f01da4bb048d5c6937e5f2af1f8e148a" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-xml-4.1.104.Final.pom">
<sha256 value="164943cdef70d11f22c0d1ca070c158b7145e8a7009c23ea17b198ed2d9eb59c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-common" version="4.1.104.Final">
<artifact name="netty-common-4.1.104.Final.pom">
<sha256 value="d13964d6ee347137d4452829deeb47518a7776a05dbb9eadc223539acd4cae85" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-common" version="4.1.107.Final">
<artifact name="netty-common-4.1.107.Final.jar">
<sha256 value="1231e7bd5f523d97280b89adefb3521132d45c22791318b9e0d462bd3ba1b8e9" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-common-4.1.107.Final.pom">
<sha256 value="fa55bbee48c7b3b4e62da28a278ea5c45558719991519b7b9da79a27e1107e4b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler" version="4.1.104.Final">
<artifact name="netty-handler-4.1.104.Final.pom">
<sha256 value="b47da4f0fa8472e39654cb0ae23a3e45675a5bd60ede521dcca1bf9797130776" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler" version="4.1.107.Final">
<artifact name="netty-handler-4.1.107.Final.jar">
<sha256 value="ce135be15a4afe717db7c5a1d5bf1d10bdfdee50c8ce77a5a39e4694b97071db" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-4.1.107.Final.pom">
<sha256 value="c6c59fd6f0f70a043a50a5826de7ad68dbb95d341e03bd1bbe179038e48b845e" origin="Generated by Gradle"/>
<artifact name="netty-handler-4.1.110.Final.pom">
<sha256 value="4d43c13d14f5635a2f8b0d5094d7a31c509ee0f52c724eba0ef30cffe3ea1555" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler-proxy" version="4.1.100.Final">
@@ -1857,25 +1817,20 @@
<sha256 value="bd7324b546a6332294cd49c36958b50476c3f9653f213aaef573f8bff944d53b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler-proxy" version="4.1.104.Final">
<artifact name="netty-handler-proxy-4.1.104.Final.pom">
<sha256 value="7b6a5edf7f94554c89b5745086245f980900205c9736d34e38885a48558216ad" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-handler-proxy" version="4.1.110.Final">
<artifact name="netty-handler-proxy-4.1.110.Final.jar">
<sha256 value="ad54ab4fe9c47ef3e723d71251126db53e8db543871adb9eafc94446539eff52" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-proxy-4.1.110.Final.pom">
<sha256 value="c613cb4e7e06f42efa31db8d8b2a339ed8bf41f00c46d38d0909a4c06c656dcf" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler-proxy" version="4.1.107.Final">
<artifact name="netty-handler-proxy-4.1.107.Final.jar">
<sha256 value="4dc4cddca45536cd2666a56976c3b4e6f54efce856fdb08de566b7a700bbead9" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-handler-ssl-ocsp" version="4.1.110.Final">
<artifact name="netty-handler-ssl-ocsp-4.1.110.Final.jar">
<sha256 value="a20e56b21dfddab1f5dbcd86abeeb16eb6bdee7d288e7e7d5c7461d34c758f56" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-proxy-4.1.107.Final.pom">
<sha256 value="db0c70ecc87f9f9d5c55c26213298ac1eba150f83d94e2f3b452d504c98efe80" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler-ssl-ocsp" version="4.1.104.Final">
<artifact name="netty-handler-ssl-ocsp-4.1.104.Final.jar">
<sha256 value="6ca922d26c8d2831f8ebff413518c709fa3454ede0982938f37dc425c15491a3" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-ssl-ocsp-4.1.104.Final.pom">
<sha256 value="aee924520525966b3481ebfee6ee95c3a206d23f07f69270557a9dd2f73dead6" origin="Generated by Gradle"/>
<artifact name="netty-handler-ssl-ocsp-4.1.110.Final.pom">
<sha256 value="7e36034ec0338e7d33a13a904c806cbe9360c15f51794dbffb5f5c5db728cec9" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-parent" version="4.1.100.Final">
@@ -1883,59 +1838,44 @@
<sha256 value="25787dd1d069fecd10e47360a50cf657bc39bed96eaa7e77400188eef5058741" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-parent" version="4.1.104.Final">
<artifact name="netty-parent-4.1.104.Final.pom">
<sha256 value="b5a9dd807789196916778004e3038b608b913a0c24c4fff16472247f23687008" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-parent" version="4.1.110.Final">
<artifact name="netty-parent-4.1.110.Final.pom">
<sha256 value="685adaf373666fc15427c810f8aff3a4fe194a97c7ed74b69d07c548f0d42f1c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-parent" version="4.1.107.Final">
<artifact name="netty-parent-4.1.107.Final.pom">
<sha256 value="9825c420d8c47c9c921dbc9caa8acafc3075129353fb1b07c8cec1b5b8fb1eb1" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-resolver" version="4.1.110.Final">
<artifact name="netty-resolver-4.1.110.Final.jar">
<sha256 value="a2e9b4ae7caa92fc5bd747e11d1dec20d81b18fc00959554302244ac5c56ce70" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-4.1.110.Final.pom">
<sha256 value="655f34192e8c7618b3c5a79e488e4daa35def41b0d16d45fa36523c3b4c9f641" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver" version="4.1.104.Final">
<artifact name="netty-resolver-4.1.104.Final.pom">
<sha256 value="1841933c88220e6c1b947cddfc34ea9d4815cfde45efc03335c034661f2fa303" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-resolver-dns" version="4.1.110.Final">
<artifact name="netty-resolver-dns-4.1.110.Final.jar">
<sha256 value="38e28b1ecfa2de0fae7357591413a60afc578ac253c4aaefa21670bc049e9516" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-4.1.110.Final.pom">
<sha256 value="63280928af39498914f4b94edcc63d732c6cf5b1cf9a804d7d87e12be184f182" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver" version="4.1.107.Final">
<artifact name="netty-resolver-4.1.107.Final.jar">
<sha256 value="303244791c040229315845e2236bb7b75249cffb308f99d48b0bab199bc6be63" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-resolver-dns-classes-macos" version="4.1.110.Final">
<artifact name="netty-resolver-dns-classes-macos-4.1.110.Final.jar">
<sha256 value="53cb490a8129ebba2c4e3de62e6fe037317aef134e9eb56c72f2af50223d2bdc" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-4.1.107.Final.pom">
<sha256 value="5309429ef003f480a5af7fba7d2d3e55f945bb252f218cbaaac68d0e70d7a885" origin="Generated by Gradle"/>
<artifact name="netty-resolver-dns-classes-macos-4.1.110.Final.pom">
<sha256 value="b8c64328c04b2a78838046c892bc4d93121d9f9a1d60ddc3fbfb61aa5bc02f23" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver-dns" version="4.1.104.Final">
<artifact name="netty-resolver-dns-4.1.104.Final.pom">
<sha256 value="f3297ab3dc55e297a2269d620d25979a44607cb1b6c5b905272143c7c86cc06b" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-resolver-dns-native-macos" version="4.1.110.Final">
<artifact name="netty-resolver-dns-native-macos-4.1.110.Final-osx-aarch_64.jar">
<sha256 value="7a785a2ecae7f37a04ea0071223e54543e4923f928b790190fc05c575e4dcdf6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver-dns" version="4.1.107.Final">
<artifact name="netty-resolver-dns-4.1.107.Final.jar">
<sha256 value="65a87e79b1966140947e6b020a455e823e967e47eec9ec90512c13cb17e98762" origin="Generated by Gradle"/>
<artifact name="netty-resolver-dns-native-macos-4.1.110.Final-osx-x86_64.jar">
<sha256 value="45503b4a97713922ff2380ecd5019e209eb74b1eeed7d7e74f13df2b62724a34" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-4.1.107.Final.pom">
<sha256 value="32d11dcd1800b454e7b4269281eb05189b18a03c74893de668ac6f9392525091" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver-dns-classes-macos" version="4.1.104.Final">
<artifact name="netty-resolver-dns-classes-macos-4.1.104.Final.jar">
<sha256 value="5d45c0fb39d911e2470de5ed6480a23332f454838923ffceb0cf1b4002ecd713" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-classes-macos-4.1.104.Final.pom">
<sha256 value="cc6a0c226b1fce0fc56674bc0c021b6512379025bb0cb0608be6a38e370dcd4f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver-dns-native-macos" version="4.1.104.Final">
<artifact name="netty-resolver-dns-native-macos-4.1.104.Final-osx-aarch_64.jar">
<sha256 value="73d2dba1e02d90817950bbeea9ef2e82c467f67588e4023b7bd5ff765d808c6c" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-native-macos-4.1.104.Final-osx-x86_64.jar">
<sha256 value="e0d7fc632da21828474f4dcf4ffc8ee852b962010808cc8a0270766ae55da18d" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-native-macos-4.1.104.Final.pom">
<sha256 value="6815d1677e86c8a08ff672fe5c94daaf2cc2c69a34555f2a83ec5e168ec9a08a" origin="Generated by Gradle"/>
<artifact name="netty-resolver-dns-native-macos-4.1.110.Final.pom">
<sha256 value="7c23eead91c4d486043268bf4d6e1d792f45f67b91515be0c7ebdf719b54f0bd" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-tcnative-boringssl-static" version="2.0.62.Final">
@@ -1959,96 +1899,91 @@
<sha256 value="c32bc348c40a0e59d68b1edbf2fb9a963ef7b28561bcfd0bae42d6aef6714acf" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport" version="4.1.104.Final">
<artifact name="netty-transport-4.1.104.Final.pom">
<sha256 value="6fc8e60ffffc7ce8d0758e9d7f4fefab39c3cf311bcd24b6e932dd7d8a3bc121" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport" version="4.1.110.Final">
<artifact name="netty-transport-4.1.110.Final.jar">
<sha256 value="a42dd68390ca14b4ff2d40628a096c76485b4adb7c19602d5289321a0669e704" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-4.1.110.Final.pom">
<sha256 value="30f5da0e7646f1840d632f88615c8b9d8205499d68559b9c4547b3b04a0683cd" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport" version="4.1.107.Final">
<artifact name="netty-transport-4.1.107.Final.jar">
<sha256 value="8b3107c684c5fcf53bc437e78db9f186008184210fdb96798efb835c073cfa86" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-classes-epoll" version="4.1.110.Final">
<artifact name="netty-transport-classes-epoll-4.1.110.Final.jar">
<sha256 value="8e59cec67de3b9f8afe4eccec11ed8ce4423948eeaf4ca512bf69324052ed510" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-4.1.107.Final.pom">
<sha256 value="7910d69667fb38b3b4a004715806508edbb905cc8175030ca230ec5b44f6fc0b" origin="Generated by Gradle"/>
<artifact name="netty-transport-classes-epoll-4.1.110.Final.pom">
<sha256 value="e2d417543ef317ffa91938a001fe5ee3cd71c93c014fbd3370374d00f1e70195" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-classes-epoll" version="4.1.104.Final">
<artifact name="netty-transport-classes-epoll-4.1.104.Final.jar">
<sha256 value="5fd94296dfdd7ba1e83e9bb66e265d8eadd6cb93bc96535b7af5aecef8b17440" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-classes-kqueue" version="4.1.110.Final">
<artifact name="netty-transport-classes-kqueue-4.1.110.Final.jar">
<sha256 value="b8eb7fe1ca02c604b8984dc7bc318576043dd79575846aa4bf22e03db953cb02" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-classes-epoll-4.1.104.Final.pom">
<sha256 value="0f1027bad6fda32d3d73a0c5df160aa913e812960ef4f252dc8764cc114a859b" origin="Generated by Gradle"/>
<artifact name="netty-transport-classes-kqueue-4.1.110.Final.pom">
<sha256 value="00c8a4b5b38ff6c604e38d5cdd5a8412ef5723710164a4691ed1e55ec80fb84d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-classes-kqueue" version="4.1.104.Final">
<artifact name="netty-transport-classes-kqueue-4.1.104.Final.jar">
<sha256 value="2bee1139451b51223b2475bb4fe6061ad9618c6ec270e60504d234e0e7388e95" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-native-epoll" version="4.1.110.Final">
<artifact name="netty-transport-native-epoll-4.1.110.Final-linux-aarch_64.jar">
<sha256 value="245ae167f69bbdec3a618ecc11696fd09a0cd51e0dc9164a9dff429f2b07dbae" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-classes-kqueue-4.1.104.Final.pom">
<sha256 value="996ec414b6aae8ab2236fc8ec3d2646c8030b1d3f3fcd4f19bb45d29e14c7597" origin="Generated by Gradle"/>
<artifact name="netty-transport-native-epoll-4.1.110.Final-linux-riscv64.jar">
<sha256 value="fdaa562a3342f05423ef6be133dd5288af61938e7cb93ce3aec10cb4829a7364" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.110.Final-linux-x86_64.jar">
<sha256 value="dcd60c6b3076af307ab877201a136e1f1066c9be809aaed827391a23909f9135" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.110.Final.jar">
<sha256 value="64415f53ca5fa222d40caa72e9fd27f09c04489ddbc0a6ad5179b93e75333102" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.110.Final.pom">
<sha256 value="e00c9c69870b7934f486ca6d097737611fda7108e78f7ea2f0788c7827d11d1f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-native-epoll" version="4.1.104.Final">
<artifact name="netty-transport-native-epoll-4.1.104.Final-linux-aarch_64.jar">
<sha256 value="497c4aec2a9fdedf3482e3da54d383b2ae2dfbf79b4ad28f4cc771f7a00f01bc" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-native-kqueue" version="4.1.110.Final">
<artifact name="netty-transport-native-kqueue-4.1.110.Final-osx-aarch_64.jar">
<sha256 value="18c9f14661bea51841656677e411210844042aad45bf2098fceb241995ed28b2" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.104.Final-linux-riscv64.jar">
<sha256 value="942b4cc8a7aec5e45b1621e993048de72d1edc912fed0684df4084e42e578189" origin="Generated by Gradle"/>
<artifact name="netty-transport-native-kqueue-4.1.110.Final-osx-x86_64.jar">
<sha256 value="a5172f55730ee3b767000cb9bf08a1ec6728fcfc17e8a4a057fe9837370990d0" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.104.Final-linux-x86_64.jar">
<sha256 value="f86d0a1ab8d0c3b6b539d946ad217a13a313769e537f6704696ce0a264c7a449" origin="Generated by Gradle"/>
<artifact name="netty-transport-native-kqueue-4.1.110.Final.jar">
<sha256 value="b6a084ca8ea54659ca2a48d4c2887ea17f23f0fc5cc271d43781b6d2198a6704" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.104.Final.jar">
<sha256 value="28c03e9e7a0b46c067b5fdc84ddf134bf424643b79ff3efc8f552f28e450151d" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-epoll-4.1.104.Final.pom">
<sha256 value="74175b528dc2cb68692153a5f0f523dd7e9df1ebe08c101a7cade0ae81ec9cad" origin="Generated by Gradle"/>
<artifact name="netty-transport-native-kqueue-4.1.110.Final.pom">
<sha256 value="71597766e9c908e50ac172a194ee5bb772a2ce26aede1a30cb99fa51c0b4a987" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-native-kqueue" version="4.1.104.Final">
<artifact name="netty-transport-native-kqueue-4.1.104.Final-osx-aarch_64.jar">
<sha256 value="9725d79ebd3db24b179977a9e59c941082bac82300096ed037a5729c3d72d9df" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-native-unix-common" version="4.1.110.Final">
<artifact name="netty-transport-native-unix-common-4.1.110.Final.jar">
<sha256 value="51717bb7471141950390c6713a449fdb1054d07e60737ee7dda7083796cdee48" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-kqueue-4.1.104.Final-osx-x86_64.jar">
<sha256 value="ad1a57bbbff4bdd1446e08e8b74c0456ef0bfad3a5601c2945ada50e6ca38989" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-kqueue-4.1.104.Final.jar">
<sha256 value="e60df7422caa825b56cc8b0a4de6011d7e3e50c179af031f5149ee05aa00a603" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-kqueue-4.1.104.Final.pom">
<sha256 value="a24c80cb6dad7164483b089d10640927e9519be76a238144158a40dcadd448ce" origin="Generated by Gradle"/>
<artifact name="netty-transport-native-unix-common-4.1.110.Final.pom">
<sha256 value="ea18ce04c9a97ac0c51f4e397b185229fd95997e90b11339adcf7c51946d53d8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-native-unix-common" version="4.1.104.Final">
<artifact name="netty-transport-native-unix-common-4.1.104.Final.jar">
<sha256 value="c12f39c8f12a6ba64078caf75fd97a7fbd05643001f424e8b84829b35d402f4e" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-rxtx" version="4.1.110.Final">
<artifact name="netty-transport-rxtx-4.1.110.Final.jar">
<sha256 value="341a073c82bf22d30c5908824284ec88109935fc753b18d17675bf574a2e0aae" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-native-unix-common-4.1.104.Final.pom">
<sha256 value="14b72f8be075a442f9fee5ceddc2bfb78b6db7c930ef667ed4532cecda70300c" origin="Generated by Gradle"/>
<artifact name="netty-transport-rxtx-4.1.110.Final.pom">
<sha256 value="e3a0569cddfa5d8b8de8412c20da963f2bca8e0d8136330f527dbf13f4f9b9e9" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-rxtx" version="4.1.104.Final">
<artifact name="netty-transport-rxtx-4.1.104.Final.jar">
<sha256 value="be01ae38c1bd36c60c20d35406ff75031d1aa61177727b2553ac259f703df077" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-sctp" version="4.1.110.Final">
<artifact name="netty-transport-sctp-4.1.110.Final.jar">
<sha256 value="44eba45eff93e61e2f1c51f38535b76754a4cd2caecc07f634b58b76225644ba" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-rxtx-4.1.104.Final.pom">
<sha256 value="bb700e221825c822159776675f5beccc566b158ad84a43f93a2142161843706f" origin="Generated by Gradle"/>
<artifact name="netty-transport-sctp-4.1.110.Final.pom">
<sha256 value="f6bde2e662326d7fd5b20f240005d0d3108cf1c1c7119f8411304ac6db874ae3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-sctp" version="4.1.104.Final">
<artifact name="netty-transport-sctp-4.1.104.Final.jar">
<sha256 value="aa33247c732182bb4a970684aeaeba377b64d6cb719b3c296fcd5ae80cb83a2c" origin="Generated by Gradle"/>
<component group="io.netty" name="netty-transport-udt" version="4.1.110.Final">
<artifact name="netty-transport-udt-4.1.110.Final.jar">
<sha256 value="c6d95e9ef5fc71ecf34ce71076ba6662399a8c670b89e8a042a163f76b380823" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-sctp-4.1.104.Final.pom">
<sha256 value="6e47c2b9deb27710e171c1ac456504e7ed57df317c0fca6f66379cc8fb5d9ff2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport-udt" version="4.1.104.Final">
<artifact name="netty-transport-udt-4.1.104.Final.jar">
<sha256 value="67896b06e1a550dff839b88acf9ac73a458cc481fd81a9c5e6ce02c70f303e91" origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-udt-4.1.104.Final.pom">
<sha256 value="0e1e96b91e1c52bf2ea3f4766e80098c34408e1dceb2612297d5da2e7f877200" origin="Generated by Gradle"/>
<artifact name="netty-transport-udt-4.1.110.Final.pom">
<sha256 value="5661e1a03bb18762861af3bebe9dd9881ed3ad5fa46406d03cf2ccb4abbd8896" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.opencensus" name="opencensus-api" version="0.28.0">
@@ -2636,49 +2571,49 @@
<sha256 value="2cd99dcfcc8753ee6cdd2946a60c129ddfa82ef989ba213131322f2b4d7177b5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-auth-common" version="4.5.4">
<artifact name="vertx-auth-common-4.5.4.jar">
<sha256 value="475c91476ca4f6da294ea719d135185fe59694d1ef0e70606467a0c0bb1cb442" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-auth-common" version="4.5.8">
<artifact name="vertx-auth-common-4.5.8.jar">
<sha256 value="ba3eb6a1bf371b2f7f2aaad50541ae725a386f69bf4087b827218c956b1ecedf" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-auth-common-4.5.4.pom">
<sha256 value="637526adc0ac3fd555e9b82c32fc1749ce0368a37945c8ba161b2b527acfd11d" origin="Generated by Gradle"/>
<artifact name="vertx-auth-common-4.5.8.pom">
<sha256 value="5cc9767f64f87b70768ff1359104aa52c1ab2c3d5ae90babc0edcd8b8566af2c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-auth-jwt" version="4.5.4">
<artifact name="vertx-auth-jwt-4.5.4.jar">
<sha256 value="4ab909628a27893c9123ba22c6d61ecf5effedcb1f30014d188f1ff8eefc4ab9" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-auth-jwt" version="4.5.8">
<artifact name="vertx-auth-jwt-4.5.8.jar">
<sha256 value="cf3e09ee2ca86278a1fb05c208db0368d8b993f91c1f8bab03d22ec65f340b62" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-auth-jwt-4.5.4.pom">
<sha256 value="9459002a1746107bb055dd23b25a7231e6c1138999ebfaa12c3bab4d2c3cf66a" origin="Generated by Gradle"/>
<artifact name="vertx-auth-jwt-4.5.8.pom">
<sha256 value="beafcacc0c3e356d926829c6bee5794555d1208a197f265ebf5e16f2a7ad8a85" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-auth-parent" version="4.5.4">
<artifact name="vertx-auth-parent-4.5.4.pom">
<sha256 value="56ea9938fc1487d88ab9c134c89d060f3841c480271a36853902bca5eefb34fc" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-auth-parent" version="4.5.8">
<artifact name="vertx-auth-parent-4.5.8.pom">
<sha256 value="11c33b7bfbd8fb99acaf6a1bf70aa985a160769472052d4e8d7b6b4cf79c0856" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-bridge-common" version="4.5.4">
<artifact name="vertx-bridge-common-4.5.4.jar">
<sha256 value="7cb3a7d529bf911b12b1f3cd7167cdf4459d51626987d56c41b8b7f98bb0ecd9" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-bridge-common" version="4.5.8">
<artifact name="vertx-bridge-common-4.5.8.jar">
<sha256 value="d1aee4bb4dda29c099b4811efc31e674ec5b28282f21fb02298ff1affc22a9b3" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-bridge-common-4.5.4.pom">
<sha256 value="fe4f385202c136a266469feb1e4674c41bd10b22b68d6d1b8434395763fef762" origin="Generated by Gradle"/>
<artifact name="vertx-bridge-common-4.5.8.pom">
<sha256 value="eeb73ecd16d348a9099c88973a7762424122133c568c19939018ef6e8cf2c0f3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-codegen" version="4.5.4">
<artifact name="vertx-codegen-4.5.4.jar">
<sha256 value="f92d47869d1c98631cd9f8f5df39046bbc946c0efce6d618e2b8084988adfd0a" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-codegen" version="4.5.8">
<artifact name="vertx-codegen-4.5.8.jar">
<sha256 value="d88eb1e0c5c36c7d2f6d15bc7e2c9a3db0cf620f84d7fb11bdf24e90829420da" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-codegen-4.5.4.pom">
<sha256 value="9b8af606e7bcbd06314b596ac7e8421dc194a0465a5b84445faa960eb7680258" origin="Generated by Gradle"/>
<artifact name="vertx-codegen-4.5.8.pom">
<sha256 value="ea4f380c2cdc9f6201004e30413f1f143b79521405b230b64f5489ab77327c64" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-core" version="4.5.4">
<artifact name="vertx-core-4.5.4.jar">
<sha256 value="c83984866e02347ae9bf699bf73134cab0081403c65bf9d50e88f826980e8f98" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-core" version="4.5.8">
<artifact name="vertx-core-4.5.8.jar">
<sha256 value="a9b04d77f55e1dece2ca83818ba3c33d7474f027b35725530cdd816680c647a2" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-core-4.5.4.pom">
<sha256 value="d66dfbbe3e9c561cf71206109c8674d67fb43231594d51558be6840e66d84388" origin="Generated by Gradle"/>
<artifact name="vertx-core-4.5.8.pom">
<sha256 value="2a5b6c1ccce595c20c21c5b9bb992a88335ac42335e08b5a8c3380e4e7ec8877" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-dependencies" version="4.3.7">
@@ -2686,9 +2621,9 @@
<sha256 value="353cc4d6761e519c7210b82b5b62bb57b09b8eabae7246234d0586d441a0feaf" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-dependencies" version="4.5.4">
<artifact name="vertx-dependencies-4.5.4.pom">
<sha256 value="41dc25be4f5a0546382558495b25e9adfba9227ed197caf003b1cdcd37b0047d" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-dependencies" version="4.5.8">
<artifact name="vertx-dependencies-4.5.8.pom">
<sha256 value="437f9f66ff07eb02c5e18e3b9162013e46428c205c95a7472e305639a4dc435e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-ext" version="38">
@@ -2701,12 +2636,12 @@
<sha256 value="9ede6271ed5ee6c9987a808ca3cffddb732151f17ab71e5ee79674e74335317c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-junit5" version="4.5.4">
<artifact name="vertx-junit5-4.5.4.jar">
<sha256 value="91644b75a0ecb1639ee9614efeb358f52cbcf32567585877e51c047f1aab0de0" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-junit5" version="4.5.8">
<artifact name="vertx-junit5-4.5.8.jar">
<sha256 value="65152901bd671da4605b280ef5821aee583c7e8d5853f52c954f8fd032e5e555" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-junit5-4.5.4.pom">
<sha256 value="9ebc076ec87681d5cde2af16d7812b5baef341aee1be89353e59d7cbde5b3a6e" origin="Generated by Gradle"/>
<artifact name="vertx-junit5-4.5.8.pom">
<sha256 value="8fecf8c45ed9c28526b1a65ce5c3c575fdb9ebdc58245e41914b5b8275bd83be" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-lang-kotlin" version="4.3.7">
@@ -2735,49 +2670,49 @@
<sha256 value="219614cfbb9c31b6287672d3f615575eaa86c4cc26e402cfc87c8a753c16693e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-unit" version="4.5.4">
<artifact name="vertx-unit-4.5.4.jar">
<sha256 value="aef70280b9b86782824e276b7b0f62de30152f5aea2420eaee3256d158b6cad1" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-unit" version="4.5.8">
<artifact name="vertx-unit-4.5.8.jar">
<sha256 value="f3806bd531ec9e099a79a095074bb39101b8dbff22da0db71f2cab11d248bc65" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-unit-4.5.4.pom">
<sha256 value="f789c3ed3cc8a4d046fd56f4d2aa2c5a2da026ee562c113b80306ed949a04cc4" origin="Generated by Gradle"/>
<artifact name="vertx-unit-4.5.8.pom">
<sha256 value="b1de0bd2593a3139e5d50e3132ff07883d41294a223dd90f2f49c91e21d4c783" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-uri-template" version="4.5.4">
<artifact name="vertx-uri-template-4.5.4.jar">
<sha256 value="57c8a9b0bb962d69b1816bfc30c9c994f646b67853ce701154f5961b0e9c6bbf" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-uri-template" version="4.5.8">
<artifact name="vertx-uri-template-4.5.8.jar">
<sha256 value="47a68ff84623077d12b6007c07d25cfc441a63634b25e9fcc2a145d782f5c5f7" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-uri-template-4.5.4.pom">
<sha256 value="fbd52bf33a2eda9ceb1cfa61fa6f9fbe2f155648ea40d49b5cd3fc780f5dcdd2" origin="Generated by Gradle"/>
<artifact name="vertx-uri-template-4.5.8.pom">
<sha256 value="28d7f24a35c9ea665121af17ba34d97f11c9bdb77f28d3e84d37c19af9b85e16" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-web" version="4.5.4">
<artifact name="vertx-web-4.5.4.jar">
<sha256 value="84a10aa5ba587c7bc1c41c0891325348fa4f6af76b8b6eba57935fbc513bcfb5" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-web" version="4.5.8">
<artifact name="vertx-web-4.5.8.jar">
<sha256 value="17c989751f4abbaa3bdb155b8ea09fba6fd3d01a42da67f2b091f3e05fee7f82" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-web-4.5.4.pom">
<sha256 value="8d125a64e685d89d090ae1953ad739982a80019a454599a76d1dd9b411151023" origin="Generated by Gradle"/>
<artifact name="vertx-web-4.5.8.pom">
<sha256 value="fbd82ab907cda2733d0eb3f7c303d51a7356f08102daa5d20b9d5d3cda420a56" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-web-client" version="4.5.4">
<artifact name="vertx-web-client-4.5.4.jar">
<sha256 value="ff8c1678726a4853080fad3a9ecc1d6384102fd1446cde88cfe40db52b1f6246" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-web-client" version="4.5.8">
<artifact name="vertx-web-client-4.5.8.jar">
<sha256 value="043104002bcaa3c1df6e3a0521f7e9074bf60e0f7aaf083535173fb69d5614e0" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-web-client-4.5.4.pom">
<sha256 value="c0adf677e02a303ca61f7e9efc62d73fdf168eb20ab225dc011c9d7578b1ec6f" origin="Generated by Gradle"/>
<artifact name="vertx-web-client-4.5.8.pom">
<sha256 value="0eb76c17eb3ef611a137803299ed941f3197d4e95be7494cd39abbd122b0469c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-web-common" version="4.5.4">
<artifact name="vertx-web-common-4.5.4.jar">
<sha256 value="d7726abca2c6059dba4fe3b977337b986279d4f7c76ac5556c84a431b8dfba25" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-web-common" version="4.5.8">
<artifact name="vertx-web-common-4.5.8.jar">
<sha256 value="32117ab45f7d2a925edad6e28460c71f592a81a8be3e686a0d169c41bd726426" origin="Generated by Gradle"/>
</artifact>
<artifact name="vertx-web-common-4.5.4.pom">
<sha256 value="86ed3e0bfa2d284aa1077fd45cc041e45edb294d4bdbde5dd483881b2525aa72" origin="Generated by Gradle"/>
<artifact name="vertx-web-common-4.5.8.pom">
<sha256 value="ef9679d90b4518d54cba7b419ef77510351dfbdbb56c9b170121abe5d611a2c5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.vertx" name="vertx-web-parent" version="4.5.4">
<artifact name="vertx-web-parent-4.5.4.pom">
<sha256 value="d9554df76cd741d44a00ac44368e2ce8bc61410ada00f44111da69a193a1697b" origin="Generated by Gradle"/>
<component group="io.vertx" name="vertx-web-parent" version="4.5.8">
<artifact name="vertx-web-parent-4.5.8.pom">
<sha256 value="c938ddab5c7b83dc454242e425d20f6df37bb4b81e1ac8c79e146100ea45d7a4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="jakarta.annotation" name="jakarta.annotation-api" version="2.1.1">
@@ -4724,12 +4659,12 @@
<sha256 value="6d535f94efb663bdb682c9f27a50335394688009642ba7a9677504bc1be4129b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="arithmetic" version="0.8.4">
<artifact name="arithmetic-0.8.4.jar">
<sha256 value="c0b50e68afea3114b04a7443d3d718b9fdedf207dbc7b09702bccb536d6e2956" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="arithmetic" version="0.8.5">
<artifact name="arithmetic-0.8.5.jar">
<sha256 value="e9a63212bd30535dfd67366b768bb307c3b8f58ac29e5b322be3048bbfec9ea2" origin="Generated by Gradle"/>
</artifact>
<artifact name="arithmetic-0.8.4.module">
<sha256 value="dc5d3e8f211aab8170babfe9a00824f6463d7a56c3d2f0fa0dd237431204375d" origin="Generated by Gradle"/>
<artifact name="arithmetic-0.8.5.module">
<sha256 value="813ba38216ddd5e00e29cc3dc9b6a56dc47d936837fe67ee0233729cc2f415a1" origin="Generated by Gradle"/>
</artifact>
<artifact name="arithmetic-0.8.4.pom">
<sha256 value="8183468a6985b3d47ba769509d688b78be8cbdad298dcacc2ec50914f2cbb491" origin="Generated by Gradle"/>
@@ -4743,56 +4678,56 @@
<sha256 value="c273525c9f23a0bd5b9cf6830b4bebd9d81e355b7f2ed3a22f23f76c2a2313d5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="blake2bf" version="0.8.4">
<artifact name="blake2bf-0.8.4.jar">
<sha256 value="7b22ca7c3e86ae77f6f2daec211a0186fd615a46dd602ee4cd28c50f9b62beab" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="blake2bf" version="0.8.5">
<artifact name="blake2bf-0.8.5.jar">
<sha256 value="c755f71c2176870ec0014fcd253fc22f62475409f9cae8ed512511fe687783b4" origin="Generated by Gradle"/>
</artifact>
<artifact name="blake2bf-0.8.4.module">
<sha256 value="2c797fcc4c0cb7898598822a01fbfcb7c7b9159aaf12d6fd4e6f7c93a30d6f5b" origin="Generated by Gradle"/>
<artifact name="blake2bf-0.8.5.module">
<sha256 value="81c14a13dbcdb1773f144adb6b568b6939c157d1697a100ba972810e90f26c6c" origin="Generated by Gradle"/>
</artifact>
<artifact name="blake2bf-0.8.4.pom">
<sha256 value="f273892e777799f375be7aae484ebed6b441f15fb24cd1573bfa5e299c6bf03d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="bls12-381" version="0.8.4">
<artifact name="bls12-381-0.8.4.jar">
<sha256 value="1fe6790671b73918caf31b529e5bafb998125df08cd157a986366a2d6e53f5fe" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="bls12-381" version="0.8.5">
<artifact name="bls12-381-0.8.5.jar">
<sha256 value="1de31f7287207ab9f289b99c4297c2b63611147aff7e3f743474dc045079407a" origin="Generated by Gradle"/>
</artifact>
<artifact name="bls12-381-0.8.4.module">
<sha256 value="dbf1e7184a30d4adc4578ee5df95502e9f6fef6f78c4f561eb5e71d644b6e23e" origin="Generated by Gradle"/>
<artifact name="bls12-381-0.8.5.module">
<sha256 value="8cc12637b2d12930c1ac1bb9c65c4353c3f25262f581c0fa6045e0731a2c7028" origin="Generated by Gradle"/>
</artifact>
<artifact name="bls12-381-0.8.4.pom">
<sha256 value="1c9e9e339bef6ac2f8462375bca44f47b42ea29fc51e34541b89043802ed7144" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="ipa-multipoint" version="0.8.4">
<artifact name="ipa-multipoint-0.8.4.jar">
<sha256 value="c5e44a5f1eed6852a8dd6db1457c935309657c9d425489ae9e20e23e45fbabfc" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="ipa-multipoint" version="0.8.5">
<artifact name="ipa-multipoint-0.8.5.jar">
<sha256 value="454d75e6da12107c77c6540bef21a38d9a6ca8b657befc27f3080259bb0a69f1" origin="Generated by Gradle"/>
</artifact>
<artifact name="ipa-multipoint-0.8.4.module">
<sha256 value="24e5ee51a0d4f71261cfb2f7b1229c1a6a730be5e01dda4de1fcd6dccf38dbb9" origin="Generated by Gradle"/>
<artifact name="ipa-multipoint-0.8.5.module">
<sha256 value="40898ca1a81b1f5ef2574012e5b444c104f230788623e7fcbf531d8d133ef93a" origin="Generated by Gradle"/>
</artifact>
<artifact name="ipa-multipoint-0.8.4.pom">
<sha256 value="16c246e84ede76f91fe96252bd94773164f979baf6592a5e95d60ce3e731ad59" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256k1" version="0.8.4">
<artifact name="secp256k1-0.8.4.jar">
<sha256 value="e594f8f88758832eeea1cb82fc6b671a680f65b9271640791adcec5a31043585" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="secp256k1" version="0.8.5">
<artifact name="secp256k1-0.8.5.jar">
<sha256 value="8f6e1143751937f0f3d172bf88ea7325462aa0ac2038a300702e0e937fab326c" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256k1-0.8.4.module">
<sha256 value="0bd1a3fe6b629656591e7ca855a41f206cbf765b5a27e91698dcaf7c85635f68" origin="Generated by Gradle"/>
<artifact name="secp256k1-0.8.5.module">
<sha256 value="68646f0d4f6a128d603d071141d08cf8adcfbe48ba8938ba201dd29f790738b3" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256k1-0.8.4.pom">
<sha256 value="7abf243b2007fa819439dedea16834be4a063d249bbe182ffaade92826717429" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hyperledger.besu" name="secp256r1" version="0.8.4">
<artifact name="secp256r1-0.8.4.jar">
<sha256 value="2219ed32cb64c0f745ae280db024c5c009401c5f1bab730c18c843fecd989e26" origin="Generated by Gradle"/>
<component group="org.hyperledger.besu" name="secp256r1" version="0.8.5">
<artifact name="secp256r1-0.8.5.jar">
<sha256 value="74abcbb422cf6b9fcfc3cd57b642ae816c9670500e8dfcfd91eabdb14500f2c2" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256r1-0.8.4.module">
<sha256 value="99ff15249a3a360176b99ece8aba58202573f67416398ab07873844291080135" origin="Generated by Gradle"/>
<artifact name="secp256r1-0.8.5.module">
<sha256 value="f98894d37c03f40ce20b74c6ca6b9b2cba4782063ac8428b7bd379f9de73672a" origin="Generated by Gradle"/>
</artifact>
<artifact name="secp256r1-0.8.4.pom">
<sha256 value="fcb5df24cb13d32c4d2b6e4cdc8adde0ee26bfadab1551932b8d3b9fcce0ab6d" origin="Generated by Gradle"/>
@@ -4829,41 +4764,41 @@
<sha256 value="f1c00e59fb8e446f0710bdc1719e61952f27c1614ae478452c2f0011035322ae" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jacoco" name="org.jacoco.agent" version="0.8.8">
<artifact name="org.jacoco.agent-0.8.8.jar">
<sha256 value="072ecbd496896623899a696fff12c01c1615f737616d2792e6d0e10cdf8a610d" origin="Generated by Gradle"/>
<component group="org.jacoco" name="org.jacoco.agent" version="0.8.11">
<artifact name="org.jacoco.agent-0.8.11.jar">
<sha256 value="d3ed85dea78a9ed55846a7738e3a0ca15c702c661ee4bc8cbfe02a8b9f4a99c0" origin="Generated by Gradle"/>
</artifact>
<artifact name="org.jacoco.agent-0.8.8.pom">
<sha256 value="7dd13c80aff315032983357c650a887d6fdb4c8a8870b207bb4802c49809e7b4" origin="Generated by Gradle"/>
<artifact name="org.jacoco.agent-0.8.11.pom">
<sha256 value="16e05e9f49621b87c53e69350140f3c46d42d966c67a933bdf4b063a2b1c8fc5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jacoco" name="org.jacoco.ant" version="0.8.8">
<artifact name="org.jacoco.ant-0.8.8.jar">
<sha256 value="02e33bd2c48dc0be67c2fea84d43beececfd400da6797c58153253d4c30aca15" origin="Generated by Gradle"/>
<component group="org.jacoco" name="org.jacoco.ant" version="0.8.11">
<artifact name="org.jacoco.ant-0.8.11.jar">
<sha256 value="81d7eb8890d9be30a939612c295603541063529cdd03a53265aba74474b70b7c" origin="Generated by Gradle"/>
</artifact>
<artifact name="org.jacoco.ant-0.8.8.pom">
<sha256 value="fafff75819609030f4626509313c0861428c2c26c8d36e9a8938334a04478909" origin="Generated by Gradle"/>
<artifact name="org.jacoco.ant-0.8.11.pom">
<sha256 value="7ed103d959d0cee7babfb1307fa6e451b1696ffd3527061553b550de55201d85" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jacoco" name="org.jacoco.build" version="0.8.8">
<artifact name="org.jacoco.build-0.8.8.pom">
<sha256 value="f4ce0b1285fd24fc6c772f42857298315904dde8fd5677267a0fad5ff9ce2aef" origin="Generated by Gradle"/>
<component group="org.jacoco" name="org.jacoco.build" version="0.8.11">
<artifact name="org.jacoco.build-0.8.11.pom">
<sha256 value="5b84b15cf2eef3e59eb91bc22784833100b09df9911e3319030c3bc648bd8b0b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jacoco" name="org.jacoco.core" version="0.8.8">
<artifact name="org.jacoco.core-0.8.8.jar">
<sha256 value="474c782f809d88924713dfdbf0acb79d330f904be576484803463d0465611643" origin="Generated by Gradle"/>
<component group="org.jacoco" name="org.jacoco.core" version="0.8.11">
<artifact name="org.jacoco.core-0.8.11.jar">
<sha256 value="fcd188c688473fc8dcc0c6caaf355e7b389502243527c33b9597a3ec28791f47" origin="Generated by Gradle"/>
</artifact>
<artifact name="org.jacoco.core-0.8.8.pom">
<sha256 value="f5fab5a48df823b83c0ea35026032368cc9b81800efb257cc7a5928298fee225" origin="Generated by Gradle"/>
<artifact name="org.jacoco.core-0.8.11.pom">
<sha256 value="bb6135f10a36349cb84a5600fd8cf73fc1296a135b2f14adcd83de8cf24cabb1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jacoco" name="org.jacoco.report" version="0.8.8">
<artifact name="org.jacoco.report-0.8.8.jar">
<sha256 value="2c129110f3e3fcaa1f8179578ea3894586199cb0826be5c7790278084c9622a9" origin="Generated by Gradle"/>
<component group="org.jacoco" name="org.jacoco.report" version="0.8.11">
<artifact name="org.jacoco.report-0.8.11.jar">
<sha256 value="8393295ae24680ed10cad8333907040f928b871332491581ca5bc784e2cb4fbe" origin="Generated by Gradle"/>
</artifact>
<artifact name="org.jacoco.report-0.8.8.pom">
<sha256 value="5213af2916bb2690be871917d82a0f9c2ba1e88b796a59343fc03df8ae138716" origin="Generated by Gradle"/>
<artifact name="org.jacoco.report-0.8.11.pom">
<sha256 value="8e3b734779d5e3fd683ec015413d52f961984c50cb9045fda2b23bff5eb42381" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.java-websocket" name="Java-WebSocket" version="1.5.3">
@@ -5720,6 +5655,14 @@
<sha256 value="02824e839f2a2f0e72959fdd30b4897240f05afc43de42d7ba0b18437601c070" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2.asm" name="asm-commons" version="9.6">
<artifact name="asm-commons-9.6.jar">
<sha256 value="7aefd0d5c0901701c69f7513feda765fb6be33af2ce7aa17c5781fc87657c511" origin="Generated by Gradle"/>
</artifact>
<artifact name="asm-commons-9.6.pom">
<sha256 value="a98ae4895334baf8ff86bd66516210dbd9a03f1a6e15e47dda82afcf6b53d77c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2.asm" name="asm-tree" version="9.2">
<artifact name="asm-tree-9.2.jar">
<sha256 value="aabf9bd23091a4ebfc109c1f3ee7cf3e4b89f6ba2d3f51c5243f16b3cffae011" origin="Generated by Gradle"/>
@@ -5728,6 +5671,14 @@
<sha256 value="f61f3ebea5520ddf19f452b03c426c7231bdd8a81d7ac28765cb5271225ac378" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2.asm" name="asm-tree" version="9.6">
<artifact name="asm-tree-9.6.jar">
<sha256 value="c43ecf17b539c777e15da7b5b86553b377e2d39a683de6285567d5283888e7ef" origin="Generated by Gradle"/>
</artifact>
<artifact name="asm-tree-9.6.pom">
<sha256 value="1bcb481d7fc16b955bb60ca07c8cfa2424bcee78bdc405bba31c7d6f5dc2d113" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2.asm" name="asm-util" version="9.2">
<artifact name="asm-util-9.2.jar">
<sha256 value="ff5b3cd331ae8a9a804768280da98f50f424fef23dd3c788bb320e08c94ee598" origin="Generated by Gradle"/>

View File

@@ -69,11 +69,11 @@ dependencyManagement {
dependency 'io.kubernetes:client-java:18.0.1'
dependency 'io.netty:netty-all:4.1.104.Final'
dependency 'io.netty:netty-all:4.1.110.Final'
dependency 'io.netty:netty-tcnative-boringssl-static:2.0.62.Final'
dependency group: 'io.netty', name: 'netty-transport-native-epoll', version:'4.1.104.Final', classifier: 'linux-x86_64'
dependency group: 'io.netty', name: 'netty-transport-native-kqueue', version:'4.1.104.Final', classifier: 'osx-x86_64'
dependency 'io.netty:netty-transport-native-unix-common:4.1.104.Final'
dependency group: 'io.netty', name: 'netty-transport-native-epoll', version:'4.1.110.Final', classifier: 'linux-x86_64'
dependency group: 'io.netty', name: 'netty-transport-native-kqueue', version:'4.1.110.Final', classifier: 'osx-x86_64'
dependency 'io.netty:netty-transport-native-unix-common:4.1.110.Final'
dependency 'io.opentelemetry:opentelemetry-api:1.33.0'
dependency 'io.opentelemetry:opentelemetry-exporter-otlp:1.33.0'
@@ -108,7 +108,6 @@ dependencyManagement {
entry 'tuweni-concurrent'
entry 'tuweni-crypto'
entry 'tuweni-devp2p'
entry 'tuweni-dns-discovery'
entry 'tuweni-io'
entry 'tuweni-net'
entry 'tuweni-rlp'
@@ -116,7 +115,7 @@ dependencyManagement {
entry 'tuweni-units'
}
dependencySet(group: 'io.vertx', version: '4.5.4') {
dependencySet(group: 'io.vertx', version: '4.5.8') {
entry 'vertx-auth-jwt'
entry 'vertx-codegen'
entry 'vertx-core'
@@ -156,7 +155,7 @@ dependencyManagement {
dependency 'org.openjdk.jol:jol-core:0.17'
dependency 'tech.pegasys:jc-kzg-4844:1.0.0'
dependencySet(group: 'org.hyperledger.besu', version: '0.8.4') {
dependencySet(group: 'org.hyperledger.besu', version: '0.8.5') {
entry 'arithmetic'
entry 'ipa-multipoint'
entry 'bls12-381'

View File

@@ -32,6 +32,9 @@ public class InMemoryTaskQueue<T> implements TaskCollection<T> {
private final Set<InMemoryTask<T>> unfinishedOutstandingTasks = new HashSet<>();
private final AtomicBoolean closed = new AtomicBoolean(false);
/** Default constructor. */
public InMemoryTaskQueue() {}
@Override
public synchronized void add(final T taskData) {
assertNotClosed();

View File

@@ -18,6 +18,7 @@ package org.hyperledger.besu.util;
public class EndianUtils {
// next two methods adopted from:
// https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/util/Pack.java
private EndianUtils() {}
/**
* Long to big endian.

View File

@@ -25,6 +25,8 @@ import java.util.function.Supplier;
/** The Future utils. */
public class FutureUtils {
private FutureUtils() {}
/**
* Returns a new CompletionStage that, when the provided stage completes exceptionally, is
* executed with the provided stage's exception as the argument to the supplied function.

View File

@@ -28,6 +28,8 @@ public class LogUtil {
static final String BESU_NAMESPACE = "org.hyperledger.besu";
static final int MAX_SUMMARY_DEPTH = 20;
private LogUtil() {}
/**
* Throttles logging to a given logger.
*

View File

@@ -43,6 +43,8 @@ public class PlatformDetector {
private static String _glibc;
private static String _jemalloc;
private PlatformDetector() {}
/**
* Gets OS type.
*