Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[ETCM-109] ECIP-1099 implementation #764

Merged
merged 6 commits into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(
Expand Down Expand Up @@ -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"))
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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")
)
)
}

Expand All @@ -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)
Expand All @@ -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))
}
4 changes: 4 additions & 0 deletions src/main/resources/chains/etc-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
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 {
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/chains/eth-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
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 {
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/chains/mordor-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
ecip1097-block-number = "1000000000000000000"


# Epoch calibration block number
# https://ecips.ethereumclassic.org/ECIPs/ecip-1099
ecip1099-block-number = "2520000"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has already been reached on Mordor, right? Have we synced and try it there already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I will sync with the Mordor before the merge


# DAO fork configuration (Ethereum HF/Classic split)
# https://blog.ethereum.org/2016/07/20/hard-fork-completed/
dao = null
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/chains/ropsten-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
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 {
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/chains/test-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
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 {
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/chains/testnet-internal-chain.conf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
# https://ecips.ethereumclassic.org/ECIPs/ecip-1097
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not accepting BigInt there? I mean - if domain uses BigInt for block numbers, why shouldn't miner?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we are using only Longs in EthashUtils. I am not sure if we do that because of performance or sth else, but I don't want to change that in this pr.

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 =
Expand Down Expand Up @@ -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 =>
Expand Down
24 changes: 17 additions & 7 deletions src/main/scala/io/iohk/ethereum/consensus/ethash/EthashUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -41,11 +42,11 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig)

import scala.collection.JavaConverters._

def getPowCacheData(epoch: Long): PowCacheData = {
def getPowCacheData(epoch: Long, seed: ByteString): 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 data = new PowCacheData(cache = EthashUtils.makeCache(epoch, seed), dagSize = EthashUtils.dagSize(epoch))

val keys = powCaches.keySet().asScala
val keysToRemove = keys.toSeq.sorted.take(keys.size - MaxPowCaches + 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it won't make problems during transition. i.e

  1. lets say we have epoch 358 and 359 here.
  2. we enter fork block ecip-1099 so next epoch is 180 instead of 360
  3. so we put dag cache for this epoch in cache, and we have there dag for epoch 180 and 359 (as we have limit of 2 dag caches max, and we always removes oldest one)
  4. after some blocks we arive at epoch 181. And now we will remove dag cache for epoch 180 instead on 359 .
    It means dag dag cache for epoch 359 will be with us for long time (until we get to new epoch 360), and if rollbacks happen accross new epoch boundaries we will need to recreate dag caches. (we have one stale in there, and we have max size of 2 dag caches )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I fixed that

Expand All @@ -57,7 +58,9 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig)
}
}

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)),
Expand Down
7 changes: 2 additions & 5 deletions src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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, _}
Expand All @@ -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
Expand Down Expand Up @@ -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) =>
Expand All @@ -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)
)
)
Expand Down
Loading