Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle legacy fork id Eth/64 #1542

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Updated the libraries for secp256k1 and AltBN series precompiles. These updates provide significant performance improvements to those areas. [\#1499](https://github.com/hyperledger/besu/pull/1499)
* Provide MegaGas/second measurements in the log when doing a full block import, such as the catch up phase of a fast sync. [\#1512](https://github.com/hyperledger/besu/pull/1512)
* Added new endpoints to get miner data, `eth_getMinerDataByBlockHash` and `eth_getMinerDataByBlockNumber`. [\#1538](https://github.com/hyperledger/besu/pull/1538)
* Added new CLI option `--Xlegacy-eth-64-fork-id-enabled`. [\#1542](https://github.com/hyperledger/besu/pull/1542)

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class EthProtocolOptions implements CLIOptions<EthProtocolConfiguration>
private static final String MAX_GET_NODE_DATA_FLAG = "--Xewp-max-get-node-data";
private static final String MAX_GET_POOLED_TRANSACTIONS = "--Xewp-max-get-pooled-transactions";
private static final String ETH_65_ENABLED = "--Xeth-65-enabled";
private static final String LEGACY_ETH_64_FORK_ID_ENABLED = "--Xlegacy-eth-64-fork-id-enabled";

@CommandLine.Option(
hidden = true,
Expand Down Expand Up @@ -80,10 +81,18 @@ public class EthProtocolOptions implements CLIOptions<EthProtocolConfiguration>
@CommandLine.Option(
hidden = true,
names = {ETH_65_ENABLED},
paramLabel = "<INTEGER>",
paramLabel = "<Boolean>",
description = "Enable the Eth/65 subprotocol. (default: ${DEFAULT-VALUE})")
private Boolean eth65Enabled = EthProtocolConfiguration.DEFAULT_ETH_65_ENABLED;

@CommandLine.Option(
hidden = true,
names = {LEGACY_ETH_64_FORK_ID_ENABLED},
paramLabel = "<Boolean>",
description = "Enable the legacy Eth/64 fork id. (default: ${DEFAULT-VALUE})")
private Boolean legacyEth64ForkIdEnabled =
EthProtocolConfiguration.DEFAULT_LEGACY_ETH_64_FORK_ID_ENABLED;

private EthProtocolOptions() {}

public static EthProtocolOptions create() {
Expand All @@ -98,6 +107,7 @@ public static EthProtocolOptions fromConfig(final EthProtocolConfiguration confi
options.maxGetNodeData = PositiveNumber.fromInt(config.getMaxGetNodeData());
options.maxGetPooledTransactions = PositiveNumber.fromInt(config.getMaxGetPooledTransactions());
options.eth65Enabled = config.isEth65Enabled();
options.legacyEth64ForkIdEnabled = config.isLegacyEth64ForkIdEnabled();
return options;
}

Expand All @@ -110,6 +120,7 @@ public EthProtocolConfiguration toDomainObject() {
.maxGetNodeData(maxGetNodeData)
.maxGetPooledTransactions(maxGetPooledTransactions)
.eth65Enabled(eth65Enabled)
.legacyEth64ForkIdEnabled(legacyEth64ForkIdEnabled)
.build();
}

Expand All @@ -126,6 +137,7 @@ public List<String> getCLIOptions() {
OptionParser.format(maxGetNodeData.getValue()),
MAX_GET_POOLED_TRANSACTIONS,
OptionParser.format(maxGetPooledTransactions.getValue()),
ETH_65_ENABLED + "=" + eth65Enabled);
ETH_65_ENABLED + "=" + eth65Enabled,
LEGACY_ETH_64_FORK_ID_ENABLED + "=" + legacyEth64ForkIdEnabled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,31 @@ public class EthProtocolConfiguration {
public static final int DEFAULT_MAX_GET_NODE_DATA = 384;
public static final int DEFAULT_MAX_GET_POOLED_TRANSACTIONS = 256;
public static final boolean DEFAULT_ETH_65_ENABLED = false;
public static final boolean DEFAULT_LEGACY_ETH_64_FORK_ID_ENABLED = false;

private final int maxGetBlockHeaders;
private final int maxGetBlockBodies;
private final int maxGetReceipts;
private final int maxGetNodeData;
private final int maxGetPooledTransactions;
private final boolean eth65Enabled;
private final boolean legacyEth64ForkIdEnabled;

public EthProtocolConfiguration(
final int maxGetBlockHeaders,
final int maxGetBlockBodies,
final int maxGetReceipts,
final int maxGetNodeData,
final int maxGetPooledTransactions,
final boolean eth65Enabled) {
final boolean eth65Enabled,
final boolean legacyEth64ForkIdEnabled) {
this.maxGetBlockHeaders = maxGetBlockHeaders;
this.maxGetBlockBodies = maxGetBlockBodies;
this.maxGetReceipts = maxGetReceipts;
this.maxGetNodeData = maxGetNodeData;
this.maxGetPooledTransactions = maxGetPooledTransactions;
this.eth65Enabled = eth65Enabled;
this.legacyEth64ForkIdEnabled = legacyEth64ForkIdEnabled;
}

public static EthProtocolConfiguration defaultConfig() {
Expand All @@ -58,7 +62,8 @@ public static EthProtocolConfiguration defaultConfig() {
DEFAULT_MAX_GET_RECEIPTS,
DEFAULT_MAX_GET_NODE_DATA,
DEFAULT_MAX_GET_POOLED_TRANSACTIONS,
DEFAULT_ETH_65_ENABLED);
DEFAULT_ETH_65_ENABLED,
DEFAULT_LEGACY_ETH_64_FORK_ID_ENABLED);
}

public static Builder builder() {
Expand Down Expand Up @@ -89,6 +94,10 @@ public boolean isEth65Enabled() {
return eth65Enabled;
}

public boolean isLegacyEth64ForkIdEnabled() {
return legacyEth64ForkIdEnabled;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
Expand Down Expand Up @@ -138,6 +147,8 @@ public static class Builder {
PositiveNumber.fromInt(EthProtocolConfiguration.DEFAULT_MAX_GET_POOLED_TRANSACTIONS);

private boolean eth65Enabled = EthProtocolConfiguration.DEFAULT_ETH_65_ENABLED;
private boolean legacyEth64ForkIdEnabled =
EthProtocolConfiguration.DEFAULT_LEGACY_ETH_64_FORK_ID_ENABLED;

public Builder maxGetBlockHeaders(final PositiveNumber maxGetBlockHeaders) {
this.maxGetBlockHeaders = maxGetBlockHeaders;
Expand Down Expand Up @@ -169,14 +180,20 @@ public Builder eth65Enabled(final boolean eth65Enabled) {
return this;
}

public Builder legacyEth64ForkIdEnabled(final boolean legacyEth64ForkIdEnabled) {
this.legacyEth64ForkIdEnabled = legacyEth64ForkIdEnabled;
return this;
}

public EthProtocolConfiguration build() {
return new EthProtocolConfiguration(
maxGetBlockHeaders.getValue(),
maxGetBlockBodies.getValue(),
maxGetReceipts.getValue(),
maxGetNodeData.getValue(),
maxGetPooledTransactions.getValue(),
eth65Enabled);
eth65Enabled,
legacyEth64ForkIdEnabled);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ public EthProtocolManager(
peerValidators,
fastSyncEnabled,
scheduler,
new ForkIdManager(blockchain, Collections.emptyList()));
new ForkIdManager(
blockchain,
Collections.emptyList(),
ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()));
}

public EthProtocolManager(
Expand Down Expand Up @@ -167,7 +170,8 @@ public EthProtocolManager(
peerValidators,
fastSyncEnabled,
scheduler,
new ForkIdManager(blockchain, forks));
new ForkIdManager(
blockchain, forks, ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()));
}

public EthContext ethContext() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ public class ForkIdManager {
private final long highestKnownFork;
private Bytes genesisHashCrc;

public ForkIdManager(final Blockchain blockchain, final List<Long> nonFilteredForks) {
public ForkIdManager(
final Blockchain blockchain, final List<Long> nonFilteredForks, final boolean legacyEth64) {
checkNotNull(blockchain);
checkNotNull(nonFilteredForks);
this.chainHeadSupplier = blockchain::getChainHeadBlockNumber;
this.genesisHash = blockchain.getGenesisBlock().getHash();
this.forkAndHashList = new ArrayList<>();
this.forks =
nonFilteredForks.stream()
.filter(fork -> fork > 0)
.filter(fork -> legacyEth64 ? fork >= 0L : fork > 0L)
.distinct()
.sorted()
.collect(Collectors.toUnmodifiableList());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright ConsenSys AG.
*
* 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.eth;

import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.GenesisHash;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.mockBlockchain;

import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.eth.manager.ForkIdManager;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class ForkIdBackwardCompatibilityTest {
private static final Logger LOG = LogManager.getLogger();

private final String name;
private final String genesisHash;
private final long head;
private final List<Long> forks;
private final boolean legacyEth64;
private final ForkId wantForkId;

public ForkIdBackwardCompatibilityTest(
final String name,
final String genesisHash,
final long head,
final List<Long> forks,
final boolean legacyEth64,
final ForkId wantForkId) {
this.name = name;
this.genesisHash = genesisHash;
this.head = head;
this.forks = forks;
this.legacyEth64 = legacyEth64;
this.wantForkId = wantForkId;
}

@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[][] {
{
"with 0 forks and legacyEth64=false",
GenesisHash.PRIVATE,
2L,
Arrays.asList(0L, 0L, 4L, 5L, 6L),
false,
new ForkId(Bytes.fromHexString("0x190a55ad"), 4L)
},
{
"with 0 forks and legacyEth64=true",
GenesisHash.PRIVATE,
2L,
Arrays.asList(0L, 0L, 4L, 5L, 6L),
true,
new ForkId(Bytes.fromHexString("0xe9ec3db1"), 4L)
},
{
"with no 0 forks and legacyEth64=false",
GenesisHash.PRIVATE,
2L,
Arrays.asList(4L, 5L, 6L),
false,
new ForkId(Bytes.fromHexString("0x190a55ad"), 4L)
},
{
"with no 0 forks and legacyEth64=true",
GenesisHash.PRIVATE,
2L,
Arrays.asList(4L, 5L, 6L),
true,
new ForkId(Bytes.fromHexString("0x190a55ad"), 4L)
},
{
"post head with 0 forks and legacyEth64=false",
GenesisHash.PRIVATE,
8L,
Arrays.asList(0L, 0L, 4L, 5L, 6L),
false,
new ForkId(Bytes.fromHexString("0x033462fc"), 0L)
},
{
"post head with 0 forks and legacyEth64=true",
GenesisHash.PRIVATE,
8L,
Arrays.asList(0L, 0L, 4L, 5L, 6L),
true,
new ForkId(Bytes.fromHexString("0xa571a483"), 0L)
},
});
}

@Test
public void assertBackwardCompatibilityWorks() {
LOG.info("Running test case {}", name);
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain(genesisHash, head), forks, legacyEth64);
assertThat(forkIdManager.computeForkId()).isEqualTo(wantForkId);
}
}
Loading