Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 5 additions & 5 deletions src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
_ <- peer2.connectToPeers(Set(peer1.node))
_ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber)
} yield {
assert(peer1.bl.getBestBlock().hash == peer2.bl.getBestBlock().hash)
assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
}
}

Expand All @@ -52,7 +52,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
_ <- peer2.connectToPeers(Set(peer1.node))
_ <- peer2.waitForRegularSyncLoadLastBlock(blockHeadersPerRequest + 1)
} yield {
assert(peer1.bl.getBestBlock().hash == peer2.bl.getBestBlock().hash)
assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
}
}
}
Expand All @@ -72,7 +72,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
_ <- peer1.mineNewBlocks(100.milliseconds, 2)(IdentityUpdate)
_ <- peer2.waitForRegularSyncLoadLastBlock(blockNumer + 4)
} yield {
assert(peer1.bl.getBestBlock().hash == peer2.bl.getBestBlock().hash)
assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
}
}

Expand All @@ -94,8 +94,8 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
_ <- peer2.waitForRegularSyncLoadLastBlock(blockNumer + 3)
} yield {
assert(
peer1.bl.getChainWeightByHash(peer1.bl.getBestBlock().hash) == peer2.bl.getChainWeightByHash(
peer2.bl.getBestBlock().hash
peer1.bl.getChainWeightByHash(peer1.bl.getBestBlock().get.hash) == peer2.bl.getChainWeightByHash(
peer2.bl.getBestBlock().get.hash
)
)
(peer1.bl.getBlockByNumber(blockNumer + 1), peer2.bl.getBlockByNumber(blockNumer + 1)) match {
Expand Down
10 changes: 5 additions & 5 deletions src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu
}

def getCurrentState(): BlockchainState = {
val bestBlock = bl.getBestBlock()
val bestBlock = bl.getBestBlock().get
val currentWorldState = getMptForBlock(bestBlock)
val currentWeight = bl.getChainWeightByHash(bestBlock.hash).get
BlockchainState(bestBlock, currentWorldState, currentWeight)
Expand Down Expand Up @@ -301,13 +301,13 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu
n: BigInt
)(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = {
Task(bl.getBestBlock()).flatMap { block =>
if (block.number >= n) {
if (block.get.number >= n) {
Task(())
} else {
Task {
val currentWeight = bl.getChainWeightByHash(block.hash).get
val currentWolrd = getMptForBlock(block)
val (newBlock, newWeight, _) = createChildBlock(block, currentWeight, currentWolrd)(updateWorldForBlock)
val currentWeight = bl.getChainWeightByHash(block.get.hash).get
val currentWolrd = getMptForBlock(block.get)
val (newBlock, newWeight, _) = createChildBlock(block.get, currentWeight, currentWolrd)(updateWorldForBlock)
bl.save(newBlock, Seq(), newWeight, saveAsBestBlock = true)
broadcastBlock(newBlock, newWeight)
}.flatMap(_ => importBlocksUntil(n)(updateWorldForBlock))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ object FastSyncItSpecUtils {
// Reads whole trie into memory, if the trie lacks nodes in storage it will be None
def getBestBlockTrie(): Option[MptNode] = {
Try {
val bestBlock = bl.getBestBlock()
val bestBlock = bl.getBestBlock().get
val bestStateRoot = bestBlock.header.stateRoot
MptTraversals.parseTrieIntoMemory(
HashNode(bestStateRoot.toArray),
Expand Down Expand Up @@ -99,7 +99,7 @@ object FastSyncItSpecUtils {

def startWithState(): Task[Unit] = {
Task {
val currentBest = bl.getBestBlock().header
val currentBest = bl.getBestBlock().get.header
val safeTarget = currentBest.number + syncConfig.fastSyncBlockValidationX
val nextToValidate = currentBest.number + 1
val syncState =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ object RegularSyncItSpecUtils {
Task(blockNumber match {
case Some(bNumber) =>
bl.getBlockByNumber(bNumber).getOrElse(throw new RuntimeException(s"block by number: $bNumber doesn't exist"))
case None => bl.getBestBlock()
case None => bl.getBestBlock().get
}).flatMap { block =>
Task {
val currentWeight = bl
Expand All @@ -112,7 +112,7 @@ object RegularSyncItSpecUtils {
def mineNewBlock(
plusDifficulty: BigInt = 0
)(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task {
val block: Block = bl.getBestBlock()
val block: Block = bl.getBestBlock().get
val currentWeight = bl
.getChainWeightByHash(block.hash)
.getOrElse(throw new RuntimeException(s"ChainWeight by hash: ${block.hash} doesn't exist"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain {

def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit = ???

def getBestBlock(): Block = ???
def getBestBlock(): Option[Block] = ???

override def save(block: Block, receipts: Seq[Receipt], weight: ChainWeight, saveAsBestBlock: Boolean): Unit = ???

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ class EthashBlockCreator(
withTransactions: Boolean = true,
initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] = None
): Task[PendingBlockAndState] = {
val transactions =
if (withTransactions) getTransactionsFromPool else Task.now(PendingTransactionsResponse(Nil))
val transactions = if (withTransactions) getTransactionsFromPool else Task.now(PendingTransactionsResponse(Nil))
Task.parZip2(getOmmersFromPool(parentBlock.hash), transactions).map { case (ommers, pendingTxs) =>
blockGenerator.generateBlock(
parentBlock,
Expand Down
69 changes: 38 additions & 31 deletions src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,39 +56,46 @@ class EthashMiner(
}

def processMining(): Unit = {
val parentBlock = blockchain.getBestBlock()
val blockNumber = parentBlock.header.number.toLong + 1
val epoch = EthashUtils.epoch(blockNumber, blockCreator.blockchainConfig.ecip1099BlockNumber.toLong)
val (dag, dagSize) = calculateDagSize(blockNumber, epoch)

blockCreator
.getBlockForMining(parentBlock)
.map { case PendingBlockAndState(PendingBlock(block, _), _) =>
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")
blockchain.getBestBlock() match {
case Some(blockValue) =>
blockCreator
.getBlockForMining(blockValue)
.map {
case PendingBlockAndState(PendingBlock(block, _), _) => {
val blockNumber = block.header.number.toLong + 1
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)
}
.runAsyncAndForget
}
}

private def calculateDagSize(blockNumber: Long, epoch: Long): (Array[Array[Int]], Long) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class MockedMiner(
}
case None =>
val parentBlock = blockchain.getBestBlock()
startMiningBlocks(mineBlocks, parentBlock)
startMiningBlocks(mineBlocks, parentBlock.get)
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/io/iohk/ethereum/domain/Blockchain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ trait Blockchain {

def getBestBlockNumber(): BigInt

def getBestBlock(): Block
def getBestBlock(): Option[Block]

def getLatestCheckpointBlockNumber(): BigInt

Expand Down Expand Up @@ -276,10 +276,10 @@ class BlockchainImpl(
override def getLatestCheckpointBlockNumber(): BigInt =
bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber

override def getBestBlock(): Block = {
override def getBestBlock(): Option[Block] = {
val bestBlockNumber = getBestBlockNumber()
log.debug("Trying to get best block with number {}", bestBlockNumber)
getBlockByNumber(bestBlockNumber).get
getBlockByNumber(bestBlockNumber)
}

override def getAccount(address: Address, blockNumber: BigInt): Option[Account] =
Expand Down
41 changes: 22 additions & 19 deletions src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,29 @@ class EthMiningService(
def getWork(req: GetWorkRequest): ServiceResponse[GetWorkResponse] =
consensus.ifEthash(ethash => {
reportActive()
val bestBlock = blockchain.getBestBlock()
val response: ServiceResponse[GetWorkResponse] =
Task.parZip2(getOmmersFromPool(bestBlock.hash), getTransactionsFromPool).map { case (ommers, pendingTxs) =>
val blockGenerator = ethash.blockGenerator
val PendingBlockAndState(pb, _) = blockGenerator.generateBlock(
bestBlock,
pendingTxs.pendingTransactions.map(_.stx.tx),
consensusConfig.coinbase,
ommers.headers,
None
)
Right(
GetWorkResponse(
powHeaderHash = ByteString(kec256(BlockHeader.getEncodedWithoutNonce(pb.block.header))),
dagSeed = EthashUtils.seed(pb.block.header.number.toLong),
target = ByteString((BigInt(2).pow(256) / pb.block.header.difficulty).toByteArray)
blockchain.getBestBlock() match {
case Some(block) =>
Task.parZip2(getOmmersFromPool(block.hash), getTransactionsFromPool).map { case (ommers, pendingTxs) =>
val blockGenerator = ethash.blockGenerator
val PendingBlockAndState(pb, _) = blockGenerator.generateBlock(
block,
pendingTxs.pendingTransactions.map(_.stx.tx),
consensusConfig.coinbase,
ommers.headers,
None
)
)
}
response
Right(
GetWorkResponse(
powHeaderHash = ByteString(kec256(BlockHeader.getEncodedWithoutNonce(pb.block.header))),
dagSeed = EthashUtils.seed(pb.block.header.number.toLong),
target = ByteString((BigInt(2).pow(256) / pb.block.header.difficulty).toByteArray)
)
)
}
case None =>
log.error("Getting current best block failed")
Task.now(Left(JsonRpcError.InternalError))
}
})(Task.now(Left(JsonRpcError.ConsensusIsNotEthash)))

def submitWork(req: SubmitWorkRequest): ServiceResponse[SubmitWorkResponse] =
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object JsonRpcError extends JsonMethodsImplicits {

def executionError(reasons: List[EthCustomError]): JsonRpcError = JsonRpcError(3, "Execution error", reasons)
val NodeNotFound = executionError(List(EthCustomError.DoesntExist("State node")))
val BlockNotFound = executionError(List(EthCustomError.DoesntExist("Block")))

// Custom errors based on proposal https://eth.wiki/json-rpc/json-rpc-error-codes-improvement-proposal
sealed abstract class EthCustomError private (val code: Int, val message: String)
Expand Down
14 changes: 9 additions & 5 deletions src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@ class QAService(
def generateCheckpoint(
req: GenerateCheckpointRequest
): ServiceResponse[GenerateCheckpointResponse] = {
Task {
val hash = req.blockHash.getOrElse(blockchain.getBestBlock().hash)
val checkpoint = generateCheckpoint(hash, req.privateKeys)
syncController ! NewCheckpoint(hash, checkpoint.signatures)
Right(GenerateCheckpointResponse(checkpoint))
val hash = req.blockHash.orElse(blockchain.getBestBlock().map(_.hash))
hash match {
case Some(hashValue) =>
Task {
val checkpoint = generateCheckpoint(hashValue, req.privateKeys)
syncController ! NewCheckpoint(hashValue, checkpoint.signatures)
Right(GenerateCheckpointResponse(checkpoint))
}
case None => Task.now(Left(JsonRpcError.BlockNotFound))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class TestService(

def mineBlocks(request: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = {
def mineBlock(): Task[Unit] = {
getBlockForMining(blockchain.getBestBlock()).map { blockForMining =>
getBlockForMining(blockchain.getBestBlock().get).map { blockForMining =>
val res = testLedgerWrapper.ledger.importBlock(blockForMining.block)
log.info("Block mining result: " + res)
pendingTransactionsManager ! PendingTransactionsManager.ClearPendingTransactions
Expand Down
47 changes: 24 additions & 23 deletions src/main/scala/io/iohk/ethereum/ledger/Ledger.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,31 +119,32 @@ class LedgerImpl(

override def importBlock(
block: Block
)(implicit blockExecutionScheduler: Scheduler): Task[BlockImportResult] = {

val currentBestBlock = blockchain.getBestBlock()

if (isBlockADuplicate(block.header, currentBestBlock.header.number)) {
Task(log.debug(s"Ignoring duplicate block: (${block.idTag})"))
.map(_ => DuplicateBlock)
} else {
val hash = currentBestBlock.header.hash
blockchain.getChainWeightByHash(hash) match {
case Some(weight) =>
val importResult = if (isPossibleNewBestBlock(block.header, currentBestBlock.header)) {
blockImport.importToTop(block, currentBestBlock, weight)
} else {
blockImport.reorganise(block, currentBestBlock, weight)
)(implicit blockExecutionScheduler: Scheduler): Task[BlockImportResult] =
blockchain.getBestBlock() match {
case Some(bestBlock) =>
if (isBlockADuplicate(block.header, bestBlock.header.number)) {
Task(log.debug(s"Ignoring duplicate block: (${block.idTag})"))
.map(_ => DuplicateBlock)
} else {
val hash = bestBlock.header.hash
blockchain.getChainWeightByHash(hash) match {
case Some(weight) =>
val importResult = if (isPossibleNewBestBlock(block.header, bestBlock.header)) {
blockImport.importToTop(block, bestBlock, weight)
} else {
blockImport.reorganise(block, bestBlock, weight)
}
importResult.foreach(measureBlockMetrics)
importResult
case None =>
log.error(s"Getting total difficulty for current best block with hash: $hash failed")
Task.now(BlockImportFailed(s"Couldn't get total difficulty for current best block with hash: $hash"))
}
importResult.foreach(measureBlockMetrics)
importResult

case None =>
Task.now(BlockImportFailed(s"Couldn't get total difficulty for current best block with hash: $hash"))

}
}
case None =>
log.error("Getting current best block failed")
Task.now(BlockImportFailed(s"Couldn't find the current best block"))
}
}

private def isBlockADuplicate(block: BlockHeader, currentBestBlockNumber: BigInt): Boolean = {
val hash = block.hash
Expand Down
Loading