mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
Add ephemery network config (#7563)
* Add Ephemery genesis config file Signed-off-by: gconnect <agatevureglory@gmail.com> --------- Signed-off-by: gconnect <agatevureglory@gmail.com> Signed-off-by: Glory Agatevure <agatevureglory@gmail.com> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect)
|
||||
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
|
||||
|
||||
### Upcoming Breaking Changes
|
||||
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release
|
||||
@@ -4461,7 +4463,6 @@ Specify `*` or `all` for `--host-whitelist` to effectively disable host protecti
|
||||
- Send client quitting disconnect message to peers on shutdown (PR [#253](https://github.com/PegaSysEng/pantheon/pull/253))
|
||||
- Improved error message for port conflict error (PR [#232](https://github.com/PegaSysEng/pantheon/pull/232))
|
||||
|
||||
|
||||
### Technical Improvements
|
||||
- Upgraded Ethereum reference tests to 6.0 beta 2. (thanks to [@jvirtanen](https://github.com/jvirtanen) for the initial upgrade to beta 1)
|
||||
- Set Java compiler default encoding to UTF-8 (PR [#238](https://github.com/PegaSysEng/pantheon/pull/238) thanks to [@matt9ucci](https://github.com/matt9ucci))
|
||||
|
||||
@@ -20,6 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.hyperledger.besu.cli.DefaultCommandValues.getDefaultBesuDataPath;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.MAINNET;
|
||||
import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG;
|
||||
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
|
||||
@@ -195,6 +196,7 @@ import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl;
|
||||
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
|
||||
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
|
||||
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
|
||||
import org.hyperledger.besu.util.EphemeryGenesisUpdater;
|
||||
import org.hyperledger.besu.util.InvalidConfigurationException;
|
||||
import org.hyperledger.besu.util.LogConfigurator;
|
||||
import org.hyperledger.besu.util.NetworkUtility;
|
||||
@@ -1602,11 +1604,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
}
|
||||
|
||||
private GenesisConfigFile readGenesisConfigFile() {
|
||||
final GenesisConfigFile effectiveGenesisFile =
|
||||
genesisFile != null
|
||||
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
|
||||
: GenesisConfigFile.fromResource(
|
||||
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
|
||||
GenesisConfigFile effectiveGenesisFile;
|
||||
effectiveGenesisFile =
|
||||
network.equals(EPHEMERY)
|
||||
? EphemeryGenesisUpdater.updateGenesis(genesisConfigOverrides)
|
||||
: genesisFile != null
|
||||
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
|
||||
: GenesisConfigFile.fromResource(
|
||||
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
|
||||
return effectiveGenesisFile.withOverrides(genesisConfigOverrides);
|
||||
}
|
||||
|
||||
@@ -2333,7 +2338,11 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
if (networkId != null) {
|
||||
builder.setNetworkId(networkId);
|
||||
}
|
||||
|
||||
// ChainId update is required for Ephemery network
|
||||
if (network.equals(EPHEMERY)) {
|
||||
String chainId = genesisConfigOverrides.get("chainId");
|
||||
builder.setNetworkId(new BigInteger(chainId));
|
||||
}
|
||||
if (p2PDiscoveryOptions.discoveryDnsUrl != null) {
|
||||
builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl);
|
||||
} else {
|
||||
|
||||
@@ -77,6 +77,7 @@ public record EthNetworkConfig(
|
||||
strings ->
|
||||
strings.stream().map(EnodeURLImpl::fromString).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
return new EthNetworkConfig(
|
||||
genesisConfigFile,
|
||||
networkName.getNetworkId(),
|
||||
|
||||
@@ -31,6 +31,12 @@ public enum NetworkName {
|
||||
/** LUKSO mainnet network name. */
|
||||
LUKSO("/lukso.json", BigInteger.valueOf(42)),
|
||||
|
||||
/**
|
||||
* EPHEMERY network name. The actual networkId used is calculated based on this default value and
|
||||
* the current time. https://ephemery.dev/
|
||||
*/
|
||||
EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135)),
|
||||
|
||||
/** Dev network name. */
|
||||
DEV("/dev.json", BigInteger.valueOf(2018), false),
|
||||
/** Future EIPs network name. */
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
|
||||
|
||||
import org.hyperledger.besu.config.GenesisConfigFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The Generate Ephemery Genesis Updater. Checks for update based on the set period and update the
|
||||
* Ephemery genesis in memory
|
||||
*/
|
||||
public class EphemeryGenesisUpdater {
|
||||
private static final int PERIOD_IN_DAYS = 28;
|
||||
private static final long PERIOD_IN_SECONDS = (PERIOD_IN_DAYS * 24 * 60 * 60);
|
||||
|
||||
/**
|
||||
* Constructor for EphemeryGenesisUpdater. Initializes the genesis updater for the Ephemery
|
||||
* network.
|
||||
*/
|
||||
public EphemeryGenesisUpdater() {}
|
||||
|
||||
/**
|
||||
* Updates the Ephemery genesis configuration based on the predefined period.
|
||||
*
|
||||
* @param overrides a map of configuration overrides
|
||||
* @return the updated GenesisConfigFile
|
||||
* @throws RuntimeException if an error occurs during the update process
|
||||
*/
|
||||
public static GenesisConfigFile updateGenesis(final Map<String, String> overrides)
|
||||
throws RuntimeException {
|
||||
GenesisConfigFile genesisConfigFile;
|
||||
try {
|
||||
if (EPHEMERY.getGenesisFile() == null) {
|
||||
throw new IOException("Genesis file or config options are null");
|
||||
}
|
||||
genesisConfigFile = GenesisConfigFile.fromResource(EPHEMERY.getGenesisFile());
|
||||
long genesisTimestamp = genesisConfigFile.getTimestamp();
|
||||
Optional<BigInteger> genesisChainId = genesisConfigFile.getConfigOptions().getChainId();
|
||||
long currentTimestamp = Instant.now().getEpochSecond();
|
||||
long periodsSinceGenesis =
|
||||
ChronoUnit.DAYS.between(Instant.ofEpochSecond(genesisTimestamp), Instant.now())
|
||||
/ PERIOD_IN_DAYS;
|
||||
|
||||
long updatedTimestamp = genesisTimestamp + (periodsSinceGenesis * PERIOD_IN_SECONDS);
|
||||
BigInteger updatedChainId =
|
||||
genesisChainId
|
||||
.orElseThrow(() -> new IllegalStateException("ChainId not present"))
|
||||
.add(BigInteger.valueOf(periodsSinceGenesis));
|
||||
// has a period elapsed since original ephemery genesis time? if so, override chainId and
|
||||
// timestamp
|
||||
if (currentTimestamp > (genesisTimestamp + PERIOD_IN_SECONDS)) {
|
||||
overrides.put("chainId", String.valueOf(updatedChainId));
|
||||
overrides.put("timestamp", String.valueOf(updatedTimestamp));
|
||||
genesisConfigFile = genesisConfigFile.withOverrides(overrides);
|
||||
}
|
||||
return genesisConfigFile.withOverrides(overrides);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error updating ephemery genesis: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.DEV;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.EXPERIMENTAL_EIPS;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS;
|
||||
import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY;
|
||||
@@ -43,6 +44,7 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.hyperledger.besu.BesuInfo;
|
||||
import org.hyperledger.besu.cli.config.EthNetworkConfig;
|
||||
import org.hyperledger.besu.cli.config.NetworkName;
|
||||
import org.hyperledger.besu.config.GenesisConfigFile;
|
||||
import org.hyperledger.besu.config.MergeConfiguration;
|
||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
||||
@@ -1863,6 +1865,20 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ephemeryValuesAreUsed() {
|
||||
parseCommand("--network", "ephemery");
|
||||
|
||||
final ArgumentCaptor<EthNetworkConfig> networkArg =
|
||||
ArgumentCaptor.forClass(EthNetworkConfig.class);
|
||||
|
||||
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
|
||||
verify(mockControllerBuilder).build();
|
||||
assertThat(NetworkName.valueOf(String.valueOf(EPHEMERY))).isEqualTo(EPHEMERY);
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classicValuesAreUsed() {
|
||||
parseCommand("--network", "classic");
|
||||
|
||||
@@ -39,9 +39,7 @@ class NetworkDeprecationMessageTest {
|
||||
@ParameterizedTest
|
||||
@EnumSource(
|
||||
value = NetworkName.class,
|
||||
names = {
|
||||
"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO",
|
||||
})
|
||||
names = {"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO", "EPHEMERY"})
|
||||
void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) {
|
||||
assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network))
|
||||
.isInstanceOf(AssertionError.class);
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.hyperledger.besu.config.GenesisConfigFile.fromConfig;
|
||||
|
||||
import org.hyperledger.besu.config.GenesisConfigFile;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class EphemeryGenesisUpdaterTest {
|
||||
private static final int GENESIS_CONFIG_TEST_CHAINID = 39438135;
|
||||
private static final long GENESIS_TEST_TIMESTAMP = 1720119600;
|
||||
private static final long EARLIER_TIMESTAMP = 1712041200;
|
||||
private static final long LATER_TIMESTAMP = 1922041200;
|
||||
private static final long PERIOD_IN_SECONDS = 28 * 24 * 60 * 60;
|
||||
private static final long PERIOD_SINCE_GENESIS = 3;
|
||||
|
||||
private static final JsonObject VALID_GENESIS_JSON =
|
||||
(new JsonObject())
|
||||
.put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID))
|
||||
.put("timestamp", GENESIS_TEST_TIMESTAMP);
|
||||
|
||||
private static final GenesisConfigFile INVALID_GENESIS_JSON = fromConfig("{}");
|
||||
private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_CHAINID =
|
||||
(new JsonObject()).put("timestamp", GENESIS_TEST_TIMESTAMP);
|
||||
|
||||
private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP =
|
||||
new JsonObject()
|
||||
.put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID));
|
||||
|
||||
@Test
|
||||
public void testEphemeryWhenChainIdIsAbsent() {
|
||||
final GenesisConfigFile config =
|
||||
GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_CHAINID.toString());
|
||||
Optional<BigInteger> chainId = config.getConfigOptions().getChainId();
|
||||
assertThat(chainId).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldDefaultTimestampToZero() {
|
||||
final GenesisConfigFile config =
|
||||
GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP.toString());
|
||||
assertThat(config.getTimestamp()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEphemeryWhenGenesisJsonIsInvalid() {
|
||||
assertThatThrownBy(INVALID_GENESIS_JSON::getDifficulty)
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("Invalid genesis block configuration");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEphemeryWhenGenesisJsonIsValid() {
|
||||
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
|
||||
assertThat(String.valueOf(config.getTimestamp()))
|
||||
.isEqualTo(String.valueOf(GENESIS_TEST_TIMESTAMP));
|
||||
assertThat(config.getConfigOptions().getChainId())
|
||||
.hasValue(BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID));
|
||||
assertThat(String.valueOf(config.getTimestamp())).isNotNull();
|
||||
assertThat(String.valueOf(config.getTimestamp())).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEphemeryNotYetDueForUpdate() {
|
||||
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
|
||||
assertThat(EARLIER_TIMESTAMP).isLessThan(config.getTimestamp() + PERIOD_IN_SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverrideWithUpdatedChainIdAndTimeStamp() {
|
||||
BigInteger expectedChainId =
|
||||
BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID)
|
||||
.add(BigInteger.valueOf(PERIOD_SINCE_GENESIS));
|
||||
|
||||
long expectedGenesisTimestamp =
|
||||
GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS);
|
||||
|
||||
final GenesisConfigFile config = GenesisConfigFile.fromResource("/ephemery.json");
|
||||
|
||||
final Map<String, String> override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
override.put("chainId", String.valueOf(expectedChainId));
|
||||
override.put("timestamp", String.valueOf(expectedGenesisTimestamp));
|
||||
|
||||
assertThat(config.withOverrides(override).getConfigOptions().getChainId()).isPresent();
|
||||
assertThat(config.withOverrides(override).getConfigOptions().getChainId())
|
||||
.hasValue(expectedChainId);
|
||||
assertThat(config.withOverrides(override).getTimestamp()).isNotNull();
|
||||
assertThat(expectedChainId).isEqualTo(override.get("chainId"));
|
||||
assertThat(String.valueOf(expectedGenesisTimestamp)).isEqualTo(override.get("timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEphemeryWhenSuccessful() {
|
||||
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
|
||||
|
||||
BigInteger expectedChainId =
|
||||
BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID)
|
||||
.add(BigInteger.valueOf(PERIOD_SINCE_GENESIS));
|
||||
|
||||
long expectedGenesisTimestamp =
|
||||
GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS);
|
||||
final Map<String, String> override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
override.put("chainId", String.valueOf(expectedChainId));
|
||||
override.put("timestamp", String.valueOf(expectedGenesisTimestamp));
|
||||
final GenesisConfigFile updatedConfig = config.withOverrides(override);
|
||||
|
||||
assertThat(LATER_TIMESTAMP)
|
||||
.isGreaterThan(Long.parseLong(String.valueOf(GENESIS_TEST_TIMESTAMP + PERIOD_IN_SECONDS)));
|
||||
assertThat(updatedConfig.getConfigOptions().getChainId()).hasValue(expectedChainId);
|
||||
assertThat(updatedConfig.getTimestamp()).isEqualTo(expectedGenesisTimestamp);
|
||||
assertThat(override.get("timestamp")).isEqualTo(String.valueOf(expectedGenesisTimestamp));
|
||||
assertThat(override.get("chainId")).isEqualTo(expectedChainId.toString());
|
||||
}
|
||||
}
|
||||
@@ -280,6 +280,9 @@ public class GenesisConfigFile {
|
||||
* @return the timestamp
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
if (overrides != null && overrides.containsKey("timestamp")) {
|
||||
return Long.parseLong(overrides.get("timestamp"));
|
||||
}
|
||||
return parseLong("timestamp", JsonUtil.getValueAsString(genesisRoot, "timestamp", "0x0"));
|
||||
}
|
||||
|
||||
|
||||
916
config/src/main/resources/ephemery.json
Normal file
916
config/src/main/resources/ephemery.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user