From 9b7114000f98df648ea07be10c7fd266638b47fd Mon Sep 17 00:00:00 2001 From: Leonor Boga Date: Fri, 16 Apr 2021 13:59:04 +0200 Subject: [PATCH] [ETCM-746] Added support for PoW with Keccak-256 (ECIP-1049) Renamed several classes from Ethash to PoW because they will be used in both Ethash Pow and Keccak PoW --- build.sbt | 22 +- .../scala/io/iohk/ethereum/utils/Hex.scala | 2 +- .../io/iohk/ethereum/crypto/package.scala | 9 + .../ets/blockchain/BlockchainTestConfig.scala | 31 +-- .../EthashTestBlockHeaderValidator.scala | 10 +- .../ets/blockchain/ScenarioSetup.scala | 14 +- .../ethereum/ledger/BlockImporterItSpec.scala | 3 +- .../sync/util/RegularSyncItSpecUtils.scala | 12 +- .../ethereum/txExecTest/ECIP1017Test.scala | 3 +- .../iohk/ethereum/txExecTest/ForksTest.scala | 3 +- src/main/resources/conf/base-testnet.conf | 2 +- src/main/resources/conf/base.conf | 6 +- src/main/resources/conf/chains/etc-chain.conf | 5 + .../resources/conf/chains/test-chain.conf | 2 +- .../chains/testnet-internal-gac-chain.conf | 2 +- .../chains/testnet-internal-nomad-chain.conf | 2 +- .../iohk/ethereum/consensus/Consensus.scala | 2 +- .../ethereum/consensus/ConsensusBuilder.scala | 24 +- .../ethereum/consensus/ConsensusConfig.scala | 4 +- .../ethereum/consensus/ConsensusMetrics.scala | 6 +- .../io/iohk/ethereum/consensus/Protocol.scala | 18 +- .../consensus/blocks/BlockGenerator.scala | 2 +- .../blocks/BlockGeneratorSkeleton.scala | 4 +- .../difficulty/DifficultyCalculator.scala | 2 +- .../consensus/ethash/EthashMiner.scala | 252 ------------------ .../io/iohk/ethereum/consensus/package.scala | 8 +- .../{ethash => pow}/EthashBlockCreator.scala | 8 +- .../{ethash => pow}/EthashConfig.scala | 4 +- .../consensus/pow/EthashDAGManager.scala | 94 +++++++ .../ethereum/consensus/pow/EthashMiner.scala | 205 ++++++++++++++ .../{ethash => pow}/EthashUtils.scala | 14 +- .../consensus/pow/KeccakCalculation.scala | 37 +++ .../{ethash => pow}/MinerProtocol.scala | 2 +- .../{ethash => pow}/MinerUtils.scala | 4 +- .../{ethash => pow}/MockedMiner.scala | 16 +- .../PoWConsensus.scala} | 56 ++-- .../RestrictedPoWSigner.scala} | 4 +- .../blocks/PoWBlockGenerator.scala} | 16 +- .../RestrictedPoWBlockGeneratorImpl.scala} | 14 +- .../{ethash => pow}/blocks/package.scala | 4 +- .../EthashDifficultyCalculator.scala | 2 +- .../TargetTimeDifficultyCalculator.scala | 2 +- .../EthashBlockHeaderValidator.scala | 17 +- .../KeccakBlockHeaderValidator.scala | 24 ++ .../MockedPowBlockHeaderValidator.scala | 2 +- .../validators/OmmersValidator.scala | 4 +- .../validators/PoWBlockHeaderValidator.scala | 33 +++ ...RestrictedEthashBlockHeaderValidator.scala | 14 +- .../validators}/StdOmmersValidator.scala | 13 +- .../validators}/StdValidatorsExecutor.scala | 7 +- .../validators}/ValidatorsExecutor.scala | 15 +- .../validators/BlockHeaderValidator.scala | 2 +- .../validators/std/StdBlockValidator.scala | 2 +- .../validators/std/StdValidators.scala | 2 +- .../iohk/ethereum/jsonrpc/BlockResponse.scala | 4 +- .../ethereum/jsonrpc/EthMiningService.scala | 2 +- .../iohk/ethereum/jsonrpc/JsonRpcError.scala | 2 +- .../io/iohk/ethereum/jsonrpc/QAService.scala | 6 +- .../ethereum/testmode/TestmodeConsensus.scala | 6 +- .../ethereum/utils/BlockchainConfig.scala | 4 + src/test/scala/io/iohk/ethereum/Mocks.scala | 7 +- .../blockchain/sync/ScenarioSetup.scala | 7 +- .../ethereum/consensus/ConsensusConfigs.scala | 4 +- .../ethereum/consensus/ConsensusSpec.scala | 2 +- .../consensus/blocks/BlockGeneratorSpec.scala | 54 ++-- .../{ethash => pow}/EthashMinerSpec.scala | 17 +- .../{ethash => pow}/EthashUtilsSpec.scala | 4 +- .../consensus/pow/KeccakCalculationSpec.scala | 35 +++ .../consensus/pow/KeccakDataUtils.scala | 29 ++ .../{ethash => pow}/MinerSpecSetup.scala | 13 +- .../{ethash => pow}/MockedMinerSpec.scala | 4 +- .../RestrictedEthashSignerSpec.scala | 10 +- .../EthashBlockHeaderValidatorSpec.scala | 42 +-- .../KeccakBlockHeaderValidatorSpec.scala | 31 +++ .../PoWBlockHeaderValidatorSpec.scala | 62 +++++ ...rictedEthashBlockHeaderValidatorSpec.scala | 15 +- .../validators}/StdOmmersValidatorSpec.scala | 7 +- .../jsonrpc/EthBlocksServiceSpec.scala | 4 +- .../ethereum/jsonrpc/EthInfoServiceSpec.scala | 4 +- .../jsonrpc/EthMiningServiceSpec.scala | 8 +- .../jsonrpc/EthProofServiceSpec.scala | 4 +- .../jsonrpc/JsonRpcControllerFixture.scala | 6 +- .../jsonrpc/PersonalServiceSpec.scala | 3 +- .../iohk/ethereum/jsonrpc/QAServiceSpec.scala | 6 +- .../io/iohk/ethereum/jsonrpc/QaJRCSpec.scala | 4 +- .../io/iohk/ethereum/ledger/LedgerSpec.scala | 2 +- .../ethereum/ledger/LedgerTestSetup.scala | 3 +- .../iohk/ethereum/ledger/StxLedgerSpec.scala | 3 +- 88 files changed, 897 insertions(+), 584 deletions(-) delete mode 100644 src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/EthashBlockCreator.scala (89%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/EthashConfig.scala (92%) create mode 100644 src/main/scala/io/iohk/ethereum/consensus/pow/EthashDAGManager.scala create mode 100644 src/main/scala/io/iohk/ethereum/consensus/pow/EthashMiner.scala rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/EthashUtils.scala (95%) create mode 100644 src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/MinerProtocol.scala (94%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/MinerUtils.scala (62%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/MockedMiner.scala (89%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash/EthashConsensus.scala => pow/PoWConsensus.scala} (81%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash/RestrictedEthashSigner.scala => pow/RestrictedPoWSigner.scala} (94%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash/blocks/EthashBlockGenerator.scala => pow/blocks/PoWBlockGenerator.scala} (88%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash/blocks/RestrictedEthashBlockGeneratorImpl.scala => pow/blocks/RestrictedPoWBlockGeneratorImpl.scala} (82%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/blocks/package.scala (80%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/difficulty/EthashDifficultyCalculator.scala (98%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/difficulty/TargetTimeDifficultyCalculator.scala (96%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/EthashBlockHeaderValidator.scala (77%) create mode 100644 src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/MockedPowBlockHeaderValidator.scala (93%) rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/OmmersValidator.scala (91%) create mode 100644 src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala rename src/main/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/RestrictedEthashBlockHeaderValidator.scala (69%) rename src/main/scala/io/iohk/ethereum/consensus/{validators/std => pow/validators}/StdOmmersValidator.scala (93%) rename src/main/scala/io/iohk/ethereum/consensus/{validators/std => pow/validators}/StdValidatorsExecutor.scala (68%) rename src/main/scala/io/iohk/ethereum/consensus/{validators/std => pow/validators}/ValidatorsExecutor.scala (89%) rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/EthashMinerSpec.scala (91%) rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/EthashUtilsSpec.scala (98%) create mode 100644 src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala create mode 100644 src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/MinerSpecSetup.scala (90%) rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/MockedMinerSpec.scala (97%) rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/RestrictedEthashSignerSpec.scala (70%) rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/EthashBlockHeaderValidatorSpec.scala (93%) create mode 100644 src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala create mode 100644 src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala rename src/test/scala/io/iohk/ethereum/consensus/{ethash => pow}/validators/RestrictedEthashBlockHeaderValidatorSpec.scala (94%) rename src/test/scala/io/iohk/ethereum/consensus/{validators/std => pow/validators}/StdOmmersValidatorSpec.scala (98%) diff --git a/build.sbt b/build.sbt index 4ac21ff405..4f3b70d271 100644 --- a/build.sbt +++ b/build.sbt @@ -13,19 +13,23 @@ val nixBuild = sys.props.isDefinedAt("nix") val mantisDev = sys.props.get("mantisDev").contains("true") || sys.env.get("MANTIS_DEV").contains("true") lazy val compilerOptimizationsForProd = Seq( - "-opt:l:method", // method-local optimizations - "-opt:l:inline", // inlining optimizations + "-opt:l:method", // method-local optimizations + "-opt:l:inline", // inlining optimizations "-opt-inline-from:io.iohk.**" // inlining the project only ) // Releasing. https://github.com/olafurpg/sbt-ci-release -inThisBuild(List( - organization := "io.iohk", - homepage := Some(url("https://github.com/input-output-hk/mantis")), - scmInfo := Some(ScmInfo(url("https://github.com/input-output-hk/mantis"), "git@github.com:input-output-hk/mantis.git")), - licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")), - developers := List() -)) +inThisBuild( + List( + organization := "io.iohk", + homepage := Some(url("https://github.com/input-output-hk/mantis")), + scmInfo := Some( + ScmInfo(url("https://github.com/input-output-hk/mantis"), "git@github.com:input-output-hk/mantis.git") + ), + licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")), + developers := List() + ) +) // https://github.com/sbt/sbt/issues/3570 updateOptions := updateOptions.value.withGigahorse(false) diff --git a/bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala b/bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala index 1c38bf61f0..15dce1e589 100644 --- a/bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala +++ b/bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala @@ -6,6 +6,6 @@ object Hex { def decode(hex: String): Array[Byte] = hex.toSeq.sliding(2, 2).toArray.map { s => - Integer.parseInt(s.mkString(""), 16).toByte + Integer.parseInt(s.mkString(""), 16).toByte } } diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala index 7e3e56b5aa..d288449eec 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala @@ -41,6 +41,15 @@ package object crypto { def kec256(input: ByteString): ByteString = ByteString(kec256(input.toArray)) + def kec256PoW(header: Array[Byte], nonce: Array[Byte]): Array[Byte] = { + val digest = new KeccakDigest(256) + digest.update(header, 0, header.length) + digest.update(nonce, 0, nonce.length) + val output = Array.ofDim[Byte](32) + digest.doFinal(output, 0) + output + } + def kec512(input: Array[Byte]): Array[Byte] = synchronized { val out = Array.ofDim[Byte](kec512.getDigestSize) kec512.update(input, 0, input.length) diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala index b8cf286ba1..91083716f5 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.ets.blockchain import akka.util.ByteString import io.iohk.ethereum.consensus.Protocol -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.domain.{Address, UInt256} import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig} import org.bouncycastle.util.encoders.Hex @@ -46,7 +46,8 @@ object BlockchainTestConfig { ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) val FrontierConfig = BaseBlockchainConfig.copy( @@ -316,19 +317,19 @@ object BlockchainTestConfig { object Validators { import BlockchainTestConfig._ - val frontierValidators = ValidatorsExecutor(FrontierConfig, Protocol.Ethash) - val homesteadValidators = ValidatorsExecutor(HomesteadConfig, Protocol.Ethash) - val eip150Validators = ValidatorsExecutor(Eip150Config, Protocol.Ethash) - val frontierToHomesteadValidators = ValidatorsExecutor(FrontierToHomesteadAt5, Protocol.Ethash) - val homesteadToEipValidators = ValidatorsExecutor(HomesteadToEIP150At5, Protocol.Ethash) - val homesteadToDaoValidators = ValidatorsExecutor(HomesteadToDaoAt5, Protocol.Ethash) - val eip158Validators = ValidatorsExecutor(Eip158Config, Protocol.Ethash) - val byzantiumValidators = ValidatorsExecutor(ByzantiumConfig, Protocol.Ethash) - val constantinopleValidators = ValidatorsExecutor(ConstantinopleConfig, Protocol.Ethash) - val constantinopleFixValidators = ValidatorsExecutor(ConstantinopleFixConfig, Protocol.Ethash) - val istanbulValidators = ValidatorsExecutor(IstanbulConfig, Protocol.Ethash) - val eip158ToByzantiumValidators = ValidatorsExecutor(Eip158ToByzantiumAt5Config, Protocol.Ethash) - val byzantiumToConstantinopleAt5 = ValidatorsExecutor(ByzantiumToConstantinopleAt5, Protocol.Ethash) + val frontierValidators = ValidatorsExecutor(FrontierConfig, Protocol.PoW) + val homesteadValidators = ValidatorsExecutor(HomesteadConfig, Protocol.PoW) + val eip150Validators = ValidatorsExecutor(Eip150Config, Protocol.PoW) + val frontierToHomesteadValidators = ValidatorsExecutor(FrontierToHomesteadAt5, Protocol.PoW) + val homesteadToEipValidators = ValidatorsExecutor(HomesteadToEIP150At5, Protocol.PoW) + val homesteadToDaoValidators = ValidatorsExecutor(HomesteadToDaoAt5, Protocol.PoW) + val eip158Validators = ValidatorsExecutor(Eip158Config, Protocol.PoW) + val byzantiumValidators = ValidatorsExecutor(ByzantiumConfig, Protocol.PoW) + val constantinopleValidators = ValidatorsExecutor(ConstantinopleConfig, Protocol.PoW) + val constantinopleFixValidators = ValidatorsExecutor(ConstantinopleFixConfig, Protocol.PoW) + val istanbulValidators = ValidatorsExecutor(IstanbulConfig, Protocol.PoW) + val eip158ToByzantiumValidators = ValidatorsExecutor(Eip158ToByzantiumAt5Config, Protocol.PoW) + val byzantiumToConstantinopleAt5 = ValidatorsExecutor(ByzantiumToConstantinopleAt5, Protocol.PoW) } // Connected with: https://github.com/ethereum/tests/issues/480 diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/EthashTestBlockHeaderValidator.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/EthashTestBlockHeaderValidator.scala index 9e91a37c45..6d3430ac93 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/EthashTestBlockHeaderValidator.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/EthashTestBlockHeaderValidator.scala @@ -1,17 +1,19 @@ package io.iohk.ethereum.ets.blockchain import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.validators.EthashBlockHeaderValidator -import io.iohk.ethereum.consensus.validators.{ BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton } +import io.iohk.ethereum.consensus.pow.validators.EthashBlockHeaderValidator +import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig -class EthashTestBlockHeaderValidator(blockchainConfig: BlockchainConfig) extends BlockHeaderValidatorSkeleton(blockchainConfig) { +class EthashTestBlockHeaderValidator(blockchainConfig: BlockchainConfig) + extends BlockHeaderValidatorSkeleton(blockchainConfig) { import EthashBlockHeaderValidator._ // NOTE the below comment is from before PoW decoupling // we need concurrent map since validators can be used from multiple places - protected val powCaches: java.util.concurrent.ConcurrentMap[Long, PowCacheData] = new java.util.concurrent.ConcurrentHashMap[Long, PowCacheData]() + protected val powCaches: java.util.concurrent.ConcurrentMap[Long, PowCacheData] = + new java.util.concurrent.ConcurrentHashMap[Long, PowCacheData]() protected def difficulty: DifficultyCalculator = DifficultyCalculator(blockchainConfig) diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala index b06da2b53f..f97fd50bde 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.ets.blockchain import akka.util.ByteString -import io.iohk.ethereum.consensus.Protocol.NoAdditionalEthashData -import io.iohk.ethereum.consensus.ethash.EthashConsensus -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor -import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, TestConsensus, ethash} +import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData +import io.iohk.ethereum.consensus.pow.{EthashConfig, PoWConsensus} +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor +import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, TestConsensus, pow} import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.components.{EphemDataSourceComponent, Storages} import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} @@ -23,7 +23,7 @@ import scala.util.{Failure, Success, Try} object ScenarioSetup { val testContext = Scheduler.fixedPool("scenario-setup-pool", 4) - val specificConfig = ethash.EthashConfig(Config.config) + val specificConfig = EthashConfig(Config.config) val fullConfig = FullConsensusConfig(ConsensusConfig(Config.config), specificConfig) def loadEthashConsensus( @@ -31,8 +31,8 @@ object ScenarioSetup { blockchain: BlockchainImpl, blockchainConfig: BlockchainConfig, validators: ValidatorsExecutor - ): ethash.EthashConsensus = { - val consensus = EthashConsensus(vm, blockchain, blockchainConfig, fullConfig, validators, NoAdditionalEthashData) + ): PoWConsensus = { + val consensus = PoWConsensus(vm, blockchain, blockchainConfig, fullConfig, validators, NoAdditionalPoWData) consensus } diff --git a/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala b/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala index fe2f42e0be..d68558b1f2 100644 --- a/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala @@ -8,9 +8,8 @@ import io.iohk.ethereum.blockchain.sync.regular.{BlockFetcher, BlockImporter} import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, StdOmmersValidator} import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.consensus.validators.std.StdOmmersValidator import io.iohk.ethereum.domain._ import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config.SyncConfig diff --git a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala index 2bcf63fe50..2fb6cefebd 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala @@ -17,10 +17,10 @@ import io.iohk.ethereum.blockchain.sync.regular.{ import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.blockchain.sync.{PeersClient, SyncProtocol} import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers -import io.iohk.ethereum.consensus.Protocol.NoAdditionalEthashData +import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.{EthashConfig, EthashConsensus} -import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, ethash} +import io.iohk.ethereum.consensus.pow.{EthashConfig, PoWConsensus} +import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, pow} import io.iohk.ethereum.crypto import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger._ @@ -54,13 +54,13 @@ object RegularSyncItSpecUtils { class FakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig) extends CommonFakePeer(peerName, fakePeerCustomConfig) { - def buildEthashConsensus(): ethash.EthashConsensus = { + def buildEthashConsensus(): pow.PoWConsensus = { val consensusConfig: ConsensusConfig = ConsensusConfig(Config.config) - val specificConfig: EthashConfig = ethash.EthashConfig(config) + val specificConfig: EthashConfig = pow.EthashConfig(config) val fullConfig = FullConsensusConfig(consensusConfig, specificConfig) val vm = VmSetup.vm(VmConfig(config), blockchainConfig, testMode = false) val consensus = - EthashConsensus(vm, bl, blockchainConfig, fullConfig, ValidatorsExecutorAlwaysSucceed, NoAdditionalEthashData) + PoWConsensus(vm, bl, blockchainConfig, fullConfig, ValidatorsExecutorAlwaysSucceed, NoAdditionalPoWData) consensus } diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala index 8a7e3725df..d968002f71 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala @@ -49,7 +49,8 @@ class ECIP1017Test extends AnyFlatSpec with Matchers { ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4)) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index a25e8beaf9..e2833fb073 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -48,7 +48,8 @@ class ForksTest extends AnyFlatSpec with Matchers { ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) val noErrors = a[Right[_, Seq[Receipt]]] diff --git a/src/main/resources/conf/base-testnet.conf b/src/main/resources/conf/base-testnet.conf index da560e0280..5e01fd1f22 100644 --- a/src/main/resources/conf/base-testnet.conf +++ b/src/main/resources/conf/base-testnet.conf @@ -18,7 +18,7 @@ mantis { consensus { coinbase = "0011223344556677889900112233445566778899" # has to be changed for each node mining-enabled = false - protocol = "restricted-ethash" + protocol = "restricted-pow" } network { diff --git a/src/main/resources/conf/base.conf b/src/main/resources/conf/base.conf index 4c46174987..3a91847d1f 100644 --- a/src/main/resources/conf/base.conf +++ b/src/main/resources/conf/base.conf @@ -287,9 +287,9 @@ mantis { # Declaring the protocol here means that a more protocol-specific configuration # is pulled from the corresponding consensus implementation. # For example, in case of ethash, a section named `ethash` is used. - # Available protocols: ethash, mocked, restricted-ethash + # Available protocols: pow, mocked, restricted-pow # In case of mocked, remember to enable qa api - protocol = ethash + protocol = pow # If true then the consensus protocol uses this node for mining. # In the case of ethash PoW, this means mining new blocks, as specified by Ethereum. @@ -305,7 +305,7 @@ mantis { # This is the section dedicated to Ethash mining. # This consensus protocol is selected by setting `mantis.consensus.protocol = ethash`. - ethash { + pow { # Maximum number of ommers kept in the pool ommers-pool-size = 30 diff --git a/src/main/resources/conf/chains/etc-chain.conf b/src/main/resources/conf/chains/etc-chain.conf index 8a0ff2ae99..242c7d063c 100644 --- a/src/main/resources/conf/chains/etc-chain.conf +++ b/src/main/resources/conf/chains/etc-chain.conf @@ -96,6 +96,11 @@ # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 ecip1099-block-number = "11700000" + # ECIP-1049 soft fork block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1049 + # https://github.com/ethereumclassic/ECIPs/issues/394 + # ecip1049-block-number = "0" // TODO to be determined + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao { diff --git a/src/main/resources/conf/chains/test-chain.conf b/src/main/resources/conf/chains/test-chain.conf index ca08907701..7a8fec32fd 100644 --- a/src/main/resources/conf/chains/test-chain.conf +++ b/src/main/resources/conf/chains/test-chain.conf @@ -161,7 +161,7 @@ # Set of initial nodes bootstrap-nodes = [] - # List of hex encoded public keys of miners which can extend chain (only used when using restricted-ethash consensus) + # List of hex encoded public keys of miners which can extend chain (only used when using restricted-pow consensus) # empty means that everybody can mine allowed-miners = [] } diff --git a/src/main/resources/conf/chains/testnet-internal-gac-chain.conf b/src/main/resources/conf/chains/testnet-internal-gac-chain.conf index fce927f0cf..497b50f869 100644 --- a/src/main/resources/conf/chains/testnet-internal-gac-chain.conf +++ b/src/main/resources/conf/chains/testnet-internal-gac-chain.conf @@ -145,7 +145,7 @@ # List of hex encoded public keys of Checkpoint Authorities checkpoint-public-keys = [] - # List of hex encoded public keys of miners which can extend chain (only used when using restricted-ethash consensus) + # List of hex encoded public keys of miners which can extend chain (only used when using restricted-pow consensus) # empty means that everybody can mine include "testnet-allowed-miners" } diff --git a/src/main/resources/conf/chains/testnet-internal-nomad-chain.conf b/src/main/resources/conf/chains/testnet-internal-nomad-chain.conf index 2147fcda9a..4e4cc1f8c3 100644 --- a/src/main/resources/conf/chains/testnet-internal-nomad-chain.conf +++ b/src/main/resources/conf/chains/testnet-internal-nomad-chain.conf @@ -157,7 +157,7 @@ "5355fc1bba22b121c3954b0174c8ebfd52efe95e3d062980a916770aec1316c6116a46af591f47f07074f48564cb31c15c90498f2ff9fadf86639e60f3cb2c0d" ] - # List of hex encoded public keys of miners which can extend chain (only used when using restricted-ethash consensus) + # List of hex encoded public keys of miners which can extend chain (only used when using restricted-pow consensus) # empty means that everybody can mine include "testnet-allowed-miners" } diff --git a/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala b/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala index 303ac1c540..166c5b98a8 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.consensus import io.iohk.ethereum.consensus.blocks.{BlockGenerator, TestBlockGenerator} import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.{MinerProtocol, MinerResponse} +import io.iohk.ethereum.consensus.pow.{MinerProtocol, MinerResponse} import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.ledger.BlockPreparator import io.iohk.ethereum.ledger.Ledger.VMImpl diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala index 1bf94498fd..8aff608503 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum.consensus -import io.iohk.ethereum.consensus.Protocol.{NoAdditionalEthashData, RestrictedEthashMinerData} -import io.iohk.ethereum.consensus.ethash.EthashConsensus -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor +import io.iohk.ethereum.consensus.Protocol.{NoAdditionalPoWData, RestrictedPoWMinerData} +import io.iohk.ethereum.consensus.pow.PoWConsensus +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.nodebuilder._ import io.iohk.ethereum.utils.{Config, Logger} @@ -15,7 +15,7 @@ trait ConsensusBuilder { * This is done dynamically when Mantis boots, based on its configuration. * * @see [[io.iohk.ethereum.consensus.Consensus Consensus]], - * [[io.iohk.ethereum.consensus.ethash.EthashConsensus EthashConsensus]], + * [[io.iohk.ethereum.consensus.pow.PoWConsensus PoWConsensus]], */ trait StdConsensusBuilder extends ConsensusBuilder { self: VmBuilder @@ -31,19 +31,19 @@ trait StdConsensusBuilder extends ConsensusBuilder { FullConsensusConfig(consensusConfig, c) //TODO [ETCM-397] refactor configs to avoid possibility of running mocked or - // restricted-ethash consensus on real network like ETC or Mordor - protected def buildEthashConsensus(): ethash.EthashConsensus = { - val specificConfig = ethash.EthashConfig(mantisConfig) + // restricted-pow consensus on real network like ETC or Mordor + protected def buildPoWConsensus(): pow.PoWConsensus = { + val specificConfig = pow.EthashConfig(mantisConfig) val fullConfig = newConfig(specificConfig) val validators = ValidatorsExecutor(blockchainConfig, consensusConfig.protocol) - val additionalEthashData = consensusConfig.protocol match { - case Protocol.Ethash | Protocol.MockedPow => NoAdditionalEthashData - case Protocol.RestrictedEthash => RestrictedEthashMinerData(nodeKey) + val additionalPoWData = consensusConfig.protocol match { + case Protocol.PoW | Protocol.MockedPow => NoAdditionalPoWData + case Protocol.RestrictedPoW => RestrictedPoWMinerData(nodeKey) } - val consensus = EthashConsensus(vm, blockchain, blockchainConfig, fullConfig, validators, additionalEthashData) + val consensus = PoWConsensus(vm, blockchain, blockchainConfig, fullConfig, validators, additionalPoWData) consensus } @@ -53,7 +53,7 @@ trait StdConsensusBuilder extends ConsensusBuilder { val consensus = config.protocol match { - case Protocol.Ethash | Protocol.MockedPow | Protocol.RestrictedEthash => buildEthashConsensus() + case Protocol.PoW | Protocol.MockedPow | Protocol.RestrictedPoW => buildPoWConsensus() } log.info(s"Using '${protocol.name}' consensus [${consensus.getClass.getName}]") diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala index 02868e3a65..46ef5f48af 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala @@ -35,9 +35,9 @@ object ConsensusConfig extends Logger { } final val AllowedProtocols = Set( - Protocol.Names.Ethash, + Protocol.Names.PoW, Protocol.Names.MockedPow, - Protocol.Names.RestrictedEthash + Protocol.Names.RestrictedPoW ) final val AllowedProtocolsError = (s: String) => diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala index 117c4ba3e3..47b3ac2ab3 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala @@ -4,9 +4,9 @@ import io.iohk.ethereum.metrics.MetricsContainer object ConsensusMetrics extends MetricsContainer { private final val blockGenTimer = "consensus.blocks.generate.timer" - final val EthashBlockGeneratorTiming = metrics.timer(blockGenTimer, "class", "EthashBlockGenerator") - final val RestrictedEthashBlockGeneratorTiming = - metrics.timer(blockGenTimer, "class", "RestrictedEthashBlockGenerator") + final val PoWBlockGeneratorTiming = metrics.timer(blockGenTimer, "class", "PoWBlockGenerator") + final val RestrictedPoWBlockGeneratorTiming = + metrics.timer(blockGenTimer, "class", "RestrictedPoWBlockGenerator") final val NoOmmersBlockGeneratorTiming = metrics.timer(blockGenTimer, "class", "NoOmmersBlockGenerator") final val MinedBlockEvaluationTimer = metrics.timer("consensus.minedblocks.evaluation.timer") diff --git a/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala b/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala index d3e5d50780..16ce5d714e 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala @@ -19,11 +19,11 @@ sealed trait Protocol { object Protocol { object Names { // This is the standard Ethereum PoW consensus protocol. - final val Ethash = "ethash" + final val PoW = "pow" final val MockedPow = "mocked" - final val RestrictedEthash = "restricted-ethash" + final val RestrictedPoW = "restricted-pow" } sealed abstract class ProtocolImpl(val name: String) extends Protocol @@ -32,7 +32,7 @@ object Protocol { case object MockedPow extends ProtocolImpl(Names.MockedPow) /** The standard Ethereum PoW consensus protocol. */ - case object Ethash extends ProtocolImpl(Names.Ethash) + case object PoW extends ProtocolImpl(Names.PoW) /** * Non-standard ethereum PoW consensus protocol, which allows restricting list of possible miners. @@ -47,13 +47,13 @@ object Protocol { * c) if public key recovered from correct signature is contained within allowedMinersPublicKeys set defined * for given chain */ - case object RestrictedEthash extends ProtocolImpl(Names.RestrictedEthash) + case object RestrictedPoW extends ProtocolImpl(Names.RestrictedPoW) /** All the known protocols. If a protocol is not put here, then it cannot be used to run Mantis. */ final val KnownProtocols = Set( - Ethash, + PoW, MockedPow, - RestrictedEthash + RestrictedPoW ) final val KnownProtocolNames = KnownProtocols.map(_.name) @@ -65,7 +65,7 @@ object Protocol { throw new IllegalArgumentException("Unknown protocol " + name) } - sealed abstract class AdditionalEthashProtocolData - case object NoAdditionalEthashData extends AdditionalEthashProtocolData - case class RestrictedEthashMinerData(miningNodeKey: AsymmetricCipherKeyPair) extends AdditionalEthashProtocolData + sealed abstract class AdditionalPoWProtocolData + case object NoAdditionalPoWData extends AdditionalPoWProtocolData + case class RestrictedPoWMinerData(miningNodeKey: AsymmetricCipherKeyPair) extends AdditionalPoWProtocolData } diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala index 4df9b00321..5d3bc7011c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala @@ -18,7 +18,7 @@ trait BlockGenerator { /** * The type of consensus-specific data used in the block generation process. - * For example, under [[io.iohk.ethereum.consensus.ethash.EthashConsensus EthashConsensus]], + * For example, under [[io.iohk.ethereum.consensus.pow.PoWConsensus EthashConsensus]], * this represents the [[io.iohk.ethereum.domain.BlockBody#uncleNodesList ommers]]. */ type X diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala index ee16a2a629..b72b137d4f 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala @@ -4,14 +4,14 @@ import java.util.concurrent.atomic.AtomicReference import akka.util.ByteString import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.blocks.Ommers +import io.iohk.ethereum.consensus.pow.blocks.Ommers import io.iohk.ethereum.consensus.validators.std.MptListValidator.intByteArraySerializable import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ -import io.iohk.ethereum.consensus.ethash.blocks.OmmersSeqEnc +import io.iohk.ethereum.consensus.pow.blocks.OmmersSeqEnc import io.iohk.ethereum.ledger.Ledger.{BlockResult, PreparedBlock} import io.iohk.ethereum.ledger.{BlockPreparator, BloomFilter, InMemoryWorldStateProxy} import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} diff --git a/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala index 29552c7e5b..0b5e2d6193 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala @@ -1,6 +1,6 @@ package io.iohk.ethereum.consensus.difficulty -import io.iohk.ethereum.consensus.ethash.difficulty.{TargetTimeDifficultyCalculator, EthashDifficultyCalculator} +import io.iohk.ethereum.consensus.pow.difficulty.{TargetTimeDifficultyCalculator, EthashDifficultyCalculator} import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala deleted file mode 100644 index 726a402653..0000000000 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala +++ /dev/null @@ -1,252 +0,0 @@ -package io.iohk.ethereum.consensus -package ethash - -import java.io.{File, FileInputStream, FileOutputStream} -import akka.actor.{Actor, ActorLogging, ActorRef, Props} -import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.SyncProtocol -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.ethash.EthashUtils.ProofOfWork -import io.iohk.ethereum.consensus.ethash.MinerProtocol.{StartMining, StopMining} -import io.iohk.ethereum.crypto -import io.iohk.ethereum.domain.{BlockHeader, Blockchain} -import io.iohk.ethereum.jsonrpc.{EthInfoService, EthMiningService} -import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateRequest -import io.iohk.ethereum.nodebuilder.Node -import io.iohk.ethereum.utils.BigIntExtensionMethods._ -import io.iohk.ethereum.utils.{ByteStringUtils, ByteUtils} -import monix.execution.Scheduler -import org.bouncycastle.util.encoders.Hex - -import scala.concurrent.duration._ -import scala.util.{Failure, Random, Success, Try} - -/** - * Implementation of Ethash CPU mining worker. - * Could be started by switching configuration flag "consensus.mining-enabled" to true - */ -class EthashMiner( - blockchain: Blockchain, - blockCreator: EthashBlockCreator, - syncController: ActorRef, - ethMiningService: EthMiningService -) extends Actor - with ActorLogging { - - import EthashMiner._ - - private implicit val scheduler: Scheduler = Scheduler(context.dispatcher) - - var currentEpoch: Option[Long] = None - var currentEpochDagSize: Option[Long] = None - var currentEpochDag: Option[Array[Array[Int]]] = None - - override def receive: Receive = stopped - - def stopped: Receive = { - case StartMining => - context become started - self ! ProcessMining - case ProcessMining => // nothing - } - - def started: Receive = { - case StopMining => context become stopped - case ProcessMining => processMining() - } - - def processMining(): Unit = { - blockchain.getBestBlock() match { - case Some(blockValue) => - blockCreator - .getBlockForMining(blockValue) - .map { - case PendingBlockAndState(PendingBlock(block, _), _) => { - val blockNumber = block.header.number.toLong - val epoch = EthashUtils.epoch(blockNumber, blockCreator.blockchainConfig.ecip1099BlockNumber.toLong) - val (dag, dagSize) = calculateDagSize(blockNumber, epoch) - val headerHash = crypto.kec256(BlockHeader.getEncodedWithoutNonce(block.header)) - val startTime = System.nanoTime() - val mineResult = - mine(headerHash, block.header.difficulty.toLong, dagSize, dag, blockCreator.miningConfig.mineRounds) - val time = System.nanoTime() - startTime - //FIXME: consider not reporting hash rate when time delta is zero - val hashRate = if (time > 0) (mineResult.triedHashes.toLong * 1000000000) / time else Long.MaxValue - ethMiningService.submitHashRate(SubmitHashRateRequest(hashRate, ByteString("mantis-miner"))) - mineResult match { - case MiningSuccessful(_, pow, nonce) => - log.info( - s"Mining successful with ${ByteStringUtils.hash2string(pow.mixHash)} and nonce ${ByteStringUtils.hash2string(nonce)}" - ) - syncController ! SyncProtocol.MinedBlock( - block.copy(header = block.header.copy(nonce = nonce, mixHash = pow.mixHash)) - ) - case _ => log.info("Mining unsuccessful") - } - self ! ProcessMining - } - } - .onErrorHandle { ex => - log.error(ex, "Unable to get block for mining") - context.system.scheduler.scheduleOnce(10.seconds, self, ProcessMining) - } - .runAsyncAndForget - case None => { - log.error("Unable to get block for mining, getBestBlock() returned None") - context.system.scheduler.scheduleOnce(10.seconds, self, ProcessMining) - } - } - } - - private def calculateDagSize(blockNumber: Long, epoch: Long): (Array[Array[Int]], Long) = { - (currentEpoch, currentEpochDag, currentEpochDagSize) match { - case (Some(`epoch`), Some(dag), Some(dagSize)) => (dag, dagSize) - case _ => - val seed = EthashUtils.seed(blockNumber) - val dagSize = EthashUtils.dagSize(epoch) - val dagNumHashes = (dagSize / EthashUtils.HASH_BYTES).toInt - val dag = - if (!dagFile(seed).exists()) generateDagAndSaveToFile(epoch, dagNumHashes, seed) - else { - val res = loadDagFromFile(seed, dagNumHashes) - res.failed.foreach { ex => - log.error(ex, "Cannot read DAG from file") - } - res.getOrElse(generateDagAndSaveToFile(epoch, dagNumHashes, seed)) - } - currentEpoch = Some(epoch) - currentEpochDag = Some(dag) - currentEpochDagSize = Some(dagSize) - (dag, dagSize) - } - } - - private def dagFile(seed: ByteString): File = { - new File( - s"${blockCreator.miningConfig.ethashDir}/full-R${EthashUtils.Revision}-${Hex.toHexString(seed.take(8).toArray[Byte])}" - ) - } - - private def generateDagAndSaveToFile(epoch: Long, dagNumHashes: Int, seed: ByteString): Array[Array[Int]] = { - // scalastyle:off magic.number - val file = dagFile(seed) - if (file.exists()) file.delete() - file.getParentFile.mkdirs() - file.createNewFile() - - val outputStream = new FileOutputStream(dagFile(seed).getAbsolutePath) - outputStream.write(DagFilePrefix.toArray[Byte]) - - val cache = EthashUtils.makeCache(epoch, seed) - val res = new Array[Array[Int]](dagNumHashes) - - (0 until dagNumHashes).foreach { i => - val item = EthashUtils.calcDatasetItem(cache, i) - outputStream.write(ByteUtils.intsToBytes(item, bigEndian = false)) - res(i) = item - - if (i % 100000 == 0) log.info(s"Generating DAG ${((i / dagNumHashes.toDouble) * 100).toInt}%") - } - - Try(outputStream.close()) - - res - } - - private def loadDagFromFile(seed: ByteString, dagNumHashes: Int): Try[Array[Array[Int]]] = { - val inputStream = new FileInputStream(dagFile(seed).getAbsolutePath) - - val prefix = new Array[Byte](8) - if (inputStream.read(prefix) != 8 || ByteString(prefix) != DagFilePrefix) { - Failure(new RuntimeException("Invalid DAG file prefix")) - } else { - val buffer = new Array[Byte](64) - val res = new Array[Array[Int]](dagNumHashes) - var index = 0 - - while (inputStream.read(buffer) > 0) { - if (index % 100000 == 0) log.info(s"Loading DAG from file ${((index / res.length.toDouble) * 100).toInt}%") - res(index) = ByteUtils.bytesToInts(buffer, bigEndian = false) - index += 1 - } - - Try(inputStream.close()) - - if (index == dagNumHashes) Success(res) - else Failure(new RuntimeException("DAG file ended unexpectedly")) - } - } - - private def mine( - headerHash: Array[Byte], - difficulty: Long, - dagSize: Long, - dag: Array[Array[Int]], - numRounds: Int - ): MiningResult = { - // scalastyle:off magic.number - val initNonce = BigInt(64, new Random()) - - (0 to numRounds).iterator - .map { n => - val nonce = (initNonce + n) % MaxNonce - val nonceBytes = ByteUtils.padLeft(ByteString(nonce.toUnsignedByteArray), 8) - val pow = EthashUtils.hashimoto(headerHash, nonceBytes.toArray[Byte], dagSize, dag.apply) - (EthashUtils.checkDifficulty(difficulty, pow), pow, nonceBytes, n) - } - .collectFirst { case (true, pow, nonceBytes, n) => MiningSuccessful(n + 1, pow, nonceBytes) } - .getOrElse(MiningUnsuccessful(numRounds)) - } - -} - -object EthashMiner { - final val BlockForgerDispatcherId = "mantis.async.dispatchers.block-forger" - - private[ethash] def props( - blockchain: Blockchain, - blockCreator: EthashBlockCreator, - syncController: ActorRef, - ethInfoService: EthInfoService, - ethMiningService: EthMiningService - ): Props = - Props( - new EthashMiner(blockchain, blockCreator, syncController, ethMiningService) - ).withDispatcher(BlockForgerDispatcherId) - - def apply(node: Node): ActorRef = { - node.consensus match { - case consensus: EthashConsensus => - val blockCreator = new EthashBlockCreator( - pendingTransactionsManager = node.pendingTransactionsManager, - getTransactionFromPoolTimeout = node.txPoolConfig.getTransactionFromPoolTimeout, - consensus = consensus, - ommersPool = node.ommersPool - ) - val minerProps = props( - blockchain = node.blockchain, - blockCreator = blockCreator, - syncController = node.syncController, - ethInfoService = node.ethInfoService, - ethMiningService = node.ethMiningService - ) - node.system.actorOf(minerProps) - case consensus => - wrongConsensusArgument[EthashConsensus](consensus) - } - } - - private case object ProcessMining - - // scalastyle:off magic.number - val MaxNonce: BigInt = BigInt(2).pow(64) - 1 - - val DagFilePrefix: ByteString = ByteString(Array(0xfe, 0xca, 0xdd, 0xba, 0xad, 0xde, 0xe1, 0xfe).map(_.toByte)) - - sealed trait MiningResult { - def triedHashes: Int - } - case class MiningSuccessful(triedHashes: Int, pow: ProofOfWork, nonce: ByteString) extends MiningResult - case class MiningUnsuccessful(triedHashes: Int) extends MiningResult - -} diff --git a/src/main/scala/io/iohk/ethereum/consensus/package.scala b/src/main/scala/io/iohk/ethereum/consensus/package.scala index 98b0a467dd..b8ae309cb4 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/package.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/package.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum import akka.util.ByteString import io.iohk.ethereum.consensus.blocks.BlockGenerator -import io.iohk.ethereum.consensus.ethash.EthashConsensus +import io.iohk.ethereum.consensus.pow.PoWConsensus import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.domain.{Block, BlockHeader} @@ -40,12 +40,12 @@ package object consensus { * There are APIs that expect that the standard Ethash consensus is running and so depend * on either its configuration or general PoW semantics. * This is a method that can handle such cases via a respective if/then/else construct: - * if we run under [[io.iohk.ethereum.consensus.ethash.EthashConsensus EthashConsensus]] + * if we run under [[io.iohk.ethereum.consensus.pow.PoWConsensus EthashConsensus]] * then the `_then` function is called, otherwise the `_else` value is computed. */ - def ifEthash[A](_then: EthashConsensus => A)(_else: => A): A = + def ifEthash[A](_then: PoWConsensus => A)(_else: => A): A = consensus match { - case ethash: EthashConsensus => _then(ethash) + case ethash: PoWConsensus => _then(ethash) case _ => _else } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashBlockCreator.scala similarity index 89% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/EthashBlockCreator.scala index a1ff47f316..bc414a4f78 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashBlockCreator.scala @@ -1,9 +1,9 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.actor.ActorRef import akka.util.ByteString import io.iohk.ethereum.consensus.blocks.PendingBlockAndState -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.domain.{Address, Block} import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.ledger.InMemoryWorldStateProxy @@ -16,7 +16,7 @@ import scala.concurrent.duration.FiniteDuration class EthashBlockCreator( val pendingTransactionsManager: ActorRef, val getTransactionFromPoolTimeout: FiniteDuration, - consensus: EthashConsensus, + consensus: PoWConsensus, ommersPool: ActorRef ) extends TransactionPicker { @@ -24,7 +24,7 @@ class EthashBlockCreator( private lazy val consensusConfig = fullConsensusConfig.generic lazy val miningConfig = fullConsensusConfig.specific private lazy val coinbase: Address = consensusConfig.coinbase - private lazy val blockGenerator: EthashBlockGenerator = consensus.blockGenerator + private lazy val blockGenerator: PoWBlockGenerator = consensus.blockGenerator lazy val blockchainConfig = consensus.blockchainConfig def getBlockForMining( diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConfig.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala similarity index 92% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConfig.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala index c765c6d3dc..718442d484 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConfig.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala @@ -1,6 +1,6 @@ package io.iohk.ethereum package consensus -package ethash +package pow import com.typesafe.config.{Config => TypesafeConfig} @@ -22,7 +22,7 @@ object EthashConfig { } def apply(mantisConfig: TypesafeConfig): EthashConfig = { - val miningConfig = mantisConfig.getConfig(Protocol.Names.Ethash) + val miningConfig = mantisConfig.getConfig(Protocol.Names.PoW) val ommersPoolSize = miningConfig.getInt(Keys.OmmersPoolSize) val ommerPoolQueryTimeout = miningConfig.getDuration(Keys.OmmerPoolQueryTimeout).toMillis.millis diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashDAGManager.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashDAGManager.scala new file mode 100644 index 0000000000..b989e69827 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashDAGManager.scala @@ -0,0 +1,94 @@ +package io.iohk.ethereum.consensus.pow + +import akka.util.ByteString +import io.iohk.ethereum.consensus.pow.EthashMiner.DagFilePrefix +import io.iohk.ethereum.utils.{ByteUtils, Logger} +import org.bouncycastle.util.encoders.Hex + +import java.io.{File, FileInputStream, FileOutputStream} +import scala.util.{Failure, Success, Try} + +class EthashDAGManager(blockCreator: EthashBlockCreator) extends Logger { + var currentEpoch: Option[Long] = None + var currentEpochDagSize: Option[Long] = None + var currentEpochDag: Option[Array[Array[Int]]] = None + + def calculateDagSize(blockNumber: Long, epoch: Long): (Array[Array[Int]], Long) = { + (currentEpoch, currentEpochDag, currentEpochDagSize) match { + case (Some(`epoch`), Some(dag), Some(dagSize)) => (dag, dagSize) + case _ => + val seed = EthashUtils.seed(blockNumber) + val dagSize = EthashUtils.dagSize(epoch) + val dagNumHashes = (dagSize / EthashUtils.HASH_BYTES).toInt + val dag = + if (!dagFile(seed).exists()) generateDagAndSaveToFile(epoch, dagNumHashes, seed) + else { + val res = loadDagFromFile(seed, dagNumHashes) + res.failed.foreach { ex => + log.error("Cannot read DAG from file", ex) + } + res.getOrElse(generateDagAndSaveToFile(epoch, dagNumHashes, seed)) + } + currentEpoch = Some(epoch) + currentEpochDag = Some(dag) + currentEpochDagSize = Some(dagSize) + (dag, dagSize) + } + } + + private def dagFile(seed: ByteString): File = { + new File( + s"${blockCreator.miningConfig.ethashDir}/full-R${EthashUtils.Revision}-${Hex + .toHexString(seed.take(8).toArray[Byte])}" + ) + } + + private def generateDagAndSaveToFile(epoch: Long, dagNumHashes: Int, seed: ByteString): Array[Array[Int]] = { + val file = dagFile(seed) + if (file.exists()) file.delete() + file.getParentFile.mkdirs() + file.createNewFile() + + val outputStream = new FileOutputStream(dagFile(seed).getAbsolutePath) + outputStream.write(DagFilePrefix.toArray[Byte]) + + val cache = EthashUtils.makeCache(epoch, seed) + val res = new Array[Array[Int]](dagNumHashes) + + (0 until dagNumHashes).foreach { i => + val item = EthashUtils.calcDatasetItem(cache, i) + outputStream.write(ByteUtils.intsToBytes(item, bigEndian = false)) + res(i) = item + + if (i % 100000 == 0) log.info(s"Generating DAG ${((i / dagNumHashes.toDouble) * 100).toInt}%") + } + + Try(outputStream.close()) + + res + } + + private def loadDagFromFile(seed: ByteString, dagNumHashes: Int): Try[Array[Array[Int]]] = { + val inputStream = new FileInputStream(dagFile(seed).getAbsolutePath) + + val prefix = new Array[Byte](8) + if (inputStream.read(prefix) != 8 || ByteString(prefix) != DagFilePrefix) { + Failure(new RuntimeException("Invalid DAG file prefix")) + } else { + val buffer = new Array[Byte](64) // scalastyle:ignore magic.number + val res = new Array[Array[Int]](dagNumHashes) + var index = 0 + + while (inputStream.read(buffer) > 0) { + if (index % 100000 == 0) log.info(s"Loading DAG from file ${((index / res.length.toDouble) * 100).toInt}%") + res(index) = ByteUtils.bytesToInts(buffer, bigEndian = false) + index += 1 + } + + Try(inputStream.close()) + + if (index == dagNumHashes) Success(res) + else Failure(new RuntimeException("DAG file ended unexpectedly")) + } + } +} diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashMiner.scala new file mode 100644 index 0000000000..29fea3c582 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashMiner.scala @@ -0,0 +1,205 @@ +package io.iohk.ethereum.consensus +package pow + +import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import akka.util.ByteString +import io.iohk.ethereum.blockchain.sync.SyncProtocol +import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} +import io.iohk.ethereum.consensus.pow.MinerProtocol.{StartMining, StopMining} +import io.iohk.ethereum.crypto +import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain} +import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateRequest +import io.iohk.ethereum.jsonrpc.{EthInfoService, EthMiningService} +import io.iohk.ethereum.nodebuilder.Node +import io.iohk.ethereum.utils.BigIntExtensionMethods._ +import io.iohk.ethereum.utils.{ByteStringUtils, ByteUtils} +import monix.execution.Scheduler + +import scala.concurrent.duration._ +import scala.util.Random + +/** + * Implementation of Ethash CPU mining worker. + * Could be started by switching configuration flag "consensus.mining-enabled" to true + */ +class EthashMiner( + blockchain: Blockchain, + blockCreator: EthashBlockCreator, + syncController: ActorRef, + ethMiningService: EthMiningService, + ecip1049BlockNumber: Option[BigInt] +) extends Actor + with ActorLogging { + + import EthashMiner._ + + private implicit val scheduler: Scheduler = Scheduler(context.dispatcher) + + private val dagManager = new EthashDAGManager(blockCreator) + + override def receive: Receive = stopped + + def stopped: Receive = { + case StartMining => + context become started + self ! ProcessMining + case ProcessMining => // nothing + } + + def started: Receive = { + case StopMining => context become stopped + case ProcessMining => processMining() + } + + def processMining(): Unit = { + blockchain.getBestBlock() match { + case Some(blockValue) => + blockCreator + .getBlockForMining(blockValue) + .map { case PendingBlockAndState(PendingBlock(block, _), _) => + val blockNumber = block.header.number + val (startTime, mineResult) = + // ECIP-1049 //TODO refactoring in ETCM-759 to remove the if clause + if (isKeccak(blockNumber)) doKeccakMining(block, blockCreator.miningConfig.mineRounds) + else doEthashMining(blockNumber.toLong, block) + + val time = System.nanoTime() - startTime + //FIXME: consider not reporting hash rate when time delta is zero + val hashRate = if (time > 0) (mineResult.triedHashes.toLong * 1000000000) / time else Long.MaxValue + ethMiningService.submitHashRate(SubmitHashRateRequest(hashRate, ByteString("mantis-miner"))) + mineResult match { + case MiningSuccessful(_, mixHash, nonce) => + log.info( + s"Mining successful with ${ByteStringUtils.hash2string(mixHash)} and nonce ${ByteStringUtils.hash2string(nonce)}" + ) + syncController ! SyncProtocol.MinedBlock( + block.copy(header = block.header.copy(nonce = nonce, mixHash = mixHash)) + ) + case _ => log.info("Mining unsuccessful") + } + self ! ProcessMining + } + .onErrorHandle { ex => + log.error(ex, "Unable to get block for mining") + context.system.scheduler.scheduleOnce(10.seconds, self, ProcessMining) + } + .runAsyncAndForget + case None => + log.error("Unable to get block for mining, getBestBlock() returned None") + context.system.scheduler.scheduleOnce(10.seconds, self, ProcessMining) + } + } + + private def isKeccak(currentBlockNumber: BigInt): Boolean = { + ecip1049BlockNumber match { + case None => false + case Some(blockNumber) => currentBlockNumber >= blockNumber + } + } + + private def doEthashMining(blockNumber: Long, block: Block): (Long, MiningResult) = { + val epoch = + EthashUtils.epoch(blockNumber, blockCreator.blockchainConfig.ecip1099BlockNumber.toLong) + val (dag, dagSize) = dagManager.calculateDagSize(blockNumber, epoch) + val headerHash = crypto.kec256(BlockHeader.getEncodedWithoutNonce(block.header)) + val startTime = System.nanoTime() + val mineResult = + mineEthah(headerHash, block.header.difficulty.toLong, dagSize, dag, blockCreator.miningConfig.mineRounds) + (startTime, mineResult) + } + + private def doKeccakMining(block: Block, numRounds: Int): (Long, MiningResult) = { + val rlpEncodedHeader = BlockHeader.getEncodedWithoutNonce(block.header) + val initNonce = BigInt(64, new Random()) // scalastyle:ignore magic.number + val startTime = System.nanoTime() + + val mined = (0 to numRounds).iterator + .map { round => + val nonce = (initNonce + round) % MaxNonce + val difficulty = block.header.difficulty + val hash = KeccakCalculation.hash(rlpEncodedHeader, nonce) + (KeccakCalculation.isMixHashValid(hash.mixHash, difficulty), hash, nonce, round) + } + .collectFirst { case (true, hash, nonce, n) => + val nonceBytes = ByteString(ByteUtils.bigIntToUnsignedByteArray(nonce)) + MiningSuccessful(n + 1, ByteString(hash.mixHash), nonceBytes) + } + .getOrElse(MiningUnsuccessful(numRounds)) + + (startTime, mined) + } + + private def mineEthah( + headerHash: Array[Byte], + difficulty: Long, + dagSize: Long, + dag: Array[Array[Int]], + numRounds: Int + ): MiningResult = { + val initNonce = BigInt(64, new Random()) // scalastyle:ignore magic.number + + (0 to numRounds).iterator + .map { n => + val nonce = (initNonce + n) % MaxNonce + val nonceBytes = ByteUtils.padLeft(ByteString(nonce.toUnsignedByteArray), 8) + val pow = EthashUtils.hashimoto(headerHash, nonceBytes.toArray[Byte], dagSize, dag.apply) + (EthashUtils.checkDifficulty(difficulty, pow), pow, nonceBytes, n) + } + .collectFirst { case (true, pow, nonceBytes, n) => MiningSuccessful(n + 1, pow.mixHash, nonceBytes) } + .getOrElse(MiningUnsuccessful(numRounds)) + } +} + +object EthashMiner { + final val BlockForgerDispatcherId = "mantis.async.dispatchers.block-forger" + + private[pow] def props( + blockchain: Blockchain, + blockCreator: EthashBlockCreator, + syncController: ActorRef, + ethInfoService: EthInfoService, + ethMiningService: EthMiningService, + ecip1049BlockNumber: Option[BigInt] + ): Props = + Props( + new EthashMiner(blockchain, blockCreator, syncController, ethMiningService, ecip1049BlockNumber) + ).withDispatcher(BlockForgerDispatcherId) + + def apply(node: Node): ActorRef = { + node.consensus match { + case consensus: PoWConsensus => + val blockCreator = new EthashBlockCreator( + pendingTransactionsManager = node.pendingTransactionsManager, + getTransactionFromPoolTimeout = node.txPoolConfig.getTransactionFromPoolTimeout, + consensus = consensus, + ommersPool = node.ommersPool + ) + val minerProps = props( + blockchain = node.blockchain, + blockCreator = blockCreator, + syncController = node.syncController, + ethInfoService = node.ethInfoService, + ethMiningService = node.ethMiningService, + ecip1049BlockNumber = node.blockchainConfig.ecip1049BlockNumber + ) + node.system.actorOf(minerProps) + case consensus => + wrongConsensusArgument[PoWConsensus](consensus) + } + } + + private case object ProcessMining + + // scalastyle:off magic.number + val MaxNonce: BigInt = BigInt(2).pow(64) - 1 + + val DagFilePrefix: ByteString = ByteString(Array(0xfe, 0xca, 0xdd, 0xba, 0xad, 0xde, 0xe1, 0xfe).map(_.toByte)) + + sealed trait MiningResult { + def triedHashes: Int + } + + case class MiningSuccessful(triedHashes: Int, mixHash: ByteString, nonce: ByteString) extends MiningResult + case class MiningUnsuccessful(triedHashes: Int) extends MiningResult + +} diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala similarity index 95% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala index db8fb9f823..b49a7edc90 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala @@ -1,5 +1,5 @@ package io.iohk.ethereum.consensus -package ethash +package pow import java.math.BigInteger import java.util @@ -15,7 +15,7 @@ import scala.annotation.tailrec object EthashUtils { - // Revision number of https://github.com/ethereum/wiki/wiki/Ethash + // Revision number of https://eth.wiki/concepts/ethash/ethash final val Revision: Int = 23 // scalastyle:off magic.number @@ -134,7 +134,7 @@ object EthashUtils { nonce: Array[Byte], fullSize: Long, cache: Array[Int] - ): ProofOfWork = { + ): EthashProofOfWork = { hashimoto(hashWithoutNonce, nonce, fullSize, (calcDatasetItem _).curried(cache)) } @@ -143,7 +143,7 @@ object EthashUtils { nonce: Array[Byte], fullSize: Long, datasetLookup: Int => Array[Int] - ): ProofOfWork = { + ): EthashProofOfWork = { /* watch out, arrays are mutable here */ val wHash = MIX_BYTES / WORD_BYTES val mixHashes = MIX_BYTES / HASH_BYTES @@ -182,7 +182,7 @@ object EthashUtils { val cmix = new Array[Int](mix.length / 4) compressMix(mix, cmix) - ProofOfWork( + EthashProofOfWork( mixHash = ByteString(intsToBytes(cmix, bigEndian = false)), difficultyBoundary = ByteString(kec256(intsToBytes(s, bigEndian = false) ++ intsToBytes(cmix, bigEndian = false))) ) @@ -240,7 +240,7 @@ object EthashUtils { (v1 * FNV_PRIME) ^ v2 } - private[ethash] def checkDifficulty(blockDifficulty: Long, proofOfWork: ProofOfWork): Boolean = { + private[pow] def checkDifficulty(blockDifficulty: Long, proofOfWork: EthashProofOfWork): Boolean = { @tailrec def compare(a1: Array[Byte], a2: Array[Byte]): Int = { if (a1.length > a2.length) 1 @@ -259,5 +259,5 @@ object EthashUtils { compare(headerDifficultyAsByteArray, proofOfWork.difficultyBoundary.toArray[Byte]) >= 0 } - case class ProofOfWork(mixHash: ByteString, difficultyBoundary: ByteString) + case class EthashProofOfWork(mixHash: ByteString, difficultyBoundary: ByteString) } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala new file mode 100644 index 0000000000..1124a3ff0a --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala @@ -0,0 +1,37 @@ +package io.iohk.ethereum.consensus.pow + +import akka.util.ByteString +import io.iohk.ethereum.crypto.{kec256, kec256PoW} +import io.iohk.ethereum.utils.ByteUtils + +object KeccakCalculation { + + final val difficultyNumerator: BigInt = BigInt(2).pow(256) + + /** + * Computation of mixHash = keccak256(keccak256(rlp(unsealed header)), nonce) + * @param hashHeader the rlp(unsealed header) + * @return KeccakProofOWork containing the computed mixHash + */ + def hash(hashHeader: Array[Byte], nonce: BigInt): KeccakMixHash = { + val preHash = ByteString(kec256(hashHeader)).toArray + val nonceBytes = ByteUtils.bigIntToUnsignedByteArray(nonce) + val mixHash = kec256PoW(preHash, nonceBytes) + + KeccakMixHash(mixHash = ByteString(mixHash)) + } + + /** + * Validates if mixHash <= 2^256 / difficulty + * @param mixHash + * @param difficulty + * @return boolean indicating whether PoW is valid or not + */ + def isMixHashValid(mixHash: ByteString, difficulty: BigInt): Boolean = { + val mixHashInt = BigInt.apply(mixHash.toArray) + val threshold = difficultyNumerator / difficulty + mixHashInt <= threshold + } + + final case class KeccakMixHash(mixHash: ByteString) +} diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/MinerProtocol.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/MinerProtocol.scala similarity index 94% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/MinerProtocol.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/MinerProtocol.scala index 27f0e79d8f..875cf43c69 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/MinerProtocol.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/MinerProtocol.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.util.ByteString diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/MinerUtils.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/MinerUtils.scala similarity index 62% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/MinerUtils.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/MinerUtils.scala index feb8aa7a57..8c3b0eb403 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/MinerUtils.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/MinerUtils.scala @@ -1,7 +1,7 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.actor.Actor -import io.iohk.ethereum.consensus.ethash.MinerResponses.MinerNotSupport +import io.iohk.ethereum.consensus.pow.MinerResponses.MinerNotSupport trait MinerUtils { self: Actor => diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/MockedMiner.scala similarity index 89% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/MockedMiner.scala index 582cd53d3b..be6ed4523c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/MockedMiner.scala @@ -1,13 +1,13 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.actor.Status.Failure import akka.actor.{Actor, ActorLogging, ActorRef, Props} import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.consensus.blocks.PendingBlockAndState -import io.iohk.ethereum.consensus.ethash.MinerProtocol.{StartMining, StopMining} -import io.iohk.ethereum.consensus.ethash.MinerResponses.{MinerIsWorking, MiningError, MiningOrdered} -import io.iohk.ethereum.consensus.ethash.MockedMiner.MineBlock -import io.iohk.ethereum.consensus.ethash.MockedMinerProtocol.MineBlocks +import io.iohk.ethereum.consensus.pow.MinerProtocol.{StartMining, StopMining} +import io.iohk.ethereum.consensus.pow.MinerResponses.{MinerIsWorking, MiningError, MiningOrdered} +import io.iohk.ethereum.consensus.pow.MockedMiner.MineBlock +import io.iohk.ethereum.consensus.pow.MockedMinerProtocol.MineBlocks import io.iohk.ethereum.consensus.wrongConsensusArgument import io.iohk.ethereum.domain.{Block, Blockchain} import io.iohk.ethereum.ledger.InMemoryWorldStateProxy @@ -97,7 +97,7 @@ object MockedMiner { case object MineBlock - private[ethash] def props( + private[pow] def props( blockchain: Blockchain, blockCreator: EthashBlockCreator, syncEventListener: ActorRef @@ -112,7 +112,7 @@ object MockedMiner { def apply(node: Node): ActorRef = { node.consensus match { - case consensus: EthashConsensus => + case consensus: PoWConsensus => val blockCreator = new EthashBlockCreator( pendingTransactionsManager = node.pendingTransactionsManager, getTransactionFromPoolTimeout = node.txPoolConfig.getTransactionFromPoolTimeout, @@ -126,7 +126,7 @@ object MockedMiner { ) node.system.actorOf(minerProps) case consensus => - wrongConsensusArgument[EthashConsensus](consensus) + wrongConsensusArgument[PoWConsensus](consensus) } } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala similarity index 81% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala index 16e6cfe121..68addb4738 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala @@ -1,20 +1,16 @@ package io.iohk.ethereum package consensus -package ethash +package pow import akka.actor.ActorRef import akka.util.Timeout import io.iohk.ethereum.consensus.Protocol._ import io.iohk.ethereum.consensus.blocks.TestBlockGenerator import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.MinerResponses.MinerNotExist -import io.iohk.ethereum.consensus.ethash.blocks.{ - EthashBlockGenerator, - EthashBlockGeneratorImpl, - RestrictedEthashBlockGeneratorImpl -} +import io.iohk.ethereum.consensus.pow.MinerResponses.MinerNotExist +import io.iohk.ethereum.consensus.pow.blocks.{PoWBlockGenerator, PoWBlockGeneratorImpl, RestrictedPoWBlockGeneratorImpl} +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor import io.iohk.ethereum.domain.BlockchainImpl import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.ledger.BlockPreparator @@ -26,15 +22,15 @@ import monix.eval.Task import scala.concurrent.duration._ /** - * Implements standard Ethereum consensus (ethash PoW). + * Implements standard Ethereum consensus (Proof of Work). */ -class EthashConsensus private ( +class PoWConsensus private ( val vm: VMImpl, blockchain: BlockchainImpl, val blockchainConfig: BlockchainConfig, val config: FullConsensusConfig[EthashConfig], val validators: ValidatorsExecutor, - val blockGenerator: EthashBlockGenerator, + val blockGenerator: PoWBlockGenerator, val difficultyCalculator: DifficultyCalculator ) extends TestConsensus with Logger { @@ -74,7 +70,7 @@ class EthashConsensus private ( mutex.synchronized { if (minerRef.isEmpty) { val miner = config.generic.protocol match { - case Ethash | RestrictedEthash => EthashMiner(node) + case PoW | RestrictedPoW => EthashMiner(node) case MockedPow => MockedMiner(node) } minerRef = Some(miner) @@ -108,10 +104,10 @@ class EthashConsensus private ( } } - def protocol: Protocol = Protocol.Ethash + def protocol: Protocol = Protocol.PoW /** Internal API, used for testing */ - protected def newBlockGenerator(validators: Validators): EthashBlockGenerator = { + protected def newBlockGenerator(validators: Validators): PoWBlockGenerator = { validators match { case _validators: ValidatorsExecutor => val blockPreparator = new BlockPreparator( @@ -121,7 +117,7 @@ class EthashConsensus private ( blockchainConfig = blockchainConfig ) - new EthashBlockGeneratorImpl( + new PoWBlockGeneratorImpl( validators = _validators, blockchain = blockchain, blockchainConfig = blockchainConfig, @@ -137,12 +133,12 @@ class EthashConsensus private ( } /** Internal API, used for testing */ - def withValidators(validators: Validators): EthashConsensus = { + def withValidators(validators: Validators): PoWConsensus = { validators match { case _validators: ValidatorsExecutor => val blockGenerator = newBlockGenerator(validators) - new EthashConsensus( + new PoWConsensus( vm = vm, blockchain = blockchain, blockchainConfig = blockchainConfig, @@ -157,8 +153,8 @@ class EthashConsensus private ( } } - def withVM(vm: VMImpl): EthashConsensus = - new EthashConsensus( + def withVM(vm: VMImpl): PoWConsensus = + new PoWConsensus( vm = vm, blockchain = blockchain, blockchainConfig = blockchainConfig, @@ -169,28 +165,28 @@ class EthashConsensus private ( ) /** Internal API, used for testing */ - def withBlockGenerator(blockGenerator: TestBlockGenerator): EthashConsensus = - new EthashConsensus( + def withBlockGenerator(blockGenerator: TestBlockGenerator): PoWConsensus = + new PoWConsensus( vm = vm, blockchain = blockchain, blockchainConfig = blockchainConfig, config = config, validators = validators, - blockGenerator = blockGenerator.asInstanceOf[EthashBlockGenerator], + blockGenerator = blockGenerator.asInstanceOf[PoWBlockGenerator], difficultyCalculator ) } -object EthashConsensus { +object PoWConsensus { def apply( vm: VMImpl, blockchain: BlockchainImpl, blockchainConfig: BlockchainConfig, config: FullConsensusConfig[EthashConfig], validators: ValidatorsExecutor, - additionalEthashProtocolData: AdditionalEthashProtocolData - ): EthashConsensus = { + additionalEthashProtocolData: AdditionalPoWProtocolData + ): PoWConsensus = { val difficultyCalculator = DifficultyCalculator(blockchainConfig) @@ -202,8 +198,8 @@ object EthashConsensus { ) val blockGenerator = additionalEthashProtocolData match { - case RestrictedEthashMinerData(key) => - new RestrictedEthashBlockGeneratorImpl( + case RestrictedPoWMinerData(key) => + new RestrictedPoWBlockGeneratorImpl( validators = validators, blockchain = blockchain, blockchainConfig = blockchainConfig, @@ -213,8 +209,8 @@ object EthashConsensus { minerKeyPair = key ) - case NoAdditionalEthashData => - new EthashBlockGeneratorImpl( + case NoAdditionalPoWData => + new PoWBlockGeneratorImpl( validators = validators, blockchain = blockchain, blockchainConfig = blockchainConfig, @@ -224,7 +220,7 @@ object EthashConsensus { ) } - new EthashConsensus( + new PoWConsensus( vm = vm, blockchain = blockchain, blockchainConfig = blockchainConfig, diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala similarity index 94% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala index f27cc3f058..b568b6e15b 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.util.ByteString import io.iohk.ethereum.crypto @@ -7,7 +7,7 @@ import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.getEncodedWithoutNonce import org.bouncycastle.crypto.AsymmetricCipherKeyPair -object RestrictedEthashSigner { +object RestrictedPoWSigner { def validateSignature(blockHeader: BlockHeader, allowedMiners: Set[ByteString]): Boolean = { val signature = blockHeader.extraData.takeRight(ECDSASignature.EncodedLength) diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala similarity index 88% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala index 020d9255ee..130abfbf26 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala @@ -1,19 +1,19 @@ -package io.iohk.ethereum.consensus.ethash.blocks +package io.iohk.ethereum.consensus.pow.blocks import java.util.function.UnaryOperator import akka.util.ByteString import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks._ import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.consensus.ConsensusMetrics -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor /** Internal API, used for testing (especially mocks) */ -trait EthashBlockGenerator extends TestBlockGenerator { +trait PoWBlockGenerator extends TestBlockGenerator { type X = Ommers /** An empty `X` */ @@ -22,7 +22,7 @@ trait EthashBlockGenerator extends TestBlockGenerator { def getPrepared(powHeaderHash: ByteString): Option[PendingBlock] } -class EthashBlockGeneratorImpl( +class PoWBlockGeneratorImpl( validators: ValidatorsExecutor, blockchain: Blockchain, blockchainConfig: BlockchainConfig, @@ -37,7 +37,7 @@ class EthashBlockGeneratorImpl( difficultyCalc, blockTimestampProvider ) - with EthashBlockGenerator { + with PoWBlockGenerator { protected def newBlockBody(transactions: Seq[SignedTransaction], x: Ommers): BlockBody = BlockBody(transactions, x) @@ -75,7 +75,7 @@ class EthashBlockGeneratorImpl( beneficiary: Address, x: Ommers, initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] - ): PendingBlockAndState = ConsensusMetrics.EthashBlockGeneratorTiming.record { () => + ): PendingBlockAndState = ConsensusMetrics.PoWBlockGeneratorTiming.record { () => val pHeader = parent.header val blockNumber = pHeader.number + 1 val parentHash = pHeader.hash @@ -102,8 +102,8 @@ class EthashBlockGeneratorImpl( prepared } - def withBlockTimestampProvider(blockTimestampProvider: BlockTimestampProvider): EthashBlockGeneratorImpl = - new EthashBlockGeneratorImpl( + def withBlockTimestampProvider(blockTimestampProvider: BlockTimestampProvider): PoWBlockGeneratorImpl = + new PoWBlockGeneratorImpl( validators, blockchain, blockchainConfig, diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/RestrictedEthashBlockGeneratorImpl.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala similarity index 82% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/RestrictedEthashBlockGeneratorImpl.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala index 7b8f16d0d3..04635c2939 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/RestrictedEthashBlockGeneratorImpl.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala @@ -1,17 +1,17 @@ -package io.iohk.ethereum.consensus.ethash.blocks +package io.iohk.ethereum.consensus.pow.blocks import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, DefaultBlockTimestampProvider, PendingBlockAndState} import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner +import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.domain.{Address, Block, Blockchain, SignedTransaction} import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} import io.iohk.ethereum.utils.BlockchainConfig import org.bouncycastle.crypto.AsymmetricCipherKeyPair import io.iohk.ethereum.consensus.ConsensusMetrics -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor -class RestrictedEthashBlockGeneratorImpl( +class RestrictedPoWBlockGeneratorImpl( validators: ValidatorsExecutor, blockchain: Blockchain, blockchainConfig: BlockchainConfig, @@ -20,7 +20,7 @@ class RestrictedEthashBlockGeneratorImpl( difficultyCalc: DifficultyCalculator, minerKeyPair: AsymmetricCipherKeyPair, blockTimestampProvider: BlockTimestampProvider = DefaultBlockTimestampProvider -) extends EthashBlockGeneratorImpl( +) extends PoWBlockGeneratorImpl( validators, blockchain, blockchainConfig, @@ -36,7 +36,7 @@ class RestrictedEthashBlockGeneratorImpl( beneficiary: Address, ommers: Ommers, initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] - ): PendingBlockAndState = ConsensusMetrics.RestrictedEthashBlockGeneratorTiming.record { () => + ): PendingBlockAndState = ConsensusMetrics.RestrictedPoWBlockGeneratorTiming.record { () => val pHeader = parent.header val blockNumber = pHeader.number + 1 val parentHash = pHeader.hash @@ -55,7 +55,7 @@ class RestrictedEthashBlockGeneratorImpl( initialWorldStateBeforeExecution ) val preparedHeader = prepared.pendingBlock.block.header - val headerWithAdditionalExtraData = RestrictedEthashSigner.signHeader(preparedHeader, minerKeyPair) + val headerWithAdditionalExtraData = RestrictedPoWSigner.signHeader(preparedHeader, minerKeyPair) val modifiedPrepared = prepared.copy(pendingBlock = prepared.pendingBlock.copy(block = prepared.pendingBlock.block.copy(header = headerWithAdditionalExtraData)) ) diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/package.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala similarity index 80% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/package.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala index 5927c44ee0..cba459629c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/package.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeaderImplicits._ @@ -9,7 +9,7 @@ package object blocks { /** * This is type `X` in `BlockGenerator`. * - * @see [[io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator EthashBlockGenerator]], + * @see [[io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator EthashBlockGenerator]], * [[io.iohk.ethereum.consensus.blocks.BlockGenerator.X BlockGenerator{ type X}]] */ final type Ommers = Seq[BlockHeader] diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/EthashDifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala similarity index 98% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/EthashDifficultyCalculator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala index 6738ece5f3..48409d097e 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/EthashDifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash.difficulty +package io.iohk.ethereum.consensus.pow.difficulty import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.domain.BlockHeader diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/TargetTimeDifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala similarity index 96% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/TargetTimeDifficultyCalculator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala index 325b36c7de..7411271451 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/difficulty/TargetTimeDifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash.difficulty +package io.iohk.ethereum.consensus.pow.difficulty import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.domain.BlockHeader diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala similarity index 77% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala index ab6e2e205f..7c38135673 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala @@ -1,10 +1,9 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow package validators import akka.util.ByteString -import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} +import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid} import io.iohk.ethereum.crypto import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig @@ -13,27 +12,21 @@ import monix.execution.atomic.{Atomic, AtomicAny} /** * A block header validator for Ethash. */ -class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) - extends BlockHeaderValidatorSkeleton(blockchainConfig) { +class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) { import EthashBlockHeaderValidator._ // NOTE the below comment is from before PoW decoupling // we need atomic since validators can be used from multiple places protected val powCaches: AtomicAny[List[PowCacheData]] = Atomic(List.empty[PowCacheData]) - protected def difficulty: DifficultyCalculator = DifficultyCalculator(blockchainConfig) - - def validateEvenMore(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = - validatePoW(blockHeader) - /** * Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. - * @return BlockHeader if valid, an [[io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError]] otherwise + * @return BlockHeaderValid if valid or an BlockHeaderError.HeaderPoWError otherwise */ - protected def validatePoW(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + def validateHeader(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { import EthashUtils._ def getPowCacheData(epoch: Long, seed: ByteString): PowCacheData = { diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala new file mode 100644 index 0000000000..0b939fe0a6 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala @@ -0,0 +1,24 @@ +package io.iohk.ethereum.consensus.pow.validators + +import io.iohk.ethereum.consensus.pow.KeccakCalculation +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid} +import io.iohk.ethereum.domain.BlockHeader + +object KeccakBlockHeaderValidator { + + /** + * Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct + * @param blockHeader + * @return BlockHeaderValid if valid or an BlockHeaderError.HeaderPoWError otherwise + */ + def validateHeader(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + val rlpEncodedHeader = BlockHeader.getEncodedWithoutNonce(blockHeader) + val expectedHash = KeccakCalculation.hash(rlpEncodedHeader, BigInt(blockHeader.nonce.toArray)) + + lazy val isDifficultyValid = KeccakCalculation.isMixHashValid(blockHeader.mixHash, blockHeader.difficulty) + + if (expectedHash.mixHash == blockHeader.mixHash && isDifficultyValid) Right(BlockHeaderValid) + else Left(HeaderPoWError) + } +} diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/MockedPowBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala similarity index 93% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/validators/MockedPowBlockHeaderValidator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala index d2f5a59d77..5b36855e39 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/MockedPowBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow package validators import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/OmmersValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala similarity index 91% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/validators/OmmersValidator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala index b1aa0d838d..5f7c276f26 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/OmmersValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala @@ -1,7 +1,7 @@ -package io.iohk.ethereum.consensus.ethash.validators +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.{OmmersError, OmmersValid} +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.{OmmersError, OmmersValid} import io.iohk.ethereum.consensus.validators.BlockHeaderError import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain} diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala new file mode 100644 index 0000000000..db115632ba --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala @@ -0,0 +1,33 @@ +package io.iohk.ethereum.consensus.pow.validators + +import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator +import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.utils.BlockchainConfig + +class PoWBlockHeaderValidator(blockchainConfig: BlockchainConfig) + extends BlockHeaderValidatorSkeleton(blockchainConfig) { + + /** + * The difficulty calculator. This is specific to the consensus protocol. + */ + override protected def difficulty: DifficultyCalculator = DifficultyCalculator(blockchainConfig) + + private val ethashBlockHeaderValidator = new EthashBlockHeaderValidator(blockchainConfig) + + /** + * A hook where even more consensus-specific validation can take place. + * For example, PoW validation is done here. + */ + override protected[validators] def validateEvenMore( + blockHeader: BlockHeader + ): Either[BlockHeaderError, BlockHeaderValid] = + if (isKeccak(blockHeader.number)) KeccakBlockHeaderValidator.validateHeader(blockHeader) + else ethashBlockHeaderValidator.validateHeader(blockHeader) + + private def isKeccak(currentBlockNumber: BigInt): Boolean = + blockchainConfig.ecip1049BlockNumber match { + case Some(keccakBlock) => currentBlockNumber >= keccakBlock + case None => false + } +} diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala similarity index 69% rename from src/main/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala index 3ff1246fba..fafb83acbe 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala @@ -1,15 +1,15 @@ -package io.iohk.ethereum.consensus.ethash.validators +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner -import io.iohk.ethereum.consensus.validators.BlockHeaderError.RestrictedEthashHeaderExtraDataError +import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner +import io.iohk.ethereum.consensus.validators.BlockHeaderError.RestrictedPoWHeaderExtraDataError import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator} import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig class RestrictedEthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) - extends EthashBlockHeaderValidator(blockchainConfig) { + extends PoWBlockHeaderValidator(blockchainConfig) { val ExtraDataMaxSize = BlockHeaderValidator.MaxExtraDataSize + ECDSASignature.EncodedLength @@ -17,15 +17,15 @@ class RestrictedEthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) blockHeader: BlockHeader, allowedMiners: Set[ByteString] ): Either[BlockHeaderError, BlockHeaderValid] = { - val emptyOrValid = allowedMiners.isEmpty || RestrictedEthashSigner.validateSignature(blockHeader, allowedMiners) - Either.cond(emptyOrValid, BlockHeaderValid, RestrictedEthashHeaderExtraDataError) + val emptyOrValid = allowedMiners.isEmpty || RestrictedPoWSigner.validateSignature(blockHeader, allowedMiners) + Either.cond(emptyOrValid, BlockHeaderValid, RestrictedPoWHeaderExtraDataError) } override protected def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { val tooLargeExtraData = blockHeader.extraData.length > ExtraDataMaxSize if (tooLargeExtraData) { - Left(RestrictedEthashHeaderExtraDataError) + Left(RestrictedPoWHeaderExtraDataError) } else { validateSignatureAgainstAllowedMiners(blockHeader, blockchainConfig.allowedMinersPublicKeys) } diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala similarity index 93% rename from src/main/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidator.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala index 22f93a8247..5661627ae2 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala @@ -1,9 +1,8 @@ -package io.iohk.ethereum.consensus.validators.std +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersError._ -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.{OmmersError, OmmersValid} +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError._ +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.{OmmersError, OmmersValid} import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator} import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} import io.iohk.ethereum.domain.BlockHeader @@ -29,8 +28,8 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm * @param getBlockHeaderByHash function to obtain an ancestor block header by hash * @param getNBlocksBack function to obtain N blocks including one given by hash and its N-1 ancestors * - * @return [[io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersValid]] if valid, - * an [[io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersError]] otherwise + * @return [[io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersValid]] if valid, + * an [[io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError]] otherwise */ def validate( parentHash: ByteString, @@ -93,7 +92,7 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm * @return [[OmmersValidator.OmmersValid]] if valid, an [[OmmersValidator.OmmersError.OmmerIsAncestorError]] or * [[OmmersValidator.OmmersError.OmmerParentIsNotAncestorError]] otherwise */ - private[std] def validateOmmersAncestors( + private[validators] def validateOmmersAncestors( parentHash: ByteString, blockNumber: BigInt, ommers: Seq[BlockHeader], diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidatorsExecutor.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala similarity index 68% rename from src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidatorsExecutor.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala index 7b67bab94d..2108312ad8 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidatorsExecutor.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala @@ -1,14 +1,13 @@ -package io.iohk.ethereum.consensus.validators.std +package io.iohk.ethereum.consensus.pow.validators -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator import io.iohk.ethereum.consensus.validators.{BlockHeaderValidator, BlockValidator, SignedTransactionValidator} /** * Implements validators that adhere to the PoW-specific - * [[ValidatorsExecutor]] + * [[io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor]] * interface. */ -final class StdValidatorsExecutor private[std] ( +final class StdValidatorsExecutor private[validators] ( val blockValidator: BlockValidator, val blockHeaderValidator: BlockHeaderValidator, val signedTransactionValidator: SignedTransactionValidator, diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/ValidatorsExecutor.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala similarity index 89% rename from src/main/scala/io/iohk/ethereum/consensus/validators/std/ValidatorsExecutor.scala rename to src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala index f867c7e4ff..ad40ad2fc6 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/ValidatorsExecutor.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala @@ -1,14 +1,9 @@ -package io.iohk.ethereum.consensus.validators.std +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.validators.{ - EthashBlockHeaderValidator, - MockedPowBlockHeaderValidator, - OmmersValidator, - RestrictedEthashBlockHeaderValidator -} -import io.iohk.ethereum.consensus.validators.{BlockHeaderValidator, Validators} import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack, Protocol} +import io.iohk.ethereum.consensus.validators.std.{StdBlockValidator, StdSignedTransactionValidator, StdValidators} +import io.iohk.ethereum.consensus.validators.{BlockHeaderValidator, Validators} import io.iohk.ethereum.domain.{Block, Receipt} import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError import io.iohk.ethereum.ledger.{BlockExecutionError, BlockExecutionSuccess} @@ -52,8 +47,8 @@ object ValidatorsExecutor { def apply(blockchainConfig: BlockchainConfig, protocol: Protocol): ValidatorsExecutor = { val blockHeaderValidator: BlockHeaderValidator = protocol match { case Protocol.MockedPow => new MockedPowBlockHeaderValidator(blockchainConfig) - case Protocol.Ethash => new EthashBlockHeaderValidator(blockchainConfig) - case Protocol.RestrictedEthash => new RestrictedEthashBlockHeaderValidator(blockchainConfig) + case Protocol.PoW => new PoWBlockHeaderValidator(blockchainConfig) + case Protocol.RestrictedPoW => new RestrictedEthashBlockHeaderValidator(blockchainConfig) } new StdValidatorsExecutor( diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala index 668c876112..9627f3c518 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala @@ -29,7 +29,7 @@ sealed trait BlockHeaderError object BlockHeaderError { case object HeaderParentNotFoundError extends BlockHeaderError case object HeaderExtraDataError extends BlockHeaderError - case object RestrictedEthashHeaderExtraDataError extends BlockHeaderError + case object RestrictedPoWHeaderExtraDataError extends BlockHeaderError case object DaoHeaderExtraDataError extends BlockHeaderError case object HeaderTimestampError extends BlockHeaderError case object HeaderDifficultyError extends BlockHeaderError diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala index e05154e270..f54d1f9930 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala @@ -1,7 +1,7 @@ package io.iohk.ethereum.consensus.validators.std import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.blocks.OmmersSeqEnc +import io.iohk.ethereum.consensus.pow.blocks.OmmersSeqEnc import io.iohk.ethereum.consensus.validators.BlockValidator import io.iohk.ethereum.crypto._ import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, Receipt, SignedTransaction} diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala index f06d9bd21f..3c3238f377 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala @@ -12,7 +12,7 @@ import org.bouncycastle.util.encoders.Hex * Implements validators that adhere to the original [[io.iohk.ethereum.consensus.validators.Validators Validators]] * interface. * - * @see [[StdValidatorsExecutor StdEthashValidators]] + * @see [[io.iohk.ethereum.consensus.pow.validators.StdValidatorsExecutor StdEthashValidators]] * for the PoW-specific counterpart. */ final class StdValidators( diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala index c0839e7bd4..91d1d791fd 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString import cats.implicits._ -import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner +import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import io.iohk.ethereum.utils.ByteStringUtils @@ -75,7 +75,7 @@ object BlockResponse { val signatureStr = signature.map(_.toBytes).map(ByteStringUtils.hash2string).getOrElse(NotAvailable) val signerStr = signature - .flatMap(_.publicKey(RestrictedEthashSigner.hashHeaderForSigning(block.header))) + .flatMap(_.publicKey(RestrictedPoWSigner.hashHeaderForSigning(block.header))) .map(ByteStringUtils.hash2string) .getOrElse(NotAvailable) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala index a4c6d0704b..8d0907ddb5 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala @@ -5,7 +5,7 @@ import akka.util.{ByteString, Timeout} import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks.PendingBlockAndState -import io.iohk.ethereum.consensus.ethash.EthashUtils +import io.iohk.ethereum.consensus.pow.EthashUtils import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain.{Address, BlockHeader, Blockchain} import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala index 6e7c64442a..6d6c0982d4 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala @@ -39,7 +39,7 @@ object JsonRpcError extends JsonMethodsImplicits { // // Note Error Code "2", "Action not allowed" could be a candidate here, but the description they provide // probably does not match this use-case. - final val ConsensusIsNotEthash = JsonRpcError(200, s"The consensus algorithm is not ${Protocol.Names.Ethash}", None) + final val ConsensusIsNotEthash = JsonRpcError(200, s"The consensus algorithm is not ${Protocol.Names.PoW}", None) def executionError(reasons: List[EthCustomError]): JsonRpcError = JsonRpcError(3, "Execution error", reasons) val NodeNotFound = executionError(List(EthCustomError.DoesntExist("State node"))) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala index 3e9b4880e3..9a4d4337fa 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala @@ -7,9 +7,9 @@ import enumeratum._ import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.consensus._ import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.MinerResponses._ -import io.iohk.ethereum.consensus.ethash.MockedMinerProtocol.MineBlocks -import io.iohk.ethereum.consensus.ethash.{MinerResponse, MinerResponses} +import io.iohk.ethereum.consensus.pow.MinerResponses._ +import io.iohk.ethereum.consensus.pow.MockedMinerProtocol.MineBlocks +import io.iohk.ethereum.consensus.pow.{MinerResponse, MinerResponses} import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.{Block, Blockchain, Checkpoint} diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala b/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala index e051a24349..273c6c8c46 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala @@ -4,8 +4,8 @@ import akka.util.ByteString import io.iohk.ethereum.consensus._ import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, NoOmmersBlockGenerator, TestBlockGenerator} import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.MinerResponses.MinerNotExist -import io.iohk.ethereum.consensus.ethash.{MinerProtocol, MinerResponse} +import io.iohk.ethereum.consensus.pow.MinerResponses.MinerNotExist +import io.iohk.ethereum.consensus.pow.{MinerProtocol, MinerResponse} import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.consensus.validators.std.{StdBlockValidator, StdSignedTransactionValidator} import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, BlockchainImpl, Receipt} @@ -26,7 +26,7 @@ class TestmodeConsensus( extends Consensus { override type Config = AnyRef - override def protocol: Protocol = Protocol.Ethash + override def protocol: Protocol = Protocol.PoW override def config: FullConsensusConfig[AnyRef] = FullConsensusConfig[AnyRef](consensusConfig, "") class TestValidators extends Validators { diff --git a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala index d2ac16524c..3ef11fe320 100644 --- a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala +++ b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala @@ -28,6 +28,7 @@ case class BlockchainConfig( treasuryAddress: Address, ecip1098BlockNumber: BigInt, ecip1097BlockNumber: BigInt, + ecip1049BlockNumber: Option[BigInt], maxCodeSize: Option[BigInt], difficultyBombPauseBlockNumber: BigInt, difficultyBombContinueBlockNumber: BigInt, @@ -75,6 +76,8 @@ object BlockchainConfig { val treasuryAddress = Address(blockchainConfig.getString("treasury-address")) val ecip1098BlockNumber: BigInt = BigInt(blockchainConfig.getString("ecip1098-block-number")) val ecip1097BlockNumber: BigInt = BigInt(blockchainConfig.getString("ecip1097-block-number")) + val ecip1049BlockNumber: Option[BigInt] = + Try(blockchainConfig.getString("ecip1049-block-number")).map(BigInt(_)).toOption val maxCodeSize: Option[BigInt] = Try(BigInt(blockchainConfig.getString("max-code-size"))).toOption val difficultyBombPauseBlockNumber: BigInt = BigInt( @@ -134,6 +137,7 @@ object BlockchainConfig { treasuryAddress = treasuryAddress, ecip1098BlockNumber = ecip1098BlockNumber, ecip1097BlockNumber = ecip1097BlockNumber, + ecip1049BlockNumber = ecip1049BlockNumber, maxCodeSize = maxCodeSize, difficultyBombPauseBlockNumber = difficultyBombPauseBlockNumber, difficultyBombContinueBlockNumber = difficultyBombContinueBlockNumber, diff --git a/src/test/scala/io/iohk/ethereum/Mocks.scala b/src/test/scala/io/iohk/ethereum/Mocks.scala index c8a03d4596..0d5c7240c6 100644 --- a/src/test/scala/io/iohk/ethereum/Mocks.scala +++ b/src/test/scala/io/iohk/ethereum/Mocks.scala @@ -2,13 +2,12 @@ package io.iohk.ethereum import akka.util.ByteString import cats.data.NonEmptyList -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersError.OmmersHeaderError -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersValid -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError.OmmersHeaderError +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersValid +import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, ValidatorsExecutor} import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderDifficultyError, HeaderNumberError} import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.{BlockError, BlockTransactionsHashError, BlockValid} -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor import io.iohk.ethereum.consensus.{Consensus, GetBlockHeaderByHash, GetNBlocksBack} import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala index a386d86c4b..1b9fc70cf2 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala @@ -2,8 +2,8 @@ package io.iohk.ethereum.blockchain.sync import io.iohk.ethereum.Mocks import io.iohk.ethereum.Mocks.MockVM +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor import io.iohk.ethereum.consensus.{Consensus, Protocol, StdTestConsensusBuilder, TestConsensus} import io.iohk.ethereum.domain.BlockchainImpl import io.iohk.ethereum.ledger.Ledger.VMImpl @@ -27,7 +27,7 @@ trait ScenarioSetup extends StdTestConsensusBuilder with SyncConfigBuilder with protected lazy val monixScheduler = Scheduler(executionContextExecutor) protected lazy val successValidators: Validators = Mocks.MockValidatorsAlwaysSucceed protected lazy val failureValidators: Validators = Mocks.MockValidatorsAlwaysFail - protected lazy val ethashValidators: ValidatorsExecutor = ValidatorsExecutor(blockchainConfig, Protocol.Ethash) + protected lazy val powValidators: ValidatorsExecutor = ValidatorsExecutor(blockchainConfig, Protocol.PoW) /** * The default validators for the test cases. @@ -41,8 +41,6 @@ trait ScenarioSetup extends StdTestConsensusBuilder with SyncConfigBuilder with //+ cake overrides /** * The default VM for the test cases. - * Override it for the same reason explained in - * [[io.iohk.ethereum.ledger.LedgerSpec.TestSetup#validators() validators]]. */ override lazy val vm: VMImpl = new MockVM() @@ -85,7 +83,6 @@ trait ScenarioSetup extends StdTestConsensusBuilder with SyncConfigBuilder with * * @note You can use this method to override the existing ledger instance that is provided by the cake. */ - // TODO: change type to trait instead of specific implementation protected def newTestLedger(consensus: Consensus): LedgerImpl = new LedgerImpl( blockchain = blockchain, diff --git a/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala b/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala index 97d50eb6e5..055043ba9d 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.consensus import akka.util.ByteString import io.iohk.ethereum.Timeouts -import io.iohk.ethereum.consensus.ethash.EthashConfig +import io.iohk.ethereum.consensus.pow.EthashConfig import io.iohk.ethereum.domain.Address /** Provides utility values used throughout tests */ @@ -20,7 +20,7 @@ object ConsensusConfigs { ) final val consensusConfig: ConsensusConfig = new ConsensusConfig( - protocol = Protocol.Ethash, + protocol = Protocol.PoW, coinbase = coinbase, headerExtraData = ByteString.empty, blockCacheSize = blockCacheSize, diff --git a/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala index 6de4b5698f..5e32dbb240 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala @@ -13,6 +13,6 @@ class ConsensusSpec extends AnyFlatSpec with Matchers { } it should "contain ethash" in { - Protocol.find(Protocol.Ethash.name).isDefined shouldBe true + Protocol.find(Protocol.PoW.name).isDefined shouldBe true } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala index 093e883c6e..4897039a8b 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala @@ -3,8 +3,9 @@ package io.iohk.ethereum.consensus.blocks import akka.util.ByteString import io.iohk.ethereum.blockchain.data.GenesisDataLoader import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.blocks.BlockTimestampProvider +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators._ -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto._ import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields @@ -36,8 +37,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("a91c44e62d17005c4b22f6ed116f485ea30d8b63f2429745816093b304eb4f73")) val miningTimestamp = 1508751768 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -63,8 +64,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("dc25764fb562d778e5d1320f4c3ba4b09021a2603a0816235e16071e11f342ea")) val miningTimestamp = 1508752265 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -90,8 +91,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("dc25764fb562d778e5d1320f4c3ba4b09021a2603a0816235e16071e11f342ea")) val miningTimestamp = 1508752265 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -144,8 +145,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("908471b57f2d3e70649f9ce0c9c318d61146d3ce19f70d2f94309f135b87b64a")) val miningTimestamp = 1508752389 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -182,8 +183,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("806f26f0efb12a0c0c16e587984227186c46f25fc4e76698a68996183edf2cf1")) val miningTimestamp = 1508752492 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -235,7 +236,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) override lazy val blockExecution = @@ -256,8 +258,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val miningTimestamp = 1499952002 val fullBlock = - pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -308,7 +310,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) override lazy val blockExecution = @@ -352,8 +355,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val miningTimestamp = 1499951223 val fullBlock = - pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -389,8 +392,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val miningTimestamp = 1499721182 val fullBlock = - pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -439,8 +442,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("247a206abc088487edc1697fcaceb33ad87b55666e438129b7048bb08c8ed88f")) val miningTimestamp = 1499721182 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -476,8 +479,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val minedMixHash = ByteString(Hex.decode("270f6b2618c5bef6a188397927129c803e5fd41c85492835486832f6825a8d78")) val miningTimestamp = 1508752698 - val fullBlock = pendingBlock.block.copy(header = - pendingBlock.block.header.copy( + val fullBlock = pendingBlock.block.copy( + header = pendingBlock.block.header.copy( nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp, @@ -588,7 +591,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) override lazy val blockchainConfig = baseBlockchainConfig @@ -602,7 +606,7 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val blockCacheSize: Int = 30 val headerExtraData: ByteString = ByteString("mined with etc scala") - override lazy val validators: ValidatorsExecutor = ethashValidators + override lazy val validators: ValidatorsExecutor = powValidators override lazy val consensusConfig = buildConsensusConfig().copy(headerExtraData = headerExtraData, blockCacheSize = blockCacheSize) diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashMinerSpec.scala similarity index 91% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/EthashMinerSpec.scala index 1a07ec6759..1a0e0fd4d8 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashMinerSpec.scala @@ -1,11 +1,11 @@ package io.iohk.ethereum.consensus -package ethash +package pow import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{TestActor, TestActorRef, TestKit, TestProbe} import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.ethash.validators.EthashBlockHeaderValidator +import io.iohk.ethereum.consensus.pow.validators.PoWBlockHeaderValidator import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.{EthInfoService, EthMiningService} @@ -69,7 +69,7 @@ class EthashMinerSpec Fixtures.Blocks.ValidBlock.body ) - val blockHeaderValidator = new EthashBlockHeaderValidator(blockchainConfig) + val powBlockHeaderValidator = new PoWBlockHeaderValidator(blockchainConfig) val ommersPool: TestProbe = TestProbe() val pendingTransactionsManager: TestProbe = TestProbe() @@ -86,7 +86,14 @@ class EthashMinerSpec ) val miner: TestActorRef[Nothing] = TestActorRef( - EthashMiner.props(blockchain, blockCreator, sync.ref, ethService, ethMiningService) + EthashMiner.props( + blockchain, + blockCreator, + sync.ref, + ethService, + ethMiningService, + blockchainConfig.ecip1049BlockNumber + ) ) protected def executeTest(parentBlock: Block, blockForMining: Block): Unit = { @@ -128,7 +135,7 @@ class EthashMinerSpec private def checkAssertions(minedBlock: Block, parentBlock: Block): Unit = { minedBlock.body.transactionList shouldBe Seq(txToMine) minedBlock.header.nonce.length shouldBe 8 - blockHeaderValidator.validate(minedBlock.header, parentBlock.header) shouldBe Right(BlockHeaderValid) + powBlockHeaderValidator.validate(minedBlock.header, parentBlock.header) shouldBe Right(BlockHeaderValid) } } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala similarity index 98% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala index d04aa3e70a..2c1a5a0a68 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.util.ByteString import io.iohk.ethereum.crypto.kec256 @@ -13,7 +13,7 @@ import io.iohk.ethereum.SuperSlow class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with SuperSlow { - import io.iohk.ethereum.consensus.ethash.EthashUtils._ + import io.iohk.ethereum.consensus.pow.EthashUtils._ val ecip1099forkBlockNumber: Long = 11460000 diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala new file mode 100644 index 0000000000..a214f5ad89 --- /dev/null +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala @@ -0,0 +1,35 @@ +package io.iohk.ethereum.consensus.pow + +import akka.util.ByteString +import io.iohk.ethereum.consensus.pow.KeccakCalculation.KeccakMixHash +import io.iohk.ethereum.domain.BlockHeader +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +class KeccakCalculationSpec extends AnyFlatSpecLike with Matchers { + import KeccakDataUtils._ + + "KeccakCalculation" should + // using the same data used in Besu test to prove that the same hash is generated + "calculate the mixhash based on header hash and a nonce (Besu example)" in { + val nonce = BigInt(-989241412479165825L) // BigInt(56) + val rlpHeader = BlockHeader.getEncodedWithoutNonce(header) + val mixhash = KeccakCalculation.hash(rlpHeader, nonce) + + assert( + ByteString(mixhash.mixHash) == ByteString( + Hex.decode("d033f82e170ff16640e902fad569243c39bce9e4da948ccc298c541b34cd263b") + ) + ) + } + + it should "compare the mixhash with the block difficulty (ECIP-1049 example)" in { + val hash = + KeccakMixHash(ByteString(Hex.decode("0116ad248e0dc3f7f843f73a62803c5f6b7c0427700b70c8b1aab39db404089f"))) + val blockDifficulty = 100L + val isPoWValid = KeccakCalculation.isMixHashValid(hash.mixHash, blockDifficulty) + + assert(isPoWValid) + } +} diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala new file mode 100644 index 0000000000..1da2a16ea5 --- /dev/null +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala @@ -0,0 +1,29 @@ +package io.iohk.ethereum.consensus.pow + +import akka.util.ByteString +import io.iohk.ethereum.domain.BlockHeader +import org.bouncycastle.util.encoders.Hex + +object KeccakDataUtils { + val header = BlockHeader( + parentHash = ByteString(Hex.decode("ad22d4d8f0e94032cb32e86027e0a5533d945ed95088264e91dd71e4fbaebeda")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("6A9ECfa04e99726eC105517AC7ae1aba550BeA6c")), + stateRoot = ByteString(Hex.decode("43e3325393fbc583a5a0b56e98073fb81e82d992b52406a79d662b690a4d2753")), + transactionsRoot = ByteString(Hex.decode("40c339f7715932ec591d8c0c588bacfaed9bddc7519a1e6e87cf45be639de810")), + receiptsRoot = ByteString(Hex.decode("eb1e644436f93be8a9938dfe598cb7fd729f9d201b6f7c0695bee883b3ea6a5b")), + logsBloom = ByteString( + Hex.decode( + "0800012104000104c00400108000400000003000000040008400000002800100000a00000000000001010401040001000001002000000000020020080000240200000000012260010000084800420200040000100000030800802000112020001a200800020000000000500010100a00000000020401480000000010001048000011104800c002410000000010800000000014200040000400000000000000600020c00000004010080000000020100200000200000800001024c4000000080100004002004808000102920408810000002000008000000008000120400020008200d80000000010010000008028004000010000008220000200000100100800" + ) + ), + difficulty = BigInt(3963642329L), + number = 4156209L, + gasLimit = 8000000L, + gasUsed = 7987824L, + unixTimestamp = 1538483791L, + extraData = ByteString(Hex.decode("d88301080f846765746888676f312e31302e31856c696e7578")), + mixHash = ByteString.empty, + nonce = ByteString.empty + ) +} diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala similarity index 90% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala index 9425feecae..982285d2e2 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.actor.ActorSystem import akka.testkit.{TestActorRef, TestProbe} @@ -6,8 +6,8 @@ import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.{ScenarioSetup, SyncProtocol} import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator -import io.iohk.ethereum.consensus.ethash.difficulty.EthashDifficultyCalculator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.ledger.Ledger.VMImpl @@ -20,8 +20,7 @@ abstract class MinerSpecSetup(implicit system: ActorSystem) extends ScenarioSetu def miner: TestActorRef[Nothing] - val origin = - Block(Fixtures.Blocks.Genesis.header, Fixtures.Blocks.Genesis.body) + val origin = Block(Fixtures.Blocks.Genesis.header, Fixtures.Blocks.Genesis.body) val sync = TestProbe() @@ -42,11 +41,11 @@ abstract class MinerSpecSetup(implicit system: ActorSystem) extends ScenarioSetu parentGas + gasLimitDifference - 1 } - val blockGenerator: EthashBlockGenerator = mock[EthashBlockGenerator] + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] override lazy val blockchain: BlockchainImpl = mock[BlockchainImpl] override lazy val vm: VMImpl = new VMImpl - override lazy val consensus: EthashConsensus = buildEthashConsensus().withBlockGenerator(blockGenerator) + override lazy val consensus: PoWConsensus = buildPoWConsensus().withBlockGenerator(blockGenerator) val blockCreator = mock[EthashBlockCreator] diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/MockedMinerSpec.scala similarity index 97% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/MockedMinerSpec.scala index 4d051e7169..a13d33f77c 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/MockedMinerSpec.scala @@ -1,9 +1,9 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import akka.actor.ActorSystem import akka.testkit.{TestActorRef, TestKit} import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.consensus.ethash.MinerResponses.{MinerIsWorking, MinerNotSupport, MiningError, MiningOrdered} +import io.iohk.ethereum.consensus.pow.MinerResponses.{MinerIsWorking, MinerNotSupport, MiningError, MiningOrdered} import io.iohk.ethereum.domain.{Block, SignedTransaction} import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.ByteStringUtils diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSignerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala similarity index 70% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSignerSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala index 0d9190bfb6..0ac85076aa 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSignerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala @@ -1,4 +1,4 @@ -package io.iohk.ethereum.consensus.ethash +package io.iohk.ethereum.consensus.pow import io.iohk.ethereum.{ObjectGenerators, crypto} import io.iohk.ethereum.security.SecureRandomBuilder @@ -14,17 +14,17 @@ class RestrictedEthashSignerSpec with SecureRandomBuilder { "RestrictedEthashSigner" should "sign and validate correct header" in { forAll(blockHeaderGen, genKey(secureRandom)) { (header, key) => - val signedHeader = RestrictedEthashSigner.signHeader(header, key) + val signedHeader = RestrictedPoWSigner.signHeader(header, key) val keyAsBytes = crypto.keyPairToByteStrings(key)._2 - assert(RestrictedEthashSigner.validateSignature(signedHeader, Set(keyAsBytes))) + assert(RestrictedPoWSigner.validateSignature(signedHeader, Set(keyAsBytes))) } } it should "fail to validate header signed with wrong key" in { forAll(blockHeaderGen, genKey(secureRandom), genKey(secureRandom)) { (header, correctKey, wrongKey) => - val signedHeader = RestrictedEthashSigner.signHeader(header, correctKey) + val signedHeader = RestrictedPoWSigner.signHeader(header, correctKey) val wrongKeyAsBytes = crypto.keyPairToByteStrings(wrongKey)._2 - assert(!RestrictedEthashSigner.validateSignature(signedHeader, Set(wrongKeyAsBytes))) + assert(!RestrictedPoWSigner.validateSignature(signedHeader, Set(wrongKeyAsBytes))) } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala similarity index 93% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidatorSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala index 375c75213f..cc9740c245 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala @@ -1,9 +1,9 @@ -package io.iohk.ethereum.consensus.ethash.validators +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.ethash.difficulty.EthashDifficultyCalculator +import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator import io.iohk.ethereum.consensus.validators.BlockHeaderError._ import io.iohk.ethereum.consensus.validators.BlockHeaderValidator._ import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} @@ -31,11 +31,11 @@ class EthashBlockHeaderValidatorSpec val blockchainConfig: BlockchainConfig = createBlockchainConfig() - val blockHeaderValidator = new EthashBlockHeaderValidator(blockchainConfig) + val powBlockHeaderValidator = new PoWBlockHeaderValidator(blockchainConfig) val difficultyCalculator = new EthashDifficultyCalculator(blockchainConfig) "BlockHeaderValidator" should "validate correctly formed BlockHeaders" in { - blockHeaderValidator.validate(validBlockHeader, validParent.header) match { + powBlockHeaderValidator.validate(validBlockHeader, validParent.header) match { case Right(_) => succeed case _ => fail() } @@ -44,7 +44,7 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created based on invalid extra data" in { forAll(randomSizeByteStringGen(MaxExtraDataSize + 1, MaxExtraDataSize + ExtraDataSizeLimit)) { wrongExtraData => val invalidBlockHeader = validBlockHeader.copy(extraData = wrongExtraData) - assert(blockHeaderValidator.validate(invalidBlockHeader, validParent.header) == Left(HeaderExtraDataError)) + assert(powBlockHeaderValidator.validate(invalidBlockHeader, validParent.header) == Left(HeaderExtraDataError)) } } @@ -72,7 +72,7 @@ class EthashBlockHeaderValidatorSpec }.toSeq.flatten forAll(cases) { (blockHeader, parentBlock, supportsDaoFork, valid) => - val blockHeaderValidator = new EthashBlockHeaderValidator(createBlockchainConfig(supportsDaoFork)) + val blockHeaderValidator = new PoWBlockHeaderValidator(createBlockchainConfig(supportsDaoFork)) blockHeaderValidator.validate(blockHeader, parentBlock.header) match { case Right(_) => assert(valid) case Left(DaoHeaderExtraDataError) => assert(!valid) @@ -84,7 +84,7 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created based on invalid timestamp" in { forAll(longGen) { timestamp => val blockHeader = validBlockHeader.copy(unixTimestamp = timestamp) - val validateResult = blockHeaderValidator.validate(blockHeader, validParent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) timestamp match { case t if t <= validParentBlockHeader.unixTimestamp => assert(validateResult == Left(HeaderTimestampError)) case validBlockHeader.unixTimestamp => assert(validateResult == Right(BlockHeaderValid)) @@ -96,7 +96,7 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created based on invalid difficulty" in { forAll(bigIntGen) { difficulty => val blockHeader = validBlockHeader.copy(difficulty = difficulty) - val validateResult = blockHeaderValidator.validate(blockHeader, validParent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) if (difficulty != validBlockHeader.difficulty) assert(validateResult == Left(HeaderDifficultyError)) else assert(validateResult == Right(BlockHeaderValid)) } @@ -105,7 +105,7 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created based on invalid gas used" in { forAll(bigIntGen) { gasUsed => val blockHeader = validBlockHeader.copy(gasUsed = gasUsed) - val validateResult = blockHeaderValidator.validate(blockHeader, validParent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) if (gasUsed > validBlockHeader.gasLimit) assert(validateResult == Left(HeaderGasUsedError)) else assert(validateResult == Right(BlockHeaderValid)) } @@ -114,7 +114,7 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created based on invalid negative gas used" in { val gasUsed = -1 val blockHeader = validBlockHeader.copy(gasUsed = gasUsed) - val validateResult = blockHeaderValidator.validate(blockHeader, validParent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) assert(validateResult == Left(HeaderGasUsedError)) } @@ -125,7 +125,7 @@ class EthashBlockHeaderValidatorSpec forAll(bigIntGen) { gasLimit => val blockHeader = validBlockHeader.copy(gasLimit = gasLimit) - val validateResult = blockHeaderValidator.validate(blockHeader, validParent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) if (gasLimit < LowerGasLimit || gasLimit > UpperGasLimit) assert(validateResult == Left(HeaderGasLimitError)) else assert(validateResult == Right(BlockHeaderValid)) @@ -135,14 +135,14 @@ class EthashBlockHeaderValidatorSpec it should "return a failure if created with gas limit above threshold and block number >= eip106 block number" in { val validParent = Block(validParentBlockHeader.copy(gasLimit = Long.MaxValue), validParentBlockBody) val invalidBlockHeader = validBlockHeader.copy(gasLimit = BigInt(Long.MaxValue) + 1) - blockHeaderValidator.validate(invalidBlockHeader, validParent.header) shouldBe Left(HeaderGasLimitError) + powBlockHeaderValidator.validate(invalidBlockHeader, validParent.header) shouldBe Left(HeaderGasLimitError) } it should "return a failure if created based on invalid number" in { forAll(longGen) { number => val blockHeader = validBlockHeader.copy(number = number) val parent = Block(validParentBlockHeader, validParentBlockBody) - val validateResult = blockHeaderValidator.validate(blockHeader, parent.header) + val validateResult = powBlockHeaderValidator.validate(blockHeader, parent.header) if (number != validParentBlockHeader.number + 1) assert(validateResult == Left(HeaderNumberError) || validateResult == Left(HeaderDifficultyError)) else assert(validateResult == Right(BlockHeaderValid)) @@ -158,9 +158,9 @@ class EthashBlockHeaderValidatorSpec val parent = Block(validParentBlockHeader, validParentBlockBody) - blockHeaderValidator.validate(blockHeaderWithInvalidNonce, parent.header) shouldBe Left(HeaderPoWError) - blockHeaderValidator.validate(blockHeaderWithInvalidMixHash, parent.header) shouldBe Left(HeaderPoWError) - blockHeaderValidator.validate(blockHeaderWithInvalidNonceAndMixHash, parent.header) shouldBe Left(HeaderPoWError) + powBlockHeaderValidator.validate(blockHeaderWithInvalidNonce, parent.header) shouldBe Left(HeaderPoWError) + powBlockHeaderValidator.validate(blockHeaderWithInvalidMixHash, parent.header) shouldBe Left(HeaderPoWError) + powBlockHeaderValidator.validate(blockHeaderWithInvalidNonceAndMixHash, parent.header) shouldBe Left(HeaderPoWError) } it should "validate correctly a block whose parent is in storage" in new EphemBlockchainTestSetup { @@ -168,14 +168,14 @@ class EthashBlockHeaderValidatorSpec .storeBlockHeader(validParentBlockHeader) .and(blockchain.storeBlockBody(validParentBlockHeader.hash, validParentBlockBody)) .commit() - blockHeaderValidator.validate(validBlockHeader, blockchain.getBlockHeaderByHash _) match { + powBlockHeaderValidator.validate(validBlockHeader, blockchain.getBlockHeaderByHash _) match { case Right(_) => succeed case _ => fail() } } it should "return a failure if the parent's header is not in storage" in new EphemBlockchainTestSetup { - blockHeaderValidator.validate(validBlockHeader, blockchain.getBlockHeaderByHash _) match { + powBlockHeaderValidator.validate(validBlockHeader, blockchain.getBlockHeaderByHash _) match { case Left(HeaderParentNotFoundError) => succeed case _ => fail() } @@ -184,7 +184,7 @@ class EthashBlockHeaderValidatorSpec it should "properly validate a block after difficulty bomb pause" in new EphemBlockchainTestSetup { val parent = Block(pausedDifficultyBombBlockParent, parentBody) - val res = blockHeaderValidator.validate(pausedDifficultyBombBlock, parent.header) + val res = powBlockHeaderValidator.validate(pausedDifficultyBombBlock, parent.header) res shouldBe Right(BlockHeaderValid) } @@ -474,7 +474,8 @@ class EthashBlockHeaderValidatorSpec ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), ecip1097BlockNumber = Long.MaxValue, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) } @@ -539,5 +540,4 @@ class EthashBlockHeaderValidatorSpec mixHash = ByteString(Hex.decode("8f86617d6422c26a89b8b349b160973ca44f90326e758f1ef669c4046741dd06")), nonce = ByteString(Hex.decode("c7de19e00a8c3e32")) ) - } diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala new file mode 100644 index 0000000000..d78aba2575 --- /dev/null +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala @@ -0,0 +1,31 @@ +package io.iohk.ethereum.consensus.pow.validators + +import akka.util.ByteString +import io.iohk.ethereum.consensus.pow.KeccakDataUtils +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +class KeccakBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { + import KeccakBlockHeaderValidatorSpec._ + + "KeccakBlockHeaderValidatorSpec" should "return BlockHeaderValid when header is valid" in { + KeccakBlockHeaderValidator.validateHeader(validBlockHeader) shouldBe Right(BlockHeaderValid) + } + + it should "return HeaderPoWError when header is invalid" in { + val invalidBlockHeader = validBlockHeader.copy(nonce = ByteString(Hex.decode("f245822d3413ab67"))) + KeccakBlockHeaderValidator.validateHeader(invalidBlockHeader) shouldBe Left(HeaderPoWError) + } +} + +object KeccakBlockHeaderValidatorSpec { + import KeccakDataUtils._ + + val validBlockHeader = header.copy( + mixHash = ByteString(Hex.decode("d033f82e170ff16640e902fad569243c39bce9e4da948ccc298c541b34cd263b")), + nonce = ByteString(Hex.decode("f245822d3412da7f")) + ) +} diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala new file mode 100644 index 0000000000..127f931208 --- /dev/null +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala @@ -0,0 +1,62 @@ +package io.iohk.ethereum.consensus.pow.validators + +import akka.util.ByteString +import io.iohk.ethereum.consensus.pow.KeccakDataUtils +import io.iohk.ethereum.consensus.pow.KeccakDataUtils.header +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.utils.Config +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +class PoWBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { + import PoWBlockHeaderValidatorSpec._ + + "PoWBlockHeaderValidator" should "call KeccakBlockHeaderValidator when chain is in Keccak" in { + val keccakConfig = blockchainConfig.copy(ecip1049BlockNumber = Some(10)) + val validatorForKeccak = new PoWBlockHeaderValidator(keccakConfig) + + validatorForKeccak.validateEvenMore(validKeccakBlockHeader) shouldBe Right(BlockHeaderValid) + + // to show that indeed the right validator needs to be called + validatorForKeccak.validateEvenMore(validEthashBlockHeader) shouldBe Left(HeaderPoWError) + } + + it should "call EthashBlockHeaderValidator when chain is not in Keccak" in { + val validatorForKeccak = new PoWBlockHeaderValidator(blockchainConfig) + + validatorForKeccak.validateEvenMore(validEthashBlockHeader) shouldBe Right(BlockHeaderValid) + + // to show that indeed the right validator needs to be called + validatorForKeccak.validateEvenMore(validKeccakBlockHeader) shouldBe Left(HeaderPoWError) + } +} + +object PoWBlockHeaderValidatorSpec { + val blockchainConfig = Config.blockchains.blockchainConfig + + val validKeccakBlockHeader = KeccakDataUtils.header.copy( + mixHash = ByteString(Hex.decode("d033f82e170ff16640e902fad569243c39bce9e4da948ccc298c541b34cd263b")), + nonce = ByteString(Hex.decode("f245822d3412da7f")) + ) + + val validEthashBlockHeader = BlockHeader( + parentHash = ByteString(Hex.decode("d882d5c210bab4cb7ef0b9f3dc2130cb680959afcd9a8f9bf83ee6f13e2f9da3")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), + stateRoot = ByteString(Hex.decode("634a2b20c9e02afdda7157afe384306c5acc4fb9c09b45dc0203c0fbb2fed0e6")), + transactionsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + receiptsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + logsBloom = ByteString(Hex.decode("00" * 256)), + difficulty = BigInt("989772"), + number = 20, + gasLimit = 131620495, + gasUsed = 0, + unixTimestamp = 1486752441, + extraData = ByteString(Hex.decode("d783010507846765746887676f312e372e33856c696e7578")), + mixHash = ByteString(Hex.decode("6bc729364c9b682cfa923ba9480367ebdfa2a9bca2a652fe975e8d5958f696dd")), + nonce = ByteString(Hex.decode("797a8f3a494f937b")) + ) +} diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala similarity index 94% rename from src/test/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidatorSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala index c5c37e024e..f1a415247d 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/validators/RestrictedEthashBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala @@ -1,8 +1,8 @@ -package io.iohk.ethereum.consensus.ethash.validators +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner -import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderPoWError, RestrictedEthashHeaderExtraDataError} +import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner +import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderPoWError, RestrictedPoWHeaderExtraDataError} import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature @@ -31,7 +31,7 @@ class RestrictedEthashBlockHeaderValidatorSpec ByteString.fromArrayUnsafe(new Array[Byte](blockHeaderValidator.ExtraDataMaxSize + 1)) ) val validationResult = blockHeaderValidator.validate(tooLongExtraData, validParent) - assert(validationResult == Left(RestrictedEthashHeaderExtraDataError)) + assert(validationResult == Left(RestrictedPoWHeaderExtraDataError)) } it should "correctly validate header with valid key" in new TestSetup { @@ -47,7 +47,7 @@ class RestrictedEthashBlockHeaderValidatorSpec // correct header is signed by different key that the one generated here val blockHeaderValidator = new RestrictedEthashBlockHeaderValidator(createBlockchainConfig(Set(keyBytes))) val validationResult = blockHeaderValidator.validate(validHeader, validParent) - assert(validationResult == Left(RestrictedEthashHeaderExtraDataError)) + assert(validationResult == Left(RestrictedPoWHeaderExtraDataError)) } it should "fail to validate header re-signed by valid signer" in new TestSetup { @@ -56,7 +56,7 @@ class RestrictedEthashBlockHeaderValidatorSpec val blockHeaderValidator = new RestrictedEthashBlockHeaderValidator(createBlockchainConfig(Set(keyBytes, validKey))) val headerWithoutSig = validHeader.copy(extraData = validHeader.extraData.dropRight(ECDSASignature.EncodedLength)) - val reSignedHeader = RestrictedEthashSigner.signHeader(headerWithoutSig, allowedKey) + val reSignedHeader = RestrictedPoWSigner.signHeader(headerWithoutSig, allowedKey) val validationResult = blockHeaderValidator.validate(reSignedHeader, validParent) assert(validationResult == Left(HeaderPoWError)) @@ -102,7 +102,8 @@ class RestrictedEthashBlockHeaderValidatorSpec ecip1097BlockNumber = Long.MaxValue, checkpointPubKeys = Set.empty, allowedMinersPublicKeys = allowedMiners, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) } diff --git a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala similarity index 98% rename from src/test/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidatorSpec.scala rename to src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala index b190d2750c..c07e58a016 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdOmmersValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala @@ -1,10 +1,9 @@ -package io.iohk.ethereum.consensus.validators.std +package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.ethash.validators.EthashBlockHeaderValidator -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.OmmersError._ +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError._ import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec @@ -106,7 +105,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr // scalastyle:off magic.number trait BlockUtils extends EphemBlockchainTestSetup { - val ommersValidator = new StdOmmersValidator(new EthashBlockHeaderValidator(blockchainConfig)) + val ommersValidator = new StdOmmersValidator(new PoWBlockHeaderValidator(blockchainConfig)) val ommerInvalidBranch = BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b12345f6a89fb1e8f017f2411a29d0ae810ab8b")), diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala index 6eb15e08c3..6769d290d6 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala @@ -5,7 +5,7 @@ import akka.testkit.TestKit import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.{Block, BlockBody, ChainWeight, UInt256} @@ -409,7 +409,7 @@ class EthBlocksServiceSpec } class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup { - val blockGenerator = mock[EthashBlockGenerator] + val blockGenerator = mock[PoWBlockGenerator] val appStateStorage = mock[AppStateStorage] override lazy val ledger = mock[Ledger] override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala index 62b1a19df4..df9ea5806a 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala @@ -7,7 +7,7 @@ import io.iohk.ethereum._ import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress import io.iohk.ethereum.blockchain.sync.{EphemBlockchainTestSetup, SyncProtocol} import io.iohk.ethereum.consensus._ -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.{Block, BlockchainImpl, UInt256, _} import io.iohk.ethereum.jsonrpc.EthInfoService.{ProtocolVersionRequest, _} @@ -140,7 +140,7 @@ class EthServiceSpec // NOTE TestSetup uses Ethash consensus; check `consensusConfig`. class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup { - val blockGenerator = mock[EthashBlockGenerator] + val blockGenerator = mock[PoWBlockGenerator] val appStateStorage = mock[AppStateStorage] val keyStore = mock[KeyStore] override lazy val ledger = mock[Ledger] diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala index f94e808e96..dd98168e12 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala @@ -6,8 +6,8 @@ import akka.util.ByteString import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.ethash.blocks.{EthashBlockGenerator, RestrictedEthashBlockGeneratorImpl} -import io.iohk.ethereum.consensus.ethash.difficulty.EthashDifficultyCalculator +import io.iohk.ethereum.consensus.pow.blocks.{PoWBlockGenerator, RestrictedPoWBlockGeneratorImpl} +import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.storage.AppStateStorage @@ -216,7 +216,7 @@ class EthMiningServiceSpec // NOTE TestSetup uses Ethash consensus; check `consensusConfig`. class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup with ApisBuilder { - val blockGenerator = mock[EthashBlockGenerator] + val blockGenerator = mock[PoWBlockGenerator] val appStateStorage = mock[AppStateStorage] override lazy val ledger = mock[Ledger] override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator) @@ -235,7 +235,7 @@ class EthMiningServiceSpec lazy val difficultyCalc = new EthashDifficultyCalculator(blockchainConfig) - lazy val restrictedGenerator = new RestrictedEthashBlockGeneratorImpl( + lazy val restrictedGenerator = new RestrictedPoWBlockGeneratorImpl( validators = MockValidatorsAlwaysSucceed, blockchain = blockchain, blockchainConfig = blockchainConfig, diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala index ca0082b9c9..3344cca062 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala @@ -6,7 +6,7 @@ import akka.util.ByteString import com.softwaremill.diffx.scalatest.DiffMatcher import io.iohk.ethereum._ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.EthUserService.{ GetBalanceRequest, @@ -215,7 +215,7 @@ class EthProofServiceSpec class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup with ApisBuilder { - val blockGenerator = mock[EthashBlockGenerator] + val blockGenerator = mock[PoWBlockGenerator] val address = Address(ByteString(Hex.decode("abbb6bebfa05aa13e908eaa492bd7a8343760477"))) val balance = UInt256(0) val nonce = 0 diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala index 16157feaae..d7f6be4f33 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala @@ -5,8 +5,8 @@ import akka.testkit.TestProbe import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator -import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.db.storage.AppStateStorage @@ -40,7 +40,7 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) encodeAsHex(RawTransactionCodec.asRawTransaction(x)) val version = Config.clientVersion - val blockGenerator = mock[EthashBlockGenerator] + val blockGenerator = mock[PoWBlockGenerator] val syncingController = TestProbe() override lazy val ledger = mock[Ledger] diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 8a767980fa..31098e5d92 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -429,7 +429,8 @@ class PersonalServiceSpec ecip1098BlockNumber = 0, treasuryAddress = Address(0), ecip1097BlockNumber = 0, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) val wallet = Wallet(address, prvKey) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala index ac387a230e..a75768fee5 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala @@ -7,9 +7,9 @@ import io.iohk.ethereum._ import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.consensus.Consensus import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.EthashConfig -import io.iohk.ethereum.consensus.ethash.MinerResponses.MiningOrdered -import io.iohk.ethereum.consensus.ethash.MockedMinerProtocol.MineBlocks +import io.iohk.ethereum.consensus.pow.EthashConfig +import io.iohk.ethereum.consensus.pow.MinerResponses.MiningOrdered +import io.iohk.ethereum.consensus.pow.MockedMinerProtocol.MineBlocks import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.QAService._ diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala index 537b5a3ddb..ef4946eafc 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.consensus.ethash.MockedMinerProtocol.MineBlocks -import io.iohk.ethereum.consensus.ethash.{MinerResponse, MinerResponses} +import io.iohk.ethereum.consensus.pow.MockedMinerProtocol.MineBlocks +import io.iohk.ethereum.consensus.pow.{MinerResponse, MinerResponses} import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.Checkpoint diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala index c94cd6e1c3..0ff0d25dee 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala @@ -5,7 +5,7 @@ import akka.util.ByteString.{empty => bEmpty} import io.iohk.ethereum.Mocks import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.consensus.Consensus -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.{BlockTransactionsHashError, BlockValid} import io.iohk.ethereum.consensus.validators.{Validators, _} import io.iohk.ethereum.domain._ diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala index 629c591445..ab320cf839 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala @@ -5,9 +5,8 @@ import akka.util.ByteString.{empty => bEmpty} import cats.data.NonEmptyList import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, StdOmmersValidator} import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError -import io.iohk.ethereum.consensus.validators.std.StdOmmersValidator import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator, Validators} import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack, TestConsensus} import io.iohk.ethereum.crypto.{generateKeyPair, kec256} diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index 40195a189b..76e304c125 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -137,7 +137,8 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { ecip1098BlockNumber = 0, treasuryAddress = Address(0), ecip1097BlockNumber = 0, - ecip1099BlockNumber = Long.MaxValue + ecip1099BlockNumber = Long.MaxValue, + ecip1049BlockNumber = None ) override lazy val stxLedger = new StxLedger(blockchain, blockchainConfig, consensus.blockPreparator)