Skip to content

Commit 67d738c

Browse files
gconnectmacfarla
andauthored
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>
1 parent 911f12e commit 67d738c

File tree

10 files changed

+1180
-10
lines changed

10 files changed

+1180
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## [Unreleased]
4+
- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect)
5+
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
46

57
### Upcoming Breaking Changes
68
- 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
44614463
- Send client quitting disconnect message to peers on shutdown (PR [#253](https://github.com/PegaSysEng/pantheon/pull/253))
44624464
- Improved error message for port conflict error (PR [#232](https://github.com/PegaSysEng/pantheon/pull/232))
44634465

4464-
44654466
### Technical Improvements
44664467
- Upgraded Ethereum reference tests to 6.0 beta 2. (thanks to [@jvirtanen](https://github.com/jvirtanen) for the initial upgrade to beta 1)
44674468
- Set Java compiler default encoding to UTF-8 (PR [#238](https://github.com/PegaSysEng/pantheon/pull/238) thanks to [@matt9ucci](https://github.com/matt9ucci))

besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static java.util.Arrays.asList;
2121
import static java.util.Collections.singletonList;
2222
import static org.hyperledger.besu.cli.DefaultCommandValues.getDefaultBesuDataPath;
23+
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
2324
import static org.hyperledger.besu.cli.config.NetworkName.MAINNET;
2425
import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG;
2526
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
@@ -195,6 +196,7 @@
195196
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
196197
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
197198
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
199+
import org.hyperledger.besu.util.EphemeryGenesisUpdater;
198200
import org.hyperledger.besu.util.InvalidConfigurationException;
199201
import org.hyperledger.besu.util.LogConfigurator;
200202
import org.hyperledger.besu.util.NetworkUtility;
@@ -1602,11 +1604,14 @@ private void validateChainDataPruningParams() {
16021604
}
16031605

16041606
private GenesisConfigFile readGenesisConfigFile() {
1605-
final GenesisConfigFile effectiveGenesisFile =
1606-
genesisFile != null
1607-
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
1608-
: GenesisConfigFile.fromResource(
1609-
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
1607+
GenesisConfigFile effectiveGenesisFile;
1608+
effectiveGenesisFile =
1609+
network.equals(EPHEMERY)
1610+
? EphemeryGenesisUpdater.updateGenesis(genesisConfigOverrides)
1611+
: genesisFile != null
1612+
? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile))
1613+
: GenesisConfigFile.fromResource(
1614+
Optional.ofNullable(network).orElse(MAINNET).getGenesisFile());
16101615
return effectiveGenesisFile.withOverrides(genesisConfigOverrides);
16111616
}
16121617

@@ -2333,7 +2338,11 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) {
23332338
if (networkId != null) {
23342339
builder.setNetworkId(networkId);
23352340
}
2336-
2341+
// ChainId update is required for Ephemery network
2342+
if (network.equals(EPHEMERY)) {
2343+
String chainId = genesisConfigOverrides.get("chainId");
2344+
builder.setNetworkId(new BigInteger(chainId));
2345+
}
23372346
if (p2PDiscoveryOptions.discoveryDnsUrl != null) {
23382347
builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl);
23392348
} else {

besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public static EthNetworkConfig getNetworkConfig(final NetworkName networkName) {
7777
strings ->
7878
strings.stream().map(EnodeURLImpl::fromString).collect(Collectors.toList()))
7979
.orElse(Collections.emptyList());
80+
8081
return new EthNetworkConfig(
8182
genesisConfigFile,
8283
networkName.getNetworkId(),

besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ public enum NetworkName {
3131
/** LUKSO mainnet network name. */
3232
LUKSO("/lukso.json", BigInteger.valueOf(42)),
3333

34+
/**
35+
* EPHEMERY network name. The actual networkId used is calculated based on this default value and
36+
* the current time. https://ephemery.dev/
37+
*/
38+
EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135)),
39+
3440
/** Dev network name. */
3541
DEV("/dev.json", BigInteger.valueOf(2018), false),
3642
/** Future EIPs network name. */
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.util;
16+
17+
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
18+
19+
import org.hyperledger.besu.config.GenesisConfigFile;
20+
21+
import java.io.IOException;
22+
import java.math.BigInteger;
23+
import java.time.Instant;
24+
import java.time.temporal.ChronoUnit;
25+
import java.util.Map;
26+
import java.util.Optional;
27+
28+
/**
29+
* The Generate Ephemery Genesis Updater. Checks for update based on the set period and update the
30+
* Ephemery genesis in memory
31+
*/
32+
public class EphemeryGenesisUpdater {
33+
private static final int PERIOD_IN_DAYS = 28;
34+
private static final long PERIOD_IN_SECONDS = (PERIOD_IN_DAYS * 24 * 60 * 60);
35+
36+
/**
37+
* Constructor for EphemeryGenesisUpdater. Initializes the genesis updater for the Ephemery
38+
* network.
39+
*/
40+
public EphemeryGenesisUpdater() {}
41+
42+
/**
43+
* Updates the Ephemery genesis configuration based on the predefined period.
44+
*
45+
* @param overrides a map of configuration overrides
46+
* @return the updated GenesisConfigFile
47+
* @throws RuntimeException if an error occurs during the update process
48+
*/
49+
public static GenesisConfigFile updateGenesis(final Map<String, String> overrides)
50+
throws RuntimeException {
51+
GenesisConfigFile genesisConfigFile;
52+
try {
53+
if (EPHEMERY.getGenesisFile() == null) {
54+
throw new IOException("Genesis file or config options are null");
55+
}
56+
genesisConfigFile = GenesisConfigFile.fromResource(EPHEMERY.getGenesisFile());
57+
long genesisTimestamp = genesisConfigFile.getTimestamp();
58+
Optional<BigInteger> genesisChainId = genesisConfigFile.getConfigOptions().getChainId();
59+
long currentTimestamp = Instant.now().getEpochSecond();
60+
long periodsSinceGenesis =
61+
ChronoUnit.DAYS.between(Instant.ofEpochSecond(genesisTimestamp), Instant.now())
62+
/ PERIOD_IN_DAYS;
63+
64+
long updatedTimestamp = genesisTimestamp + (periodsSinceGenesis * PERIOD_IN_SECONDS);
65+
BigInteger updatedChainId =
66+
genesisChainId
67+
.orElseThrow(() -> new IllegalStateException("ChainId not present"))
68+
.add(BigInteger.valueOf(periodsSinceGenesis));
69+
// has a period elapsed since original ephemery genesis time? if so, override chainId and
70+
// timestamp
71+
if (currentTimestamp > (genesisTimestamp + PERIOD_IN_SECONDS)) {
72+
overrides.put("chainId", String.valueOf(updatedChainId));
73+
overrides.put("timestamp", String.valueOf(updatedTimestamp));
74+
genesisConfigFile = genesisConfigFile.withOverrides(overrides);
75+
}
76+
return genesisConfigFile.withOverrides(overrides);
77+
} catch (IOException e) {
78+
throw new RuntimeException("Error updating ephemery genesis: " + e.getMessage(), e);
79+
}
80+
}
81+
}

besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.hamcrest.Matchers.is;
2020
import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC;
2121
import static org.hyperledger.besu.cli.config.NetworkName.DEV;
22+
import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY;
2223
import static org.hyperledger.besu.cli.config.NetworkName.EXPERIMENTAL_EIPS;
2324
import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS;
2425
import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY;
@@ -43,6 +44,7 @@
4344

4445
import org.hyperledger.besu.BesuInfo;
4546
import org.hyperledger.besu.cli.config.EthNetworkConfig;
47+
import org.hyperledger.besu.cli.config.NetworkName;
4648
import org.hyperledger.besu.config.GenesisConfigFile;
4749
import org.hyperledger.besu.config.MergeConfiguration;
4850
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
@@ -1863,6 +1865,20 @@ public void luksoValuesAreUsed() {
18631865
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
18641866
}
18651867

1868+
@Test
1869+
public void ephemeryValuesAreUsed() {
1870+
parseCommand("--network", "ephemery");
1871+
1872+
final ArgumentCaptor<EthNetworkConfig> networkArg =
1873+
ArgumentCaptor.forClass(EthNetworkConfig.class);
1874+
1875+
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
1876+
verify(mockControllerBuilder).build();
1877+
assertThat(NetworkName.valueOf(String.valueOf(EPHEMERY))).isEqualTo(EPHEMERY);
1878+
assertThat(commandOutput.toString(UTF_8)).isEmpty();
1879+
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
1880+
}
1881+
18661882
@Test
18671883
public void classicValuesAreUsed() {
18681884
parseCommand("--network", "classic");

besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ void shouldGenerateDeprecationMessageForDeprecatedNetworks(final NetworkName net
3939
@ParameterizedTest
4040
@EnumSource(
4141
value = NetworkName.class,
42-
names = {
43-
"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO",
44-
})
42+
names = {"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO", "EPHEMERY"})
4543
void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) {
4644
assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network))
4745
.isInstanceOf(AssertionError.class);
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.util;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
19+
import static org.hyperledger.besu.config.GenesisConfigFile.fromConfig;
20+
21+
import org.hyperledger.besu.config.GenesisConfigFile;
22+
23+
import java.math.BigInteger;
24+
import java.util.Map;
25+
import java.util.Optional;
26+
import java.util.TreeMap;
27+
28+
import io.vertx.core.json.JsonObject;
29+
import org.junit.jupiter.api.Test;
30+
import org.junit.jupiter.api.extension.ExtendWith;
31+
import org.mockito.junit.jupiter.MockitoExtension;
32+
33+
@ExtendWith(MockitoExtension.class)
34+
public class EphemeryGenesisUpdaterTest {
35+
private static final int GENESIS_CONFIG_TEST_CHAINID = 39438135;
36+
private static final long GENESIS_TEST_TIMESTAMP = 1720119600;
37+
private static final long EARLIER_TIMESTAMP = 1712041200;
38+
private static final long LATER_TIMESTAMP = 1922041200;
39+
private static final long PERIOD_IN_SECONDS = 28 * 24 * 60 * 60;
40+
private static final long PERIOD_SINCE_GENESIS = 3;
41+
42+
private static final JsonObject VALID_GENESIS_JSON =
43+
(new JsonObject())
44+
.put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID))
45+
.put("timestamp", GENESIS_TEST_TIMESTAMP);
46+
47+
private static final GenesisConfigFile INVALID_GENESIS_JSON = fromConfig("{}");
48+
private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_CHAINID =
49+
(new JsonObject()).put("timestamp", GENESIS_TEST_TIMESTAMP);
50+
51+
private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP =
52+
new JsonObject()
53+
.put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID));
54+
55+
@Test
56+
public void testEphemeryWhenChainIdIsAbsent() {
57+
final GenesisConfigFile config =
58+
GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_CHAINID.toString());
59+
Optional<BigInteger> chainId = config.getConfigOptions().getChainId();
60+
assertThat(chainId).isNotPresent();
61+
}
62+
63+
@Test
64+
public void testShouldDefaultTimestampToZero() {
65+
final GenesisConfigFile config =
66+
GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP.toString());
67+
assertThat(config.getTimestamp()).isZero();
68+
}
69+
70+
@Test
71+
public void testEphemeryWhenGenesisJsonIsInvalid() {
72+
assertThatThrownBy(INVALID_GENESIS_JSON::getDifficulty)
73+
.isInstanceOf(IllegalArgumentException.class)
74+
.hasMessageContaining("Invalid genesis block configuration");
75+
}
76+
77+
@Test
78+
public void testEphemeryWhenGenesisJsonIsValid() {
79+
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
80+
assertThat(String.valueOf(config.getTimestamp()))
81+
.isEqualTo(String.valueOf(GENESIS_TEST_TIMESTAMP));
82+
assertThat(config.getConfigOptions().getChainId())
83+
.hasValue(BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID));
84+
assertThat(String.valueOf(config.getTimestamp())).isNotNull();
85+
assertThat(String.valueOf(config.getTimestamp())).isNotEmpty();
86+
}
87+
88+
@Test
89+
public void testEphemeryNotYetDueForUpdate() {
90+
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
91+
assertThat(EARLIER_TIMESTAMP).isLessThan(config.getTimestamp() + PERIOD_IN_SECONDS);
92+
}
93+
94+
@Test
95+
void testOverrideWithUpdatedChainIdAndTimeStamp() {
96+
BigInteger expectedChainId =
97+
BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID)
98+
.add(BigInteger.valueOf(PERIOD_SINCE_GENESIS));
99+
100+
long expectedGenesisTimestamp =
101+
GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS);
102+
103+
final GenesisConfigFile config = GenesisConfigFile.fromResource("/ephemery.json");
104+
105+
final Map<String, String> override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
106+
override.put("chainId", String.valueOf(expectedChainId));
107+
override.put("timestamp", String.valueOf(expectedGenesisTimestamp));
108+
109+
assertThat(config.withOverrides(override).getConfigOptions().getChainId()).isPresent();
110+
assertThat(config.withOverrides(override).getConfigOptions().getChainId())
111+
.hasValue(expectedChainId);
112+
assertThat(config.withOverrides(override).getTimestamp()).isNotNull();
113+
assertThat(expectedChainId).isEqualTo(override.get("chainId"));
114+
assertThat(String.valueOf(expectedGenesisTimestamp)).isEqualTo(override.get("timestamp"));
115+
}
116+
117+
@Test
118+
public void testEphemeryWhenSuccessful() {
119+
final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString());
120+
121+
BigInteger expectedChainId =
122+
BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID)
123+
.add(BigInteger.valueOf(PERIOD_SINCE_GENESIS));
124+
125+
long expectedGenesisTimestamp =
126+
GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS);
127+
final Map<String, String> override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
128+
override.put("chainId", String.valueOf(expectedChainId));
129+
override.put("timestamp", String.valueOf(expectedGenesisTimestamp));
130+
final GenesisConfigFile updatedConfig = config.withOverrides(override);
131+
132+
assertThat(LATER_TIMESTAMP)
133+
.isGreaterThan(Long.parseLong(String.valueOf(GENESIS_TEST_TIMESTAMP + PERIOD_IN_SECONDS)));
134+
assertThat(updatedConfig.getConfigOptions().getChainId()).hasValue(expectedChainId);
135+
assertThat(updatedConfig.getTimestamp()).isEqualTo(expectedGenesisTimestamp);
136+
assertThat(override.get("timestamp")).isEqualTo(String.valueOf(expectedGenesisTimestamp));
137+
assertThat(override.get("chainId")).isEqualTo(expectedChainId.toString());
138+
}
139+
}

config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ public Optional<String> getCoinbase() {
280280
* @return the timestamp
281281
*/
282282
public long getTimestamp() {
283+
if (overrides != null && overrides.containsKey("timestamp")) {
284+
return Long.parseLong(overrides.get("timestamp"));
285+
}
283286
return parseLong("timestamp", JsonUtil.getValueAsString(genesisRoot, "timestamp", "0x0"));
284287
}
285288

0 commit comments

Comments
 (0)