Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
[PAN-2954] - Allow fixedDifficulty=1 to mean "all solutions" (#1784)
Browse files Browse the repository at this point in the history
If you try and do a difficulty of 1 the UInt256 class used for comparison throws
an error because 2^256 is 33 bytes.  Instead use 2^256-1 which is 32.
  • Loading branch information
Danno Ferrin authored Jul 30, 2019
1 parent 686b481 commit 4f531b5
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ private EthHashSolverInputs generateNonceSolverInputs(
final SealableBlockHeader sealableBlockHeader) {
final BigInteger difficulty =
BytesValues.asUnsignedBigInteger(sealableBlockHeader.getDifficulty().getBytes());
final UInt256 target = UInt256.of(EthHash.TARGET_UPPER_BOUND.divide(difficulty));
final UInt256 target =
difficulty.equals(BigInteger.ONE)
? UInt256.MAX_VALUE
: UInt256.of(EthHash.TARGET_UPPER_BOUND.divide(difficulty));

return new EthHashSolverInputs(
target, EthHash.hashHeader(sealableBlockHeader), sealableBlockHeader.getNumber());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,20 @@ public class EthHashBlockCreatorTest {
BytesValue.fromHexString("0x476574682f76312e302e302f6c696e75782f676f312e342e32");
private final MetricsSystem metricsSystem = new NoOpMetricsSystem();

private final ExecutionContextTestFixture executionContextTestFixture =
ExecutionContextTestFixture.builder()
.protocolSchedule(
new ProtocolScheduleBuilder<>(
GenesisConfigFile.DEFAULT.getConfigOptions(),
BigInteger.valueOf(42),
Function.identity(),
PrivacyParameters.DEFAULT,
false)
.createProtocolSchedule())
.build();

@Test
public void createMainnetBlock1() throws IOException {
final ExecutionContextTestFixture executionContextTestFixture =
ExecutionContextTestFixture.builder()
.protocolSchedule(
new ProtocolScheduleBuilder<>(
GenesisConfigFile.DEFAULT.getConfigOptions(),
BigInteger.valueOf(42),
Function.identity(),
PrivacyParameters.DEFAULT,
false)
.createProtocolSchedule())
.build();

final EthHashSolver solver = new EthHashSolver(Lists.newArrayList(BLOCK_1_NONCE), new Light());

final PendingTransactions pendingTransactions =
Expand Down Expand Up @@ -94,4 +94,46 @@ public void createMainnetBlock1() throws IOException {
Assertions.assertThat(actualBlock).isEqualTo(expectedBlock);
Assertions.assertThat(blockCreator.getHashesPerSecond().isPresent()).isTrue();
}

@Test
public void createMainnetBlock1_fixedDifficulty1() throws IOException {
final ExecutionContextTestFixture executionContextTestFixture =
ExecutionContextTestFixture.builder()
.protocolSchedule(
new ProtocolScheduleBuilder<>(
GenesisConfigFile.fromConfig(
"{\"config\": {\"ethash\": {\"fixeddifficulty\":1}}}")
.getConfigOptions(),
BigInteger.valueOf(42),
Function.identity(),
PrivacyParameters.DEFAULT,
false)
.createProtocolSchedule())
.build();

final EthHashSolver solver = new EthHashSolver(Lists.newArrayList(BLOCK_1_NONCE), new Light());

final PendingTransactions pendingTransactions =
new PendingTransactions(
TransactionPoolConfiguration.DEFAULT_TX_RETENTION_HOURS,
1,
TestClock.fixed(),
metricsSystem);

final EthHashBlockCreator blockCreator =
new EthHashBlockCreator(
BLOCK_1_COINBASE,
parent -> BLOCK_1_EXTRA_DATA,
pendingTransactions,
executionContextTestFixture.getProtocolContext(),
executionContextTestFixture.getProtocolSchedule(),
gasLimit -> gasLimit,
solver,
Wei.ZERO,
executionContextTestFixture.getBlockchain().getChainHeadHeader());

blockCreator.createBlock(BLOCK_1_TIMESTAMP);
// If we weren't setting difficulty to 2^256-1 a difficulty of 1 would have caused a
// IllegalArgumentException at the previous line, as 2^256 is 33 bytes.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ public final class ProofOfWorkValidationRule implements DetachedBlockHeaderValid

private static final Logger LOG = LogManager.getLogger();

private static final BigInteger ETHHASH_TARGET_UPPER_BOUND = BigInteger.valueOf(2).pow(256);
private static final BigInteger ETHASH_TARGET_UPPER_BOUND = BigInteger.valueOf(2).pow(256);

private static final EthHasher HASHER = new EthHasher.Light();
static final EthHasher HASHER = new EthHasher.Light();

@Override
public boolean validate(final BlockHeader header, final BlockHeader parent) {
Expand All @@ -47,8 +47,10 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) {
}
final BigInteger difficulty =
BytesValues.asUnsignedBigInteger(header.getDifficulty().getBytes());
final UInt256 target = UInt256.of(ETHHASH_TARGET_UPPER_BOUND.divide(difficulty));

final UInt256 target =
difficulty.equals(BigInteger.ONE)
? UInt256.MAX_VALUE
: UInt256.of(ETHASH_TARGET_UPPER_BOUND.divide(difficulty));
final UInt256 result = UInt256.wrap(Bytes32.wrap(hashBuffer, 32));
if (result.compareTo(target) > 0) {
LOG.warn(
Expand All @@ -75,7 +77,7 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) {
return true;
}

private Hash hashHeader(final BlockHeader header) {
Hash hashHeader(final BlockHeader header) {
final BytesValueRLPOutput out = new BytesValueRLPOutput();

// Encode header without nonce and mixhash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationTestUtils;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.uint.UInt256;

import java.io.IOException;
Expand Down Expand Up @@ -75,6 +77,27 @@ public void failsBlockWithZeroValuedDifficulty() {
assertThat(validationRule.validate(header, parentHeader)).isFalse();
}

@Test
public void passesBlockWithOneValuedDifficulty() {
final BlockHeaderBuilder headerBuilder =
BlockHeaderBuilder.fromHeader(blockHeader)
.difficulty(UInt256.ONE)
.blockHeaderFunctions(mainnetBlockHashFunction())
.timestamp(1);
final BlockHeader preHeader = headerBuilder.buildBlockHeader();
final byte[] hashBuffer = new byte[64];
final Hash headerHash = validationRule.hashHeader(preHeader);
ProofOfWorkValidationRule.HASHER.hash(
hashBuffer, preHeader.getNonce(), preHeader.getNumber(), headerHash.extractArray());

final BlockHeader header =
headerBuilder
.mixHash(Hash.wrap(Bytes32.leftPad(BytesValue.wrap(hashBuffer).slice(0, Bytes32.SIZE))))
.buildBlockHeader();

assertThat(validationRule.validate(header, parentHeader)).isTrue();
}

@Test
public void failsWithVeryLargeDifficulty() {
final UInt256 largeDifficulty = UInt256.of(BigInteger.valueOf(2).pow(255));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public interface UInt256 extends UInt256Value<UInt256> {
UInt256 ONE = of(1);
/** The value 32. */
UInt256 U_32 = of(32);
/** The value of 2^256-1 */
UInt256 MAX_VALUE =
fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");

static UInt256 of(final long value) {
return new DefaultUInt256(UInt256Bytes.of(value));
Expand Down

0 comments on commit 4f531b5

Please sign in to comment.