diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f67ffa0ec..6e853c492e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
### Additions and Improvements
+* Ethereum Classic Magneto Hard Fork [\#2315](https://github.com/hyperledger/besu/pull/2315)
+
### Bug Fixes
### Early Access Features
diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java
index 36b97846b6..d277373860 100644
--- a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java
+++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java
@@ -113,8 +113,9 @@ public class ForkIdsTest {
new ForkId(Bytes.ofUnsignedInt(0x175782aaL), 301243L),
new ForkId(Bytes.ofUnsignedInt(0x604f6ee1L), 999983L),
new ForkId(Bytes.ofUnsignedInt(0xf42f5539L), 2520000L),
- new ForkId(Bytes.ofUnsignedInt(0x66b5c286L), 0L),
- new ForkId(Bytes.ofUnsignedInt(0x66b5c286L), 0L))
+ new ForkId(Bytes.ofUnsignedInt(0x66b5c286L), 3985893),
+ new ForkId(Bytes.ofUnsignedInt(0x92b323e0L), 0),
+ new ForkId(Bytes.ofUnsignedInt(0x92b323e0L), 0))
},
new Object[] {
NetworkName.KOTTI,
@@ -122,8 +123,9 @@ public class ForkIdsTest {
new ForkId(Bytes.ofUnsignedInt(0x550152eL), 716617L),
new ForkId(Bytes.ofUnsignedInt(0xa3270822L), 1705549L),
new ForkId(Bytes.ofUnsignedInt(0x8f3698e0L), 2200013L),
- new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 0L),
- new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 0L))
+ new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 4368634),
+ new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 0),
+ new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 0))
},
new Object[] {
NetworkName.CLASSIC,
@@ -139,8 +141,9 @@ public class ForkIdsTest {
new ForkId(Bytes.ofUnsignedInt(0x518b59c6L), 9573000L),
new ForkId(Bytes.ofUnsignedInt(0x7ba22882L), 10500839L),
new ForkId(Bytes.ofUnsignedInt(0x9007bfccL), 11700000L),
- new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 0L),
- new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 0L))
+ new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 13189133),
+ new ForkId(Bytes.ofUnsignedInt(0x0f6bf187L), 0),
+ new ForkId(Bytes.ofUnsignedInt(0x0f6bf187L), 0))
});
}
diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java
index cf5fded7e7..f3caac982d 100644
--- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java
+++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java
@@ -191,6 +191,15 @@ public interface GenesisConfigOptions {
*/
OptionalLong getThanosBlockNumber();
+ /**
+ * Block number to activate Magneto on Classic networks.
+ *
+ * @return block number of Magneto fork on Classic networks
+ * @see https://github.com/ethereumclassic/ECIPs/issues/424
+ */
+ OptionalLong getMagnetoBlockNumber();
+
/**
* Block number to activate ECIP-1049 on Classic networks. Changes the hashing algorithm to
* keccak-256.
diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
index 27f95f14d1..ddccbfa7e7 100644
--- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
+++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
@@ -317,6 +317,11 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
return getOptionalLong("thanosblock");
}
+ @Override
+ public OptionalLong getMagnetoBlockNumber() {
+ return getOptionalLong("magnetoblock");
+ }
+
@Override
public OptionalLong getEcip1049BlockNumber() {
return getOptionalLong("ecip1049block");
@@ -405,6 +410,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
getAghartaBlockNumber().ifPresent(l -> builder.put("aghartaBlock", l));
getPhoenixBlockNumber().ifPresent(l -> builder.put("phoenixBlock", l));
getThanosBlockNumber().ifPresent(l -> builder.put("thanosBlock", l));
+ getMagnetoBlockNumber().ifPresent(l -> builder.put("magnetoBlock", l));
getEcip1049BlockNumber().ifPresent(l -> builder.put("ecip1049Block", l));
getContractSizeLimit().ifPresent(l -> builder.put("contractSizeLimit", l));
@@ -503,6 +509,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
getAghartaBlockNumber(),
getPhoenixBlockNumber(),
getThanosBlockNumber(),
+ getMagnetoBlockNumber(),
getEcip1049BlockNumber());
// when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json
diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
index 5495675bd1..5f138d2292 100644
--- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
+++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
@@ -49,6 +49,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
private OptionalLong aghartaBlockNumber = OptionalLong.empty();
private OptionalLong phoenixBlockNumber = OptionalLong.empty();
private OptionalLong thanosBlockNumber = OptionalLong.empty();
+ private OptionalLong magnetoBlockNumber = OptionalLong.empty();
private OptionalLong ecip1049BlockNumber = OptionalLong.empty();
private Optional chainId = Optional.empty();
private OptionalInt contractSizeLimit = OptionalInt.empty();
@@ -231,6 +232,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
return thanosBlockNumber;
}
+ @Override
+ public OptionalLong getMagnetoBlockNumber() {
+ return magnetoBlockNumber;
+ }
+
@Override
public OptionalLong getEcip1049BlockNumber() {
return ecip1049BlockNumber;
@@ -292,6 +298,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
getAghartaBlockNumber().ifPresent(l -> builder.put("aghartaBlock", l));
getPhoenixBlockNumber().ifPresent(l -> builder.put("phoenixBlock", l));
getThanosBlockNumber().ifPresent(l -> builder.put("thanosBlock", l));
+ getMagnetoBlockNumber().ifPresent(l -> builder.put("magnetoBlock", l));
getEcip1049BlockNumber().ifPresent(l -> builder.put("ecip1049Block", l));
getContractSizeLimit().ifPresent(l -> builder.put("contractSizeLimit", l));
@@ -446,6 +453,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
return this;
}
+ public StubGenesisConfigOptions magneto(final long blockNumber) {
+ magnetoBlockNumber = OptionalLong.of(blockNumber);
+ return this;
+ }
+
public StubGenesisConfigOptions ecip1049(final long blockNumber) {
ecip1049BlockNumber = OptionalLong.of(blockNumber);
return this;
diff --git a/config/src/main/resources/classic.json b/config/src/main/resources/classic.json
index f1132106ad..1063ef04d0 100644
--- a/config/src/main/resources/classic.json
+++ b/config/src/main/resources/classic.json
@@ -11,6 +11,7 @@
"aghartaBlock": 9573000,
"phoenixBlock": 10500839,
"thanosBlock": 11700000,
+ "magnetoBlock": 13189133,
"ethash": {
}
diff --git a/config/src/main/resources/kotti.json b/config/src/main/resources/kotti.json
index d809428702..2f1725b12a 100644
--- a/config/src/main/resources/kotti.json
+++ b/config/src/main/resources/kotti.json
@@ -5,6 +5,7 @@
"atlantisBlock": 716617,
"aghartaBlock": 1705549,
"phoenixBlock": 2200013,
+ "magnetoBlock": 4368634,
"clique":{
"blockperiodseconds":15,
"epochlength":30000
diff --git a/config/src/main/resources/mordor.json b/config/src/main/resources/mordor.json
index fe0a1e64f1..15311cc5f6 100644
--- a/config/src/main/resources/mordor.json
+++ b/config/src/main/resources/mordor.json
@@ -6,6 +6,7 @@
"phoenixBlock": 999983,
"ecip1017EraRounds": 2000000,
"thanosBlock": 2520000,
+ "magnetoBlock": 3985893,
"ethash": {}
},
"nonce": "0x0000000000000000",
diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java
index 09d3c8ffc2..34338c600c 100644
--- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java
+++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java
@@ -369,7 +369,8 @@ public class AdminNodeInfoTest {
.agharta(7)
.phoenix(8)
.thanos(9)
- .ecip1049(10);
+ .magneto(10)
+ .ecip1049(11);
final AdminNodeInfo methodClassic =
new AdminNodeInfo(
@@ -383,17 +384,19 @@ public class AdminNodeInfoTest {
final JsonRpcRequestContext request = adminNodeInfo();
final Map expectedConfig =
- Map.of(
- "classicForkBlock", 1L,
- "ecip1015Block", 2L,
- "dieHardBlock", 3L,
- "gothamBlock", 4L,
- "ecip1041Block", 5L,
- "atlantisBlock", 6L,
- "aghartaBlock", 7L,
- "phoenixBlock", 8L,
- "thanosBlock", 9L,
- "ecip1049Block", 10L);
+ new HashMap<>(
+ Map.of(
+ "classicForkBlock", 1L,
+ "ecip1015Block", 2L,
+ "dieHardBlock", 3L,
+ "gothamBlock", 4L,
+ "ecip1041Block", 5L,
+ "atlantisBlock", 6L,
+ "aghartaBlock", 7L,
+ "phoenixBlock", 8L,
+ "thanosBlock", 9L,
+ "magnetoBlock", 10L));
+ expectedConfig.put("ecip1049Block", 11L);
final JsonRpcResponse response = methodClassic.response(request);
assertThat(response).isInstanceOf(JsonRpcSuccessResponse.class);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
index 512b5ccb1a..d69127ec4a 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
@@ -33,6 +33,7 @@ import java.util.Collections;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
+import java.util.Set;
public class ClassicProtocolSpecs {
private static final Wei MAX_BLOCK_REWARD = Wei.fromEth(5);
@@ -285,4 +286,34 @@ public class ClassicProtocolSpecs {
.powHasher(powHasher(PowAlgorithm.KECCAK256))
.name("ecip1049");
}
+
+ public static ProtocolSpecBuilder magnetoDefinition(
+ final Optional chainId,
+ final OptionalInt configContractSizeLimit,
+ final OptionalInt configStackSizeLimit,
+ final boolean enableRevertReason,
+ final OptionalLong ecip1017EraRounds,
+ final boolean quorumCompatibilityMode) {
+ return thanosDefinition(
+ chainId,
+ configContractSizeLimit,
+ configStackSizeLimit,
+ enableRevertReason,
+ ecip1017EraRounds,
+ quorumCompatibilityMode)
+ .gasCalculator(BerlinGasCalculator::new)
+ .transactionValidatorBuilder(
+ gasCalculator ->
+ new MainnetTransactionValidator(
+ gasCalculator,
+ true,
+ chainId,
+ Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST),
+ quorumCompatibilityMode))
+ .transactionReceiptFactory(
+ enableRevertReason
+ ? MainnetProtocolSpecs::berlinTransactionReceiptFactoryWithReasonEnabled
+ : MainnetProtocolSpecs::berlinTransactionReceiptFactory)
+ .name("Magneto");
+ }
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
index 478cf6ffe9..733101493f 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
@@ -183,6 +183,16 @@ public class MainnetProtocolSpecFactory {
quorumCompatibilityMode);
}
+ public ProtocolSpecBuilder magnetoDefinition() {
+ return ClassicProtocolSpecs.magnetoDefinition(
+ chainId,
+ contractSizeLimit,
+ evmStackSize,
+ isRevertReasonEnabled,
+ ecip1017EraRounds,
+ quorumCompatibilityMode);
+ }
+
public ProtocolSpecBuilder ecip1049Definition() {
return ClassicProtocolSpecs.ecip1049Definition(
chainId,
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
index 888681fd5a..0617903077 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
@@ -616,7 +616,7 @@ public abstract class MainnetProtocolSpecs {
result.isSuccessful() ? 1 : 0, gasUsed, result.getLogs(), result.getRevertReason());
}
- private static TransactionReceipt berlinTransactionReceiptFactory(
+ static TransactionReceipt berlinTransactionReceiptFactory(
final TransactionType transactionType,
final TransactionProcessingResult transactionProcessingResult,
final WorldState worldState,
@@ -629,7 +629,7 @@ public abstract class MainnetProtocolSpecs {
Optional.empty());
}
- private static TransactionReceipt berlinTransactionReceiptFactoryWithReasonEnabled(
+ static TransactionReceipt berlinTransactionReceiptFactoryWithReasonEnabled(
final TransactionType transactionType,
final TransactionProcessingResult transactionProcessingResult,
final WorldState worldState,
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
index f6927aab68..c117ff3090 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
@@ -234,6 +234,7 @@ public class ProtocolScheduleBuilder {
create(config.getAghartaBlockNumber(), specFactory.aghartaDefinition()),
create(config.getPhoenixBlockNumber(), specFactory.phoenixDefinition()),
create(config.getThanosBlockNumber(), specFactory.thanosDefinition()),
+ create(config.getMagnetoBlockNumber(), specFactory.magnetoDefinition()),
create(config.getEcip1049BlockNumber(), specFactory.ecip1049Definition()))
.stream()
.filter(Optional::isPresent)
@@ -327,6 +328,7 @@ public class ProtocolScheduleBuilder {
lastForkBlock = validateForkOrder("Agharta", config.getAghartaBlockNumber(), lastForkBlock);
lastForkBlock = validateForkOrder("Phoenix", config.getPhoenixBlockNumber(), lastForkBlock);
lastForkBlock = validateForkOrder("Thanos", config.getThanosBlockNumber(), lastForkBlock);
+ lastForkBlock = validateForkOrder("Magneto", config.getMagnetoBlockNumber(), lastForkBlock);
assert (lastForkBlock >= 0);
}
}