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 13bcb56709..c157cd7302 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala @@ -36,7 +36,6 @@ object BlockchainTestConfig { daoForkConfig = None, accountStartNonce = UInt256.Zero, bootstrapNodes = Set(), - // TODO: only place where this was supposed to be used but now it seems it's not, remove? Issue: EC-312 gasTieBreaker = false, ethCompatibleStorage = true, @@ -45,7 +44,8 @@ object BlockchainTestConfig { phoenixBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) val FrontierConfig = BaseBlockchainConfig.copy( @@ -75,7 +75,8 @@ object BlockchainTestConfig { daoForkConfig = Some( new DaoForkConfig { override val forkBlockNumber: BigInt = 5 - override val forkBlockHash = ByteString(Hex.decode("f6d7ef1087b5fd94eada533cf8a563f78c3944a2f8ae850e80935d20dc3b7315")) + override val forkBlockHash = + ByteString(Hex.decode("f6d7ef1087b5fd94eada533cf8a563f78c3944a2f8ae850e80935d20dc3b7315")) override val blockExtraData = Some(ByteString(Hex.decode("64616f2d686172642d666f726b"))) override val range = 10 override val refundContract = Some(Address("bf4ed7b27f1d666546e30d74d50d173d20bca754")) @@ -231,8 +232,13 @@ object BlockchainTestConfig { maxCodeSize = Some(24576), byzantiumBlockNumber = -1, constantinopleBlockNumber = 0, - monetaryPolicyConfig = - MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000"), BigInt("3000000000000000000"), BigInt("2000000000000000000")) + monetaryPolicyConfig = MonetaryPolicyConfig( + 5000000, + 0.2, + BigInt("5000000000000000000"), + BigInt("3000000000000000000"), + BigInt("2000000000000000000") + ) ) val ConstantinopleFixConfig = BaseBlockchainConfig.copy( frontierBlockNumber = -1, @@ -245,8 +251,13 @@ object BlockchainTestConfig { byzantiumBlockNumber = -1, constantinopleBlockNumber = -1, petersburgBlockNumber = 0, - monetaryPolicyConfig = - MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000"), BigInt("3000000000000000000"), BigInt("2000000000000000000")) + monetaryPolicyConfig = MonetaryPolicyConfig( + 5000000, + 0.2, + BigInt("5000000000000000000"), + BigInt("3000000000000000000"), + BigInt("2000000000000000000") + ) ) val IstanbulConfig = BaseBlockchainConfig.copy( frontierBlockNumber = -1, @@ -260,8 +271,13 @@ object BlockchainTestConfig { constantinopleBlockNumber = -1, petersburgBlockNumber = -1, istanbulBlockNumber = 0, - monetaryPolicyConfig = - MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000"), BigInt("3000000000000000000"), BigInt("2000000000000000000")) + monetaryPolicyConfig = MonetaryPolicyConfig( + 5000000, + 0.2, + BigInt("5000000000000000000"), + BigInt("3000000000000000000"), + BigInt("2000000000000000000") + ) ) val Eip158ToByzantiumAt5Config = BaseBlockchainConfig.copy( frontierBlockNumber = -1, @@ -286,8 +302,13 @@ object BlockchainTestConfig { maxCodeSize = Some(24576), byzantiumBlockNumber = 0, constantinopleBlockNumber = 5, - monetaryPolicyConfig = - MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000"), BigInt("3000000000000000000"), BigInt("2000000000000000000")) + monetaryPolicyConfig = MonetaryPolicyConfig( + 5000000, + 0.2, + BigInt("5000000000000000000"), + BigInt("3000000000000000000"), + BigInt("2000000000000000000") + ) ) } @@ -299,7 +320,7 @@ object Validators { 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 homesteadToDaoValidators = ValidatorsExecutor(HomesteadToDaoAt5, Protocol.Ethash) val eip158Validators = ValidatorsExecutor(Eip158Config, Protocol.Ethash) val byzantiumValidators = ValidatorsExecutor(ByzantiumConfig, Protocol.Ethash) val constantinopleValidators = ValidatorsExecutor(ConstantinopleConfig, Protocol.Ethash) @@ -314,17 +335,24 @@ object ValidatorsWithSkippedPoW { import BlockchainTestConfig._ - val frontierValidators = ValidatorsExecutor(FrontierConfig, new EthashTestBlockHeaderValidator(FrontierConfig)) + val frontierValidators = ValidatorsExecutor(FrontierConfig, new EthashTestBlockHeaderValidator(FrontierConfig)) val homesteadValidators = ValidatorsExecutor(HomesteadConfig, new EthashTestBlockHeaderValidator(HomesteadConfig)) val eip150Validators = ValidatorsExecutor(Eip150Config, new EthashTestBlockHeaderValidator(Eip150Config)) - val frontierToHomesteadValidators = ValidatorsExecutor(FrontierToHomesteadAt5, new EthashTestBlockHeaderValidator(FrontierToHomesteadAt5)) - val homesteadToEipValidators = ValidatorsExecutor(HomesteadToEIP150At5, new EthashTestBlockHeaderValidator(HomesteadToEIP150At5)) - val homesteadToDaoValidators= ValidatorsExecutor(HomesteadToDaoAt5, new EthashTestBlockHeaderValidator(HomesteadToDaoAt5)) + val frontierToHomesteadValidators = + ValidatorsExecutor(FrontierToHomesteadAt5, new EthashTestBlockHeaderValidator(FrontierToHomesteadAt5)) + val homesteadToEipValidators = + ValidatorsExecutor(HomesteadToEIP150At5, new EthashTestBlockHeaderValidator(HomesteadToEIP150At5)) + val homesteadToDaoValidators = + ValidatorsExecutor(HomesteadToDaoAt5, new EthashTestBlockHeaderValidator(HomesteadToDaoAt5)) val eip158Validators = ValidatorsExecutor(Eip158Config, new EthashTestBlockHeaderValidator(Eip158Config)) val byzantiumValidators = ValidatorsExecutor(ByzantiumConfig, new EthashTestBlockHeaderValidator(ByzantiumConfig)) - val constantinopleValidators = ValidatorsExecutor(ConstantinopleConfig, new EthashTestBlockHeaderValidator(ConstantinopleConfig)) - val constantinopleFixValidators = ValidatorsExecutor(ConstantinopleFixConfig, new EthashTestBlockHeaderValidator(ConstantinopleFixConfig)) + val constantinopleValidators = + ValidatorsExecutor(ConstantinopleConfig, new EthashTestBlockHeaderValidator(ConstantinopleConfig)) + val constantinopleFixValidators = + ValidatorsExecutor(ConstantinopleFixConfig, new EthashTestBlockHeaderValidator(ConstantinopleFixConfig)) val istanbulValidators = ValidatorsExecutor(IstanbulConfig, new EthashTestBlockHeaderValidator(IstanbulConfig)) - val eip158ToByzantiumValidators = ValidatorsExecutor(Eip158ToByzantiumAt5Config, new EthashTestBlockHeaderValidator(Eip158ToByzantiumAt5Config)) - val byzantiumToConstantinopleAt5 = ValidatorsExecutor(ByzantiumToConstantinopleAt5, new EthashTestBlockHeaderValidator(ByzantiumToConstantinopleAt5)) + val eip158ToByzantiumValidators = + ValidatorsExecutor(Eip158ToByzantiumAt5Config, new EthashTestBlockHeaderValidator(Eip158ToByzantiumAt5Config)) + val byzantiumToConstantinopleAt5 = + ValidatorsExecutor(ByzantiumToConstantinopleAt5, new EthashTestBlockHeaderValidator(ByzantiumToConstantinopleAt5)) } diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala index 91835502c9..5b9740d3cf 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala @@ -47,7 +47,8 @@ class ECIP1017Test extends AnyFlatSpec with Matchers { petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) 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 b7bd3a75b4..ea1373961f 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -46,7 +46,8 @@ class ForksTest extends AnyFlatSpec with Matchers { petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) val noErrors = a[Right[_, Seq[Receipt]]] diff --git a/src/main/resources/chains/etc-chain.conf b/src/main/resources/chains/etc-chain.conf index ede4d99845..43abf1a636 100644 --- a/src/main/resources/chains/etc-chain.conf +++ b/src/main/resources/chains/etc-chain.conf @@ -88,6 +88,10 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "11700000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao { diff --git a/src/main/resources/chains/eth-chain.conf b/src/main/resources/chains/eth-chain.conf index e424ea022b..15230e8c42 100644 --- a/src/main/resources/chains/eth-chain.conf +++ b/src/main/resources/chains/eth-chain.conf @@ -88,6 +88,10 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "1000000000000000000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao { diff --git a/src/main/resources/chains/mordor-chain.conf b/src/main/resources/chains/mordor-chain.conf index b666246f48..ad6154120d 100644 --- a/src/main/resources/chains/mordor-chain.conf +++ b/src/main/resources/chains/mordor-chain.conf @@ -88,6 +88,11 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "2520000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao = null diff --git a/src/main/resources/chains/ropsten-chain.conf b/src/main/resources/chains/ropsten-chain.conf index 43d8a442b9..4c21e99118 100644 --- a/src/main/resources/chains/ropsten-chain.conf +++ b/src/main/resources/chains/ropsten-chain.conf @@ -91,6 +91,11 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "1000000000000000000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao { diff --git a/src/main/resources/chains/test-chain.conf b/src/main/resources/chains/test-chain.conf index cd13c15837..3f00f5a69e 100644 --- a/src/main/resources/chains/test-chain.conf +++ b/src/main/resources/chains/test-chain.conf @@ -88,6 +88,11 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "1000000000000000000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao { diff --git a/src/main/resources/chains/testnet-internal-chain.conf b/src/main/resources/chains/testnet-internal-chain.conf index b6702aa330..56ba51d92e 100644 --- a/src/main/resources/chains/testnet-internal-chain.conf +++ b/src/main/resources/chains/testnet-internal-chain.conf @@ -88,6 +88,10 @@ # Has to be equal or greater than ecip1098-block-number ecip1097-block-number = "1000000000000000000" + # Epoch calibration block number + # https://ecips.ethereumclassic.org/ECIPs/ecip-1099 + ecip1099-block-number = "1000000000000000000" + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao = null diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala index e61235c56f..b474d1602f 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala @@ -24,6 +24,7 @@ class EthashBlockCreator( lazy val miningConfig = fullConsensusConfig.specific private lazy val coinbase: Address = consensusConfig.coinbase private lazy val blockGenerator: EthashBlockGenerator = consensus.blockGenerator + lazy val blockchainConfig = consensus.blockchainConfig def getBlockForMining(parentBlock: Block, withTransactions: Boolean = true): Future[PendingBlock] = { val transactions = diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala index 0332c78d41..1a0e08aacf 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala @@ -28,7 +28,7 @@ import scala.concurrent.duration._ class EthashConsensus private ( val vm: VMImpl, blockchain: BlockchainImpl, - blockchainConfig: BlockchainConfig, + val blockchainConfig: BlockchainConfig, val config: FullConsensusConfig[EthashConfig], val validators: ValidatorsExecutor, val blockGenerator: EthashBlockGenerator, diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala index ea05789ac6..db4fb5610c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala @@ -56,12 +56,12 @@ class EthashMiner( def processMining(): Unit = { val parentBlock = blockchain.getBestBlock() - val epoch = EthashUtils.epoch(parentBlock.header.number.toLong + 1) - + val blockNumber = parentBlock.header.number.toLong + 1 + val epoch = EthashUtils.epoch(blockNumber, blockCreator.blockchainConfig.ecip1099BlockNumber.toLong) val (dag, dagSize) = (currentEpoch, currentEpochDag, currentEpochDagSize) match { case (Some(`epoch`), Some(dag), Some(dagSize)) => (dag, dagSize) case _ => - val seed = EthashUtils.seed(epoch) + val seed = EthashUtils.seed(blockNumber) val dagSize = EthashUtils.dagSize(epoch) val dagNumHashes = (dagSize / EthashUtils.HASH_BYTES).toInt val dag = @@ -122,7 +122,7 @@ class EthashMiner( val outputStream = new FileOutputStream(dagFile(seed).getAbsolutePath) outputStream.write(DagFilePrefix.toArray[Byte]) - val cache = EthashUtils.makeCache(epoch) + val cache = EthashUtils.makeCache(epoch, seed) val res = new Array[Array[Int]](dagNumHashes) (0 until dagNumHashes).foreach { i => diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala index 473cb70e20..db8fb9f823 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala @@ -38,9 +38,6 @@ object EthashUtils { // cache growth per epoch final val CACHE_BYTES_GROWTH: Long = BigInt(2).pow(17).toLong - // blocks per epoch - final val EPOCH_LENGTH: Int = 30000 - // width of mix final val MIX_BYTES: Int = 128 @@ -56,14 +53,27 @@ object EthashUtils { // number of accesses in hashimoto loop final val ACCESSES: Int = 64 + // blocks per epoch (before ecip-1099) + final val EPOCH_LENGTH_BEFORE_ECIP_1099: Int = 30000 + + // blocks per epoch (after ecip-1099) + final val EPOCH_LENGTH_AFTER_ECIP_1099: Int = 60000 + // scalastyle:on magic.number - def seed(epoch: Long): ByteString = { + private def epochBeforeEcip1099(blockNumber: Long): Long = blockNumber / EPOCH_LENGTH_BEFORE_ECIP_1099 + + def seed(blockNumber: Long): ByteString = { + val epoch = epochBeforeEcip1099(blockNumber) (BigInt(0) until epoch) .foldLeft(ByteString(Hex.decode("00" * 32))) { case (b, _) => kec256(b) } } - def epoch(blockNumber: Long): Long = blockNumber / EPOCH_LENGTH + private def calcEpochLength(blockNumber: Long, ecip1099ActivationBlock: Long): Long = + if (blockNumber < ecip1099ActivationBlock) EPOCH_LENGTH_BEFORE_ECIP_1099 else EPOCH_LENGTH_AFTER_ECIP_1099 + + def epoch(blockNumber: Long, ecip1099ActivationBlock: Long): Long = + blockNumber / calcEpochLength(blockNumber, ecip1099ActivationBlock) def cacheSize(epoch: Long): Long = { val sz = (CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * epoch) - HASH_BYTES @@ -91,11 +101,11 @@ object EthashUtils { else isPrime(n, 3) } - def makeCache(epoch: Long): Array[Int] = { + def makeCache(epoch: Long, seed: ByteString): Array[Int] = { /* watch out, arrays are mutable here */ val n = (cacheSize(epoch) / HASH_BYTES).toInt - val s = seed(epoch).toArray[Byte] + val s = seed.toArray[Byte] val bytes = new Array[Array[Byte]](n) bytes(0) = kec512(s) diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala index 351547b837..25c3ccbaa7 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/validators/EthashBlockHeaderValidator.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus.ethash package validators +import akka.util.ByteString import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.ethash.difficulty.EthashDifficultyCalculator import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError @@ -8,6 +9,7 @@ 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 +import monix.execution.atomic.{Atomic, AtomicAny} /** * A block header validator for Ethash. @@ -17,9 +19,8 @@ class EthashBlockHeaderValidator(blockchainConfig: 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]() + // 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 = new EthashDifficultyCalculator(blockchainConfig) @@ -39,25 +40,21 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) protected def validatePoW(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { import EthashUtils._ - import scala.collection.JavaConverters._ - - def getPowCacheData(epoch: Long): PowCacheData = { - Option(powCaches.get(epoch)) match { - case Some(pcd) => pcd - case None => - val data = new PowCacheData(cache = EthashUtils.makeCache(epoch), dagSize = EthashUtils.dagSize(epoch)) - - val keys = powCaches.keySet().asScala - val keysToRemove = keys.toSeq.sorted.take(keys.size - MaxPowCaches + 1) - keysToRemove.foreach(powCaches.remove) - - powCaches.put(epoch, data) - - data + def getPowCacheData(epoch: Long, seed: ByteString): PowCacheData = { + powCaches.transformAndExtract { cache => + cache.find(_.epoch == epoch) match { + case Some(pcd) => (pcd, cache) + case None => + val data = + PowCacheData(epoch, cache = EthashUtils.makeCache(epoch, seed), dagSize = EthashUtils.dagSize(epoch)) + (data, (data :: cache).take(MaxPowCaches)) + } } } - val powCacheData = getPowCacheData(epoch(blockHeader.number.toLong)) + val epoch = EthashUtils.epoch(blockHeader.number.toLong, blockchainConfig.ecip1099BlockNumber.toLong) + val seed = EthashUtils.seed(blockHeader.number.toLong) + val powCacheData = getPowCacheData(epoch, seed) val proofOfWork = hashimotoLight( crypto.kec256(BlockHeader.getEncodedWithoutNonce(blockHeader)), @@ -75,5 +72,5 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) object EthashBlockHeaderValidator { final val MaxPowCaches: Int = 2 // maximum number of epochs for which PoW cache is stored in memory - class PowCacheData(val cache: Array[Int], val dagSize: Long) + case class PowCacheData(epoch: Long, cache: Array[Int], dagSize: Long) } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index 8907d3d474..c1466eb7bf 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala @@ -3,7 +3,6 @@ package io.iohk.ethereum.jsonrpc import java.time.Duration import java.util.Date import java.util.concurrent.atomic.AtomicReference - import akka.actor.ActorRef import akka.pattern.ask import akka.util.{ByteString, Timeout} @@ -12,6 +11,7 @@ import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress import io.iohk.ethereum.consensus.ConsensusConfig +import io.iohk.ethereum.consensus.ethash.EthashUtils import io.iohk.ethereum.crypto._ import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation import io.iohk.ethereum.domain.{BlockHeader, SignedTransaction, UInt256, _} @@ -30,7 +30,6 @@ import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.transactions.PendingTransactionsManager.{PendingTransaction, PendingTransactionsResponse} import io.iohk.ethereum.utils._ import org.bouncycastle.util.encoders.Hex - import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.concurrent.duration.FiniteDuration @@ -545,8 +544,6 @@ class EthService( def getWork(req: GetWorkRequest): ServiceResponse[GetWorkResponse] = consensus.ifEthash(ethash => { reportActive() - import io.iohk.ethereum.consensus.ethash.EthashUtils.{epoch, seed} - val bestBlock = blockchain.getBestBlock() val response: ServiceResponse[GetWorkResponse] = getOmmersFromPool(bestBlock.hash).zip(getTransactionsFromPool).map { case (ommers, pendingTxs) => @@ -560,7 +557,7 @@ class EthService( Right( GetWorkResponse( powHeaderHash = ByteString(kec256(BlockHeader.getEncodedWithoutNonce(pb.block.header))), - dagSeed = seed(epoch(pb.block.header.number.toLong)), + dagSeed = EthashUtils.seed(pb.block.header.number.toLong), target = ByteString((BigInt(2).pow(256) / pb.block.header.difficulty).toByteArray) ) ) diff --git a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala index 4261e75551..bb0a0173b3 100644 --- a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala +++ b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala @@ -40,7 +40,8 @@ case class BlockchainConfig( gasTieBreaker: Boolean, ethCompatibleStorage: Boolean, bootstrapNodes: Set[String], - checkpointPubKeys: Set[ByteString] = Set.empty + checkpointPubKeys: Set[ByteString] = Set.empty, + ecip1099BlockNumber: BigInt ) { val minRequireSignatures: Int = (Math.floor(checkpointPubKeys.size / 2) + 1).toInt } @@ -101,6 +102,8 @@ object BlockchainConfig { val bootstrapNodes: Set[String] = blockchainConfig.getStringList("bootstrap-nodes").asScala.toSet val checkpointPubKeys = readCheckpointPubKeys(blockchainConfig) + val ecip1099BlockNumber: BigInt = BigInt(blockchainConfig.getString("ecip1099-block-number")) + BlockchainConfig( frontierBlockNumber = frontierBlockNumber, homesteadBlockNumber = homesteadBlockNumber, @@ -132,7 +135,8 @@ object BlockchainConfig { gasTieBreaker = gasTieBreaker, ethCompatibleStorage = ethCompatibleStorage, bootstrapNodes = bootstrapNodes, - checkpointPubKeys = checkpointPubKeys + checkpointPubKeys = checkpointPubKeys, + ecip1099BlockNumber = ecip1099BlockNumber ) } // scalastyle:on method.length diff --git a/src/test/resources/application.conf b/src/test/resources/application.conf index 1ee101cb18..6635c1398b 100644 --- a/src/test/resources/application.conf +++ b/src/test/resources/application.conf @@ -32,6 +32,8 @@ mantis { byzantium-block-number = "4370000" + ecip1099-block-number = "1000000000000000000" + # todo change constantinople-block-number = "1000000000000000000" diff --git a/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala index ed96902bc1..08055726b5 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala @@ -204,7 +204,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) override lazy val blockExecution = @@ -268,7 +269,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) override lazy val blockExecution = @@ -510,7 +512,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) override lazy val blockchainConfig = baseBlockchainConfig diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala index 1d1d1017a7..351a6154ed 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashUtilsSpec.scala @@ -14,9 +14,11 @@ class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC import io.iohk.ethereum.consensus.ethash.EthashUtils._ + val ecip1099forkBlockNumber: Long = 11460000 + "Ethash" should "generate correct hash" in { forAll(Gen.choose[Long](0, 15000000L)) { blockNumber => - seed(epoch(blockNumber)) shouldBe seedForBlockReference(blockNumber) + seed(blockNumber) shouldBe seedForBlockReference(blockNumber) } } @@ -27,6 +29,19 @@ class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC } } + it should "calculate epoch" in { + val table = Table( + ("blockNUmber", "epoch", "ecip1099ActivationBlockNumber"), + (11459999, 381, Long.MaxValue), + (11460000, 382, Long.MaxValue), + (11459999, 381, ecip1099forkBlockNumber), + (11460000, 191, ecip1099forkBlockNumber) + ) + forAll(table) { (blockNUmber, _epoch, ecip1099BlockNumber) => + epoch(blockNUmber, ecip1099BlockNumber) shouldEqual _epoch + } + } + it should "compute proof of work using cache" in { val hash = Array(0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72).map(_.toByte) @@ -38,8 +53,10 @@ class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84).map(_.toByte) val blockNumber = 486382 - val cache = makeCache(epoch(blockNumber)) - val proofOfWork = hashimotoLight(hash, nonce, dagSize(epoch(blockNumber)), cache) + val _epoch = epoch(blockNumber, ecip1099forkBlockNumber) + val _seed = seed(blockNumber) + val cache = makeCache(_epoch, _seed) + val proofOfWork = hashimotoLight(hash, nonce, dagSize(_epoch), cache) proofOfWork.mixHash shouldBe ByteString(mixHash) proofOfWork.difficultyBoundary shouldBe ByteString(boundary) @@ -109,9 +126,11 @@ class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC ) forAll(table) { (blockNumber, hashWithoutNonce, nonce, mixHash) => - val cache = makeCache(epoch(blockNumber)) + val _epoch = epoch(blockNumber, ecip1099forkBlockNumber) + val _seed = seed(blockNumber) + val cache = makeCache(_epoch, _seed) val proofOfWork = - hashimotoLight(Hex.decode(hashWithoutNonce), Hex.decode(nonce), dagSize(epoch(blockNumber)), cache) + hashimotoLight(Hex.decode(hashWithoutNonce), Hex.decode(nonce), dagSize(_epoch), cache) proofOfWork.mixHash shouldBe ByteString(Hex.decode(mixHash)) } } @@ -119,10 +138,10 @@ class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC def seedForBlockReference(blockNumber: BigInt): ByteString = { @tailrec def go(current: BigInt, currentHash: ByteString): ByteString = { - if (current < EPOCH_LENGTH) { + if (current < EPOCH_LENGTH_BEFORE_ECIP_1099) { currentHash } else { - go(current - EPOCH_LENGTH, kec256(currentHash)) + go(current - EPOCH_LENGTH_BEFORE_ECIP_1099, kec256(currentHash)) } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSpec.scala index 5e034fb84d..b09e29f112 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSpec.scala @@ -469,7 +469,8 @@ class BlockHeaderValidatorSpec petersburgBlockNumber = Long.MaxValue, ecip1098BlockNumber = Long.MaxValue, treasuryAddress = Address(0), - ecip1097BlockNumber = Long.MaxValue + ecip1097BlockNumber = Long.MaxValue, + ecip1099BlockNumber = Long.MaxValue ) } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index a6c17a2591..5185fc6e26 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 petersburgBlockNumber = 0, ecip1098BlockNumber = 0, treasuryAddress = Address(0), - ecip1097BlockNumber = 0 + ecip1097BlockNumber = 0, + ecip1099BlockNumber = Long.MaxValue ) val wallet = Wallet(address, prvKey) diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index 5b03ece192..1b0e6b6107 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -133,7 +133,8 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { petersburgBlockNumber = 0, ecip1098BlockNumber = 0, treasuryAddress = Address(0), - ecip1097BlockNumber = 0 + ecip1097BlockNumber = 0, + ecip1099BlockNumber = Long.MaxValue ) override lazy val stxLedger = new StxLedger(blockchain, blockchainConfig, consensus.blockPreparator)