Skip to content

Commit

Permalink
ETC DieHard fork support (#177)
Browse files Browse the repository at this point in the history
This PR introduces code to implement Ethereum Classic DieHard Fork support

ECIP-1015 Gas cost change
ECIP-1010 Delay Difficulty Bomb Explosion

Signed-off-by: edwardmack <ed@edwardmack.com>
  • Loading branch information
edwardmack authored and shemnon committed Nov 12, 2019
1 parent 55e2475 commit bfa29cd
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,31 @@ public interface GenesisConfigOptions {
*/
OptionalLong getClassicForkBlock();

/**
* Block number for ECIP-1015 fork on Classic network ECIP-1015: Long-term gas cost changes for
* IO-heavy operations to mitigate transaction spam attacks In reference to EIP-150 (ETH Tangerine
* Whistle) Note, this fork happens after Homestead (Mainnet definition) and before DieHard fork
*
* @see <a
* href="https://ecips.ethereumclassic.org/ECIPs/ecip-1015">https://ecips.ethereumclassic.org/ECIPs/ecip-1015</a>
* @return block number to activate ECIP-1015 code
*/
OptionalLong getEcip1015BlockNumber();

/**
* Block number for DieHard fork on Classic network The DieHard fork includes changes to meet
* specification for ECIP-1010 and EIP-160 Note, this fork happens after ECIP-1015 (classic
* tangerine whistle) and before Gotham fork ECIP-1010: Delay Difficulty Bomb Explosion
*
* @see <a
* href="https://ecips.ethereumclassic.org/ECIPs/ecip-1010">https://ecips.ethereumclassic.org/ECIPs/ecip-1010</a>
* EIP-160: EXP cost increase
* @see <a
* href="https://eips.ethereum.org/EIPS/eip-160">https://eips.ethereum.org/EIPS/eip-160</a>
* @return block number to activate Classic DieHard fork
*/
OptionalLong getDieHardBlockNumber();

Optional<BigInteger> getChainId();

OptionalInt getContractSizeLimit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ public OptionalLong getClassicForkBlock() {
return getOptionalLong("classicforkblock");
}

@Override
public OptionalLong getEcip1015BlockNumber() {
return getOptionalLong("ecip1015block");
}

@Override
public OptionalLong getDieHardBlockNumber() {
return getOptionalLong("diehardblock");
}

@Override
public Optional<BigInteger> getChainId() {
return getOptionalBigInteger("chainid");
Expand Down
2 changes: 2 additions & 0 deletions config/src/main/resources/classic.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"chainId": 61,
"homesteadBlock": 1150000,
"classicForkBlock": 1920000,
"ecip1015Block": 2500000,
"diehardBlock": 3000000,
"ethash": {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
private OptionalLong constantinopleFixBlockNumber = OptionalLong.empty();
private OptionalLong istanbulBlockNumber = OptionalLong.empty();
private OptionalLong classicForkBlock = OptionalLong.empty();
private OptionalLong ecip1015BlockNumber = OptionalLong.empty();
private OptionalLong diehardBlockNumber = OptionalLong.empty();
private Optional<BigInteger> chainId = Optional.empty();
private OptionalInt contractSizeLimit = OptionalInt.empty();
private OptionalInt stackSizeLimit = OptionalInt.empty();
Expand Down Expand Up @@ -127,6 +129,16 @@ public OptionalLong getClassicForkBlock() {
return classicForkBlock;
}

@Override
public OptionalLong getEcip1015BlockNumber() {
return ecip1015BlockNumber;
}

@Override
public OptionalLong getDieHardBlockNumber() {
return diehardBlockNumber;
}

@Override
public OptionalInt getContractSizeLimit() {
return contractSizeLimit;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.mainnet;

import org.hyperledger.besu.util.uint.UInt256;

import java.math.BigInteger;

import com.google.common.primitives.Ints;

public abstract class ClassicDifficultyCalculators {
private static final BigInteger MINIMUM_DIFFICULTY = BigInteger.valueOf(131_072L);
private static final BigInteger DIFFICULTY_BOUND_DIVISOR = BigInteger.valueOf(2_048L);
private static final BigInteger BIGINT_2 = BigInteger.valueOf(2L);
private static final long EXPONENTIAL_DIFF_PERIOD = 100_000L;
private static final long PAUSE_BLOCK = 3_000_000L;
private static final long FIXED_DIFF = PAUSE_BLOCK / EXPONENTIAL_DIFF_PERIOD;

public static DifficultyCalculator<Void> DIFFICULTY_BOMB_PAUSED =
(time, parent, protocolContext) -> {
final BigInteger parentDifficulty = difficulty(parent.getDifficulty());
final BigInteger difficulty =
ensureMinimumDifficulty(
BigInteger.valueOf(Math.max(1 - (time - parent.getTimestamp()) / 10, -99L))
.multiply(parentDifficulty.divide(DIFFICULTY_BOUND_DIVISOR))
.add(parentDifficulty));
return adjustForDifficultyPause(FIXED_DIFF, difficulty);
};

private static BigInteger adjustForDifficultyPause(
final long periodCount, final BigInteger difficulty) {
return difficulty.add(BIGINT_2.pow(Ints.checkedCast(periodCount - 2)));
}

private static BigInteger ensureMinimumDifficulty(final BigInteger difficulty) {
return difficulty.compareTo(MINIMUM_DIFFICULTY) < 0 ? MINIMUM_DIFFICULTY : difficulty;
}

private static BigInteger difficulty(final UInt256 value) {
return new BigInteger(1, value.getBytes().extractArray());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.mainnet;

import java.math.BigInteger;
import java.util.Optional;
import java.util.OptionalInt;

public class ClassicProtocolSpecs {

public static ProtocolSpecBuilder<Void> classicRecoveryInitDefinition(
final OptionalInt contractSizeLimit, final OptionalInt configStackSizeLimit) {
return MainnetProtocolSpecs.homesteadDefinition(contractSizeLimit, configStackSizeLimit)
.blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::createClassicValidator)
.name("ClassicRecoveryInit");
}

public static ProtocolSpecBuilder<Void> tangerineWhistleDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit) {
return MainnetProtocolSpecs.homesteadDefinition(contractSizeLimit, configStackSizeLimit)
.gasCalculator(TangerineWhistleGasCalculator::new)
.transactionValidatorBuilder(
gasCalculator -> new MainnetTransactionValidator(gasCalculator, true, chainId))
.name("ClassicTangerineWhistle");
}

public static ProtocolSpecBuilder<Void> dieHardDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit) {
return tangerineWhistleDefinition(chainId, OptionalInt.empty(), configStackSizeLimit)
.gasCalculator(DieHardGasCalculator::new)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED)
.name("DieHard");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.mainnet;

import org.hyperledger.besu.ethereum.core.Gas;

public class DieHardGasCalculator extends TangerineWhistleGasCalculator {
private static final Gas EXP_OPERATION_BYTE_GAS_COST = Gas.of(50L);

@Override
protected Gas expOperationByteGasCost() {
return EXP_OPERATION_BYTE_GAS_COST;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,32 @@ public ProtocolSchedule<C> createProtocolSchedule() {
config.getEvmStackSize(),
isRevertReasonEnabled));

// specs for classic network
config
.getClassicForkBlock()
.ifPresent(
classicBlockNumber -> {
final ProtocolSpec<C> originalProtocolSpce =
protocolSchedule.getByBlockNumber(classicBlockNumber);
addProtocolSpec(
protocolSchedule,
OptionalLong.of(classicBlockNumber),
ClassicProtocolSpecs.classicRecoveryInitDefinition(
config.getContractSizeLimit(), config.getEvmStackSize()));
protocolSchedule.putMilestone(classicBlockNumber + 10, originalProtocolSpce);
});

addProtocolSpec(
protocolSchedule,
config.getEcip1015BlockNumber(),
ClassicProtocolSpecs.tangerineWhistleDefinition(
chainId, config.getContractSizeLimit(), config.getEvmStackSize()));
addProtocolSpec(
protocolSchedule,
config.getDieHardBlockNumber(),
ClassicProtocolSpecs.dieHardDefinition(
chainId, config.getContractSizeLimit(), config.getEvmStackSize()));

LOG.info("Protocol schedule created with milestones: {}", protocolSchedule.listMilestones());
return protocolSchedule;
}
Expand Down

0 comments on commit bfa29cd

Please sign in to comment.