From 11b5be03c85dde6f1e193f0d94967705c85dc4a0 Mon Sep 17 00:00:00 2001 From: Michal Mrozek Date: Fri, 6 Nov 2020 15:36:50 +0100 Subject: [PATCH 1/4] [ETCM-301] Fix block preparation --- .../ets/blockchain/ScenarioSetup.scala | 12 +++++++++--- .../ethereum/sync/util/CommonFakePeer.scala | 2 +- .../sync/util/RegularSyncItSpecUtils.scala | 2 +- .../txExecTest/util/DumpChainApp.scala | 4 ++-- .../blocks/BlockGeneratorSkeleton.scala | 6 +++--- .../io/iohk/ethereum/domain/Blockchain.scala | 8 ++++---- .../io/iohk/ethereum/jsonrpc/EthService.scala | 2 +- .../iohk/ethereum/ledger/BlockExecution.scala | 8 +++++++- .../ethereum/ledger/BlockPreparator.scala | 7 +++---- .../ledger/InMemoryWorldStateProxy.scala | 7 ++----- .../io/iohk/ethereum/ledger/Ledger.scala | 6 +----- .../io/iohk/ethereum/ledger/StxLedger.scala | 2 +- .../io/iohk/ethereum/snappy/SnappyTest.scala | 9 +++++---- .../blockchain/sync/StateSyncUtils.scala | 3 ++- .../ethereum/jsonrpc/EthServiceSpec.scala | 4 ++-- .../ethereum/ledger/BlockImportSpec.scala | 18 +++++++++++++++--- .../ethereum/ledger/BlockRewardSpec.scala | 12 ++++++++++-- .../ethereum/ledger/DeleteAccountsSpec.scala | 10 +++++++++- .../ledger/DeleteTouchedAccountsSpec.scala | 18 ++++++++++++++++-- .../ledger/InMemoryWorldStateProxySpec.scala | 19 +++++++++++++------ .../ethereum/ledger/LedgerTestSetup.scala | 15 ++++++++++----- .../iohk/ethereum/ledger/StxLedgerSpec.scala | 11 +++++++++-- 22 files changed, 126 insertions(+), 59 deletions(-) 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 ec54acabd8..78e3aed718 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala @@ -1,7 +1,7 @@ package io.iohk.ethereum.ets.blockchain +import akka.util.ByteString import java.util.concurrent.Executors - import io.iohk.ethereum.consensus.ethash.EthashConsensus import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, TestConsensus, ethash} @@ -13,10 +13,10 @@ import io.iohk.ethereum.domain._ import io.iohk.ethereum.ets.common.AccountState import io.iohk.ethereum.ledger.Ledger.VMImpl import io.iohk.ethereum.ledger._ +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.BigIntExtensionMethods._ import io.iohk.ethereum.utils.{BlockchainConfig, Config} import org.bouncycastle.util.encoders.Hex - import scala.concurrent.ExecutionContext import scala.util.{Failure, Success, Try} @@ -60,7 +60,13 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) { val consensus: TestConsensus = ScenarioSetup.loadEthashConsensus(_vm, blockchain, blockchainConfig, validators) val emptyWorld: InMemoryWorldStateProxy = - blockchain.getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + blockchain.getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) val ledger = new LedgerImpl( diff --git a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala index 0d7adfdb9d..a3f303b1e8 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala @@ -223,7 +223,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu bl.getWorldStateProxy( blockNumber = block.number, accountStartNonce = blockchainConfig.accountStartNonce, - stateRootHash = Some(block.header.stateRoot), + stateRootHash = block.header.stateRoot, noEmptyAccounts = EvmConfig.forBlock(block.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) 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 0fed272a32..8f90846884 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala @@ -133,7 +133,7 @@ object RegularSyncItSpecUtils { bl.getWorldStateProxy( blockNumber = block.number, accountStartNonce = blockchainConfig.accountStartNonce, - stateRootHash = Some(block.header.stateRoot), + stateRootHash = block.header.stateRoot, noEmptyAccounts = EvmConfig.forBlock(block.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index 396d779fe8..a1b5e4bbfa 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -173,7 +173,7 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { override def getWorldStateProxy( blockNumber: BigInt, accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): InMemoryWorldStateProxy = ??? @@ -181,7 +181,7 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { override def getReadOnlyWorldStateProxy( blockNumber: Option[BigInt], accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): InMemoryWorldStateProxy = ??? 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 078332d1b9..cc93b8627c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala @@ -13,7 +13,7 @@ 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.ledger.Ledger.{BlockPreparationResult, BlockResult} +import io.iohk.ethereum.ledger.Ledger.{PreparedBlock, BlockResult} import io.iohk.ethereum.ledger.{BlockPreparator, BloomFilter} import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} import io.iohk.ethereum.utils.BlockchainConfig @@ -99,8 +99,8 @@ abstract class BlockGeneratorSkeleton( val body = newBlockBody(transactionsForBlock, x) val block = Block(header, body) - val prepared = blockPreparator.prepareBlock(block) match { - case BlockPreparationResult(prepareBlock, BlockResult(_, gasUsed, receipts), stateRoot, updatedWorld) => + val prepared = blockPreparator.prepareBlock(block, parent.header) match { + case PreparedBlock(prepareBlock, BlockResult(_, gasUsed, receipts), stateRoot, updatedWorld) => val receiptsLogs: Seq[Array[Byte]] = BloomFilter.EmptyBloomFilter.toArray +: receipts.map(_.logsBloomFilter.toArray) val bloomFilter = ByteString(or(receiptsLogs: _*)) diff --git a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala index 296176bf63..942ad73886 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala @@ -183,7 +183,7 @@ trait Blockchain { def getWorldStateProxy( blockNumber: BigInt, accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): WS @@ -191,7 +191,7 @@ trait Blockchain { def getReadOnlyWorldStateProxy( blockNumber: Option[BigInt], accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): WS @@ -467,7 +467,7 @@ class BlockchainImpl( override def getWorldStateProxy( blockNumber: BigInt, accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): InMemoryWorldStateProxy = @@ -485,7 +485,7 @@ class BlockchainImpl( override def getReadOnlyWorldStateProxy( blockNumber: Option[BigInt], accountStartNonce: UInt256, - stateRootHash: Option[ByteString], + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): InMemoryWorldStateProxy = diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index d76f278793..3c83b11eed 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala @@ -695,7 +695,7 @@ class EthService( val world = blockchain.getWorldStateProxy( block.header.number, blockchainConfig.accountStartNonce, - Some(block.header.stateRoot), + block.header.stateRoot, noEmptyAccounts = false, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala index 94eff9d5b7..7d1d920e47 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala @@ -67,7 +67,13 @@ class BlockExecution( * @param block the block with transactions to run */ private[ledger] def executeBlockTransactions(block: Block): Either[BlockExecutionError, BlockResult] = { - val parentStateRoot = blockchain.getBlockHeaderByHash(block.header.parentHash).map(_.stateRoot) + val parentStateRoot = + blockchain + .getBlockHeaderByHash(block.header.parentHash) + .map(_.stateRoot) + .getOrElse( + throw new IllegalStateException("Cannot find parent") + ) // Should not never occur because validated earlier val blockHeaderNumber = block.header.number val initialWorld = blockchain.getWorldStateProxy( blockNumber = blockHeaderNumber, diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala index 520bb961a9..16967f3964 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala @@ -376,12 +376,11 @@ class BlockPreparator( } } - def prepareBlock(block: Block): BlockPreparationResult = { - val parentStateRoot = blockchain.getBlockHeaderByHash(block.header.parentHash).map(_.stateRoot) + def prepareBlock(block: Block, parent: BlockHeader): PreparedBlock = { val initialWorld = blockchain.getReadOnlyWorldStateProxy( None, blockchainConfig.accountStartNonce, - parentStateRoot, + parent.stateRoot, noEmptyAccounts = EvmConfig.forBlock(block.header.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) @@ -391,7 +390,7 @@ class BlockPreparator( case (execResult @ BlockResult(resultingWorldStateProxy, _, _), txExecuted) => val worldToPersist = payBlockReward(block, resultingWorldStateProxy) val worldPersisted = InMemoryWorldStateProxy.persistState(worldToPersist) - BlockPreparationResult( + PreparedBlock( block.copy(body = block.body.copy(transactionList = txExecuted)), execResult, worldPersisted.stateRootHash, diff --git a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala index b9e97cd282..dfd326664f 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala @@ -18,14 +18,11 @@ object InMemoryWorldStateProxy { nodesKeyValueStorage: MptStorage, accountStartNonce: UInt256, getBlockHashByNumber: BigInt => Option[ByteString], - stateRootHash: Option[ByteString] = None, + stateRootHash: ByteString, noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean ): InMemoryWorldStateProxy = { - val accountsStateTrieProxy = createProxiedAccountsStateTrie( - nodesKeyValueStorage, - stateRootHash.getOrElse(ByteString(MerklePatriciaTrie.EmptyRootHash)) - ) + val accountsStateTrieProxy = createProxiedAccountsStateTrie(nodesKeyValueStorage, stateRootHash) new InMemoryWorldStateProxy( nodesKeyValueStorage, accountsStateTrieProxy, diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index 1894328b20..e5f526f407 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -163,7 +163,7 @@ object Ledger { type PR = ProgramResult[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] case class BlockResult(worldState: InMemoryWorldStateProxy, gasUsed: BigInt = 0, receipts: Seq[Receipt] = Nil) - case class BlockPreparationResult( + case class PreparedBlock( block: Block, blockResult: BlockResult, stateRootHash: ByteString, @@ -184,7 +184,3 @@ sealed trait BlockStatus case object InChain extends BlockStatus case object Queued extends BlockStatus case object UnknownBlock extends BlockStatus - -trait BlockPreparationError - -case class TxError(reason: String) extends BlockPreparationError diff --git a/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala b/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala index c03a8b7d50..8d46ad0470 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala @@ -18,7 +18,7 @@ class StxLedger(blockchain: BlockchainImpl, blockchainConfig: BlockchainConfig, blockchain.getReadOnlyWorldStateProxy( blockNumber = None, accountStartNonce = blockchainConfig.accountStartNonce, - stateRootHash = Some(blockHeader.stateRoot), + stateRootHash = blockHeader.stateRoot, noEmptyAccounts = EvmConfig.forBlock(blockHeader.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) diff --git a/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala b/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala index 9c0069f904..c02aa6fedd 100644 --- a/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala +++ b/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala @@ -66,9 +66,10 @@ class SnappyTest extends AnyFreeSpec with Matchers with Logger { new BlockExecution(blockchain, blockchainConfig, consensus.blockPreparator, blockValidation) blockExecution.executeAndValidateBlock(block) - case None => - // this seems to discard failures, for better errors messages we might want to implement a different method (simulateBlock?) - val result = blockPreparator.prepareBlock(block) - Right(result.blockResult.receipts) + case None => throw new NotImplementedError() +// // this seems to discard failures, for better errors messages we might want to implement a different method (simulateBlock?) +// val result = blockPreparator.prepareBlock(block) +// Right(result.blockResult.receipts) +// FIXME DO WE NEED THAT? } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala index 6f2fac239e..76eff7f2d5 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala @@ -4,6 +4,7 @@ import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.SyncStateScheduler.SyncResponse import io.iohk.ethereum.domain.{Account, Address, Blockchain, BlockchainImpl} import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.{BlockchainConfig, ByteUtils} object StateSyncUtils extends EphemBlockchainTestSetup { @@ -34,7 +35,7 @@ object StateSyncUtils extends EphemBlockchainTestSetup { .getWorldStateProxy( blockNumber = 1, accountStartNonce = blockchainConfig.accountStartNonce, - stateRootHash = existingTree, + stateRootHash = existingTree.getOrElse(ByteString(MerklePatriciaTrie.EmptyRootHash)), noEmptyAccounts = true, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala index e857d17254..0af7699bb9 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala @@ -586,7 +586,7 @@ class EthServiceSpec val txResult = TxResult( BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true), + .getWorldStateProxy(-1, UInt256.Zero, ByteString.empty, noEmptyAccounts = false, ethCompatibleStorage = true), 123, Nil, ByteString("return_value"), @@ -1345,7 +1345,7 @@ class EthServiceSpec val fakeWorld = blockchain.getReadOnlyWorldStateProxy( None, UInt256.Zero, - None, + ByteString.empty, noEmptyAccounts = false, ethCompatibleStorage = true ) diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala index 77a3302b5f..a535a8adde 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala @@ -8,8 +8,8 @@ import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderDifficultyE import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockQueue.Leaf +import io.iohk.ethereum.mpt.MerklePatriciaTrie import org.scalatest.concurrent.ScalaFutures - import scala.concurrent.duration._ import scala.language.postfixOps import org.scalatest.flatspec.AnyFlatSpec @@ -47,7 +47,13 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val newWeight = currentWeight.increaseTotalDifficulty(difficulty) val blockData = BlockData(block, Seq.empty[Receipt], newWeight) val emptyWorld: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) // Just to bypass metrics needs (blockchain.getBlockByHash _).expects(*).returning(None) @@ -79,7 +85,13 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { (blockQueue.getBranch _).expects(hash, true).returning(List(block)) val emptyWorld: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) (blockchain.getBlockHeaderByHash _).expects(*).returning(Some(block.header)) (blockchain.getWorldStateProxy _).expects(*, *, *, *, *).returning(emptyWorld) diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala index a26570c248..f1e7d03b9e 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.ledger +import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.{HefPostEcip1098, HefEmpty} +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.{HefEmpty, HefPostEcip1098} import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockPreparator._ import io.iohk.ethereum.ledger.Ledger.VMImpl import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec @@ -184,7 +186,13 @@ class BlockRewardSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC val afterByzantiumNewBlockReward: BigInt = BigInt(10).pow(18) * 3 val worldState: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) .saveAccount(validAccountAddress, Account(balance = 10)) .saveAccount(validAccountAddress2, Account(balance = 20)) .saveAccount(validAccountAddress3, Account(balance = 30)) diff --git a/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala index bed3cff7ad..3a9fa66b06 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.ledger +import akka.util.ByteString import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, UInt256} import io.iohk.ethereum.ledger.Ledger.VMImpl +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig import org.scalamock.scalatest.MockFactory @@ -65,7 +67,13 @@ class DeleteAccountsSpec extends AnyFlatSpec with Matchers with MockFactory { val worldStateWithoutPersist: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) .saveAccount(validAccountAddress, Account(balance = 10)) .saveAccount(validAccountAddress2, Account(balance = 20)) .saveAccount(validAccountAddress3, Account(balance = 30)) diff --git a/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala index fc022f658b..9e368d06a1 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.ledger +import akka.util.ByteString import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, UInt256} import io.iohk.ethereum.ledger.Ledger.VMImpl +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.vm.{BlockchainConfigForEvm, EvmConfig} @@ -159,7 +161,13 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers with MockFacto val worldStateWithoutPersist: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, postEip161Config.noEmptyAccounts, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + postEip161Config.noEmptyAccounts, + ethCompatibleStorage = true + ) .saveAccount(validAccountAddress, Account(balance = validAccountBalance)) .saveAccount(validAccountAddress2, Account(balance = 20)) .saveAccount(validAccountAddress3, Account(balance = 30)) @@ -168,7 +176,13 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers with MockFacto val worldStateWithoutPersistPreEIP161: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, postEip160Config.noEmptyAccounts, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + postEip160Config.noEmptyAccounts, + ethCompatibleStorage = true + ) .saveAccount(validAccountAddress, Account(balance = validAccountBalance)) .saveAccount(validAccountAddress2, Account(balance = 20)) .saveAccount(validAccountAddress3, Account(balance = 30)) diff --git a/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala b/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala index 71e1bcb530..e9c1d27498 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala @@ -3,6 +3,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, UInt256} +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.vm.{EvmConfig, Generators} import org.bouncycastle.util.encoders.Hex @@ -125,7 +126,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { val newWorldState = BlockchainImpl(storagesInstance.storages).getWorldStateProxy( -1, UInt256.Zero, - Some(persistedWorldState.stateRootHash), + persistedWorldState.stateRootHash, noEmptyAccounts = true, ethCompatibleStorage = true ) @@ -255,7 +256,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { blockchain.getReadOnlyWorldStateProxy( None, UInt256.Zero, - Some(persistedWorldStateWithAnAccount.stateRootHash), + persistedWorldStateWithAnAccount.stateRootHash, noEmptyAccounts = false, ethCompatibleStorage = false ) @@ -275,7 +276,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { val newReadWorld = blockchain.getReadOnlyWorldStateProxy( None, UInt256.Zero, - Some(changedReadWorld.stateRootHash), + changedReadWorld.stateRootHash, noEmptyAccounts = false, ethCompatibleStorage = false ) @@ -301,7 +302,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { val world2 = blockchain.getWorldStateProxy( -1, UInt256.Zero, - Some(world1.stateRootHash), + world1.stateRootHash, noEmptyAccounts = false, ethCompatibleStorage = true ) @@ -323,11 +324,17 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { val postEip161Config = EvmConfig.PostEIP161ConfigBuilder(io.iohk.ethereum.vm.Fixtures.blockchainConfig) val worldState = - blockchain.getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + blockchain.getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) val postEIP161WorldState = blockchain.getWorldStateProxy( -1, UInt256.Zero, - None, + ByteString(MerklePatriciaTrie.EmptyRootHash), noEmptyAccounts = postEip161Config.noEmptyAccounts, ethCompatibleStorage = false ) diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala index 99057e7f91..bf43cba109 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.ledger import java.util.concurrent.Executors - import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} import cats.data.NonEmptyList @@ -15,6 +14,7 @@ import io.iohk.ethereum.crypto.{generateKeyPair, kec256} import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError import io.iohk.ethereum.ledger.Ledger.{PC, PR, VMImpl} +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.nodebuilder.SecureRandomBuilder import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.{BlockchainConfig, Config, DaoForkConfig} @@ -25,7 +25,6 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex import org.scalamock.handlers.{CallHandler0, CallHandler1, CallHandler4} import org.scalamock.scalatest.MockFactory - import scala.concurrent.ExecutionContext // scalastyle:off magic.number @@ -85,7 +84,13 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { val defaultValue: BigInt = 1000 val emptyWorld: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) - .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + .getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) val worldWithMinerAndOriginAccounts: InMemoryWorldStateProxy = InMemoryWorldStateProxy.persistState( emptyWorld @@ -133,7 +138,7 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { val initialWorld = BlockchainImpl(blockchainStorages).getWorldStateProxy( -1, UInt256.Zero, - Some(stateRootHash), + stateRootHash, noEmptyAccounts = false, ethCompatibleStorage = true ) @@ -225,7 +230,7 @@ trait DaoForkTestSetup extends TestSetup with MockFactory { .expects( proDaoBlock.header.number, proDaoBlockchainConfig.accountStartNonce, - Some(Fixtures.Blocks.DaoParentBlock.header.stateRoot), + Fixtures.Blocks.DaoParentBlock.header.stateRoot, false, true ) diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index f3bf2c9b44..5a6124ddb9 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -5,6 +5,7 @@ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.Block.BlockDec import io.iohk.ethereum.domain._ +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.utils._ import org.bouncycastle.util.encoders.Hex @@ -79,7 +80,7 @@ class StxLedgerSpec extends AnyFlatSpec with Matchers with Logger { val newBlock: Block = genesisBlock.copy(header = block.header.copy(number = 1, parentHash = genesisHash)) - val preparedBlock: Ledger.BlockPreparationResult = consensus.blockPreparator.prepareBlock(newBlock) + val preparedBlock: Ledger.PreparedBlock = consensus.blockPreparator.prepareBlock(newBlock, genesisBlock.header) val preparedWorld: InMemoryWorldStateProxy = preparedBlock.updatedWorld val header: BlockHeader = preparedBlock.block.header.copy(number = 1, stateRoot = preparedBlock.stateRootHash) @@ -140,7 +141,13 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { override lazy val stxLedger = new StxLedger(blockchain, blockchainConfig, consensus.blockPreparator) val emptyWorld: InMemoryWorldStateProxy = - blockchain.getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) + blockchain.getWorldStateProxy( + -1, + UInt256.Zero, + ByteString(MerklePatriciaTrie.EmptyRootHash), + noEmptyAccounts = false, + ethCompatibleStorage = true + ) val existingAddress = Address(10) val existingAccount = Account(nonce = UInt256.Zero, balance = UInt256(10)) From 30bf21c3b9fbb466a9e51a6c297ff50b12a1b89e Mon Sep 17 00:00:00 2001 From: Michal Mrozek Date: Mon, 9 Nov 2020 13:46:44 +0100 Subject: [PATCH 2/4] [ETCM-301] PR fixes --- .../io/iohk/ethereum/jsonrpc/EthService.scala | 7 +++--- .../iohk/ethereum/ledger/BlockExecution.scala | 24 +++++++++++-------- .../io/iohk/ethereum/snappy/SnappyTest.scala | 2 +- .../ethereum/ledger/BlockExecutionSpec.scala | 14 +++++++---- .../io/iohk/ethereum/ledger/LedgerSpec.scala | 8 ++++--- .../ethereum/ledger/LedgerTestSetup.scala | 4 +++- 6 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index 131dc07c06..9c9090a62b 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala @@ -34,7 +34,7 @@ import io.iohk.ethereum.jsonrpc.{FilterManager => FM} import monix.eval.Task import org.bouncycastle.util.encoders.Hex -import scala.collection.concurrent.{ Map => ConcurrentMap, TrieMap } +import scala.collection.concurrent.{Map => ConcurrentMap, TrieMap} import scala.concurrent.duration.FiniteDuration import scala.language.existentials import scala.reflect.ClassTag @@ -532,9 +532,8 @@ class EthService( // NOTE This is called from places that guarantee we are running Ethash consensus. private def removeObsoleteHashrates(now: Date): Unit = { - hashRate.retain { - case (_, (_, reported)) => - Duration.between(reported.toInstant, now.toInstant).toMillis < jsonRpcConfig.minerActiveTimeout.toMillis + hashRate.retain { case (_, (_, reported)) => + Duration.between(reported.toInstant, now.toInstant).toMillis < jsonRpcConfig.minerActiveTimeout.toMillis } } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala index 7d1d920e47..78b68d724a 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.ledger import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockExecutionError.MissingParentError import io.iohk.ethereum.ledger.Ledger.BlockResult import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, Logger} import io.iohk.ethereum.vm.EvmConfig - import scala.annotation.tailrec class BlockExecution( @@ -55,7 +55,10 @@ class BlockExecution( /** Executes a block (executes transactions and pays rewards) */ private def executeBlock(block: Block): Either[BlockExecutionError, BlockResult] = { for { - execResult <- executeBlockTransactions(block) + parent <- blockchain + .getBlockHeaderByHash(block.header.parentHash) + .toRight(MissingParentError) // Should not never occur because validated earlier + execResult <- executeBlockTransactions(block, parent) worldToPersist = blockPreparator.payBlockReward(block, execResult.worldState) // State root hash needs to be up-to-date for validateBlockAfterExecution worldPersisted = InMemoryWorldStateProxy.persistState(worldToPersist) @@ -66,14 +69,11 @@ class BlockExecution( * * @param block the block with transactions to run */ - private[ledger] def executeBlockTransactions(block: Block): Either[BlockExecutionError, BlockResult] = { - val parentStateRoot = - blockchain - .getBlockHeaderByHash(block.header.parentHash) - .map(_.stateRoot) - .getOrElse( - throw new IllegalStateException("Cannot find parent") - ) // Should not never occur because validated earlier + private[ledger] def executeBlockTransactions( + block: Block, + parent: BlockHeader + ): Either[BlockExecutionError, BlockResult] = { + val parentStateRoot = parent.stateRoot val blockHeaderNumber = block.header.number val initialWorld = blockchain.getWorldStateProxy( blockNumber = blockHeaderNumber, @@ -180,4 +180,8 @@ object BlockExecutionError { extends BlockExecutionError case class ValidationAfterExecError(reason: String) extends BlockExecutionError + + case object MissingParentError extends BlockExecutionError { + override val reason: Any = "Cannot find parent" + } } diff --git a/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala b/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala index c02aa6fedd..9e5341761f 100644 --- a/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala +++ b/src/snappy/scala/io/iohk/ethereum/snappy/SnappyTest.scala @@ -70,6 +70,6 @@ class SnappyTest extends AnyFreeSpec with Matchers with Logger { // // this seems to discard failures, for better errors messages we might want to implement a different method (simulateBlock?) // val result = blockPreparator.prepareBlock(block) // Right(result.blockResult.receipts) -// FIXME DO WE NEED THAT? +// FIXME Remove whole snappy tests [ETCM-349] } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala index 8a825099ee..49f3adef4f 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala @@ -147,7 +147,8 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper "block without txs" in new BlockExecutionTestSetup { val block = Block(validBlockHeader, validBlockBodyWithNoTxs) - val txsExecResult: Either[BlockExecutionError, BlockResult] = blockExecution.executeBlockTransactions(block) + val txsExecResult: Either[BlockExecutionError, BlockResult] = + blockExecution.executeBlockTransactions(block, validBlockParentHeader) txsExecResult.isRight shouldBe true @@ -179,7 +180,8 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper val blockExecution = new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) - val txsExecResult: Either[BlockExecutionError, BlockResult] = blockExecution.executeBlockTransactions(block) + val txsExecResult: Either[BlockExecutionError, BlockResult] = + blockExecution.executeBlockTransactions(block, validBlockParentHeader) txsExecResult.isRight shouldBe true val BlockResult(resultingWorldState, resultingGasUsed, resultingReceipts) = txsExecResult.right.get @@ -246,7 +248,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper val blockExecution = new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) - val txsExecResult = blockExecution.executeBlockTransactions(block) + val txsExecResult = blockExecution.executeBlockTransactions(block, validBlockParentHeader) txsExecResult.isRight shouldBe txValidAccordingToValidators if (txsExecResult.isRight) { @@ -283,7 +285,8 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper validBlockBodyWithNoTxs.copy(transactionList = Seq(validStxSignedByOrigin.tx, invalidStx)) val block = Block(validBlockHeader, blockBodyWithTxs) - val txsExecResult: Either[BlockExecutionError, BlockResult] = blockExecution.executeBlockTransactions(block) + val txsExecResult: Either[BlockExecutionError, BlockResult] = + blockExecution.executeBlockTransactions(block, validBlockParentHeader) txsExecResult.isLeft shouldBe true } @@ -294,7 +297,8 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper validBlockBodyWithNoTxs.copy(transactionList = Seq(invalidStx, validStxSignedByOrigin.tx)) val block = Block(validBlockHeader, blockBodyWithTxs) - val txsExecResult: Either[BlockExecutionError, BlockResult] = blockExecution.executeBlockTransactions(block) + val txsExecResult: Either[BlockExecutionError, BlockResult] = + blockExecution.executeBlockTransactions(block, validBlockParentHeader) txsExecResult.isLeft shouldBe true } diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala index e78af425de..65b68dbd77 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala @@ -216,7 +216,7 @@ class LedgerSpec extends AnyFlatSpec with ScalaCheckPropertyChecks with Matchers val validBlockBodyWithTxs: BlockBody = validBlockBodyWithNoTxs.copy(transactionList = Seq(stx1.tx, stx2.tx)) val block = Block(validBlockHeader, validBlockBodyWithTxs) - val txsExecResult = ledger.blockExecution.executeBlockTransactions(block) + val txsExecResult = ledger.blockExecution.executeBlockTransactions(block, validBlockParentHeader) assert(txsExecResult.isRight) val BlockResult(resultingWorldState, resultingGasUsed, resultingReceipts) = txsExecResult.right.get @@ -296,7 +296,8 @@ class LedgerSpec extends AnyFlatSpec with ScalaCheckPropertyChecks with Matchers // We don't care about block txs in this test ledger.blockExecution.executeBlockTransactions( - proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)) + proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), + parentBlockHeader ) } @@ -310,7 +311,8 @@ class LedgerSpec extends AnyFlatSpec with ScalaCheckPropertyChecks with Matchers // We don't care about block txs in this test ledger.blockExecution.executeBlockTransactions( - proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)) + proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), + parentBlockHeader ) } diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala index bf43cba109..4099b624e9 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala @@ -223,9 +223,11 @@ trait DaoForkTestSetup extends TestSetup with MockFactory { petersburgBlockNumber = Long.MaxValue ) + val parentBlockHeader = Fixtures.Blocks.DaoParentBlock.header + (testBlockchain.getBlockHeaderByHash _) .expects(proDaoBlock.header.parentHash) - .returning(Some(Fixtures.Blocks.DaoParentBlock.header)) + .returning(Some(parentBlockHeader)) (testBlockchain.getWorldStateProxy _) .expects( proDaoBlock.header.number, From 80322c0e675c3236800383a55a1ced58a4c92655 Mon Sep 17 00:00:00 2001 From: Michal Mrozek Date: Thu, 12 Nov 2020 14:15:40 +0100 Subject: [PATCH 3/4] [ETCM-301] expose initial world state in block generator --- .../consensus/blocks/BlockGenerator.scala | 6 +- .../blocks/BlockGeneratorSkeleton.scala | 11 +- .../blocks/NoOmmersBlockGenerator.scala | 12 +- .../consensus/ethash/EthashBlockCreator.scala | 23 ++-- .../consensus/ethash/EthashMiner.scala | 6 +- .../consensus/ethash/MockedMiner.scala | 28 +++-- .../ethash/blocks/EthashBlockGenerator.scala | 20 ++- .../io/iohk/ethereum/jsonrpc/EthService.scala | 10 +- .../iohk/ethereum/jsonrpc/TestService.scala | 5 +- .../ethereum/ledger/BlockPreparator.scala | 25 ++-- .../ledger/InMemoryWorldStateProxy.scala | 2 +- .../consensus/BlockGeneratorSpec.scala | 119 +++++++++++------- .../consensus/ethash/EthashMinerSpec.scala | 7 +- .../consensus/ethash/MinerSpecSetup.scala | 18 +-- .../consensus/ethash/MockedMinerSpec.scala | 5 +- .../ethereum/jsonrpc/EthServiceSpec.scala | 12 +- .../jsonrpc/JsonRpcControllerEthSpec.scala | 10 +- .../jsonrpc/JsonRpcControllerFixture.scala | 11 +- .../iohk/ethereum/ledger/StxLedgerSpec.scala | 3 +- .../ethereum/network/PeerManagerSpec.scala | 23 +++- 20 files changed, 219 insertions(+), 137 deletions(-) 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 74133358a3..4df9b00321 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus.blocks import io.iohk.ethereum.domain.{Address, Block, SignedTransaction} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy /** * We use a `BlockGenerator` to create the next block. @@ -39,8 +40,9 @@ trait BlockGenerator { parent: Block, transactions: Seq[SignedTransaction], beneficiary: Address, - x: X - ): PendingBlock + x: X, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] + ): PendingBlockAndState } /** 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 cc93b8627c..894dc58924 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.consensus.blocks import java.util.concurrent.atomic.AtomicReference - import akka.util.ByteString import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator @@ -13,8 +12,8 @@ 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.ledger.Ledger.{PreparedBlock, BlockResult} -import io.iohk.ethereum.ledger.{BlockPreparator, BloomFilter} +import io.iohk.ethereum.ledger.Ledger.{BlockResult, PreparedBlock} +import io.iohk.ethereum.ledger.{BlockPreparator, BloomFilter, InMemoryWorldStateProxy} import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.ByteUtils.or @@ -90,7 +89,8 @@ abstract class BlockGeneratorSkeleton( beneficiary: Address, blockNumber: BigInt, blockPreparator: BlockPreparator, - x: X + x: X, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] ): PendingBlockAndState = { val blockTimestamp = blockTimestampProvider.getEpochSecond @@ -99,7 +99,7 @@ abstract class BlockGeneratorSkeleton( val body = newBlockBody(transactionsForBlock, x) val block = Block(header, body) - val prepared = blockPreparator.prepareBlock(block, parent.header) match { + blockPreparator.prepareBlock(block, parent.header, initialWorldStateBeforeExecution) match { case PreparedBlock(prepareBlock, BlockResult(_, gasUsed, receipts), stateRoot, updatedWorld) => val receiptsLogs: Seq[Array[Byte]] = BloomFilter.EmptyBloomFilter.toArray +: receipts.map(_.logsBloomFilter.toArray) @@ -122,7 +122,6 @@ abstract class BlockGeneratorSkeleton( updatedWorld ) } - prepared } protected def prepareTransactions( diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala index 2cfff9a8ff..9972a53bce 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala @@ -3,7 +3,7 @@ package io.iohk.ethereum.consensus.blocks import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} import io.iohk.ethereum.utils.BlockchainConfig abstract class NoOmmersBlockGenerator( @@ -42,15 +42,17 @@ abstract class NoOmmersBlockGenerator( parent: Block, transactions: Seq[SignedTransaction], beneficiary: Address, - x: Nil.type - ): PendingBlock = { + x: Nil.type, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] + ): PendingBlockAndState = { val pHeader = parent.header val blockNumber = pHeader.number + 1 - val prepared = prepareBlock(parent, transactions, beneficiary, blockNumber, blockPreparator, x) + val prepared = + prepareBlock(parent, transactions, beneficiary, blockNumber, blockPreparator, x, initialWorldStateBeforeExecution) cache.updateAndGet((t: List[PendingBlockAndState]) => (prepared :: t).take(blockCacheSize)) - prepared.pendingBlock + prepared } } 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 b474d1602f..a7b66c2ed8 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala @@ -2,10 +2,11 @@ package io.iohk.ethereum.consensus.ethash import akka.actor.ActorRef import akka.pattern.ask -import akka.util.{Timeout, ByteString} -import io.iohk.ethereum.consensus.blocks.PendingBlock +import akka.util.{ByteString, Timeout} +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator import io.iohk.ethereum.domain.{Address, Block} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse import scala.concurrent.Future @@ -26,13 +27,21 @@ class EthashBlockCreator( private lazy val blockGenerator: EthashBlockGenerator = consensus.blockGenerator lazy val blockchainConfig = consensus.blockchainConfig - def getBlockForMining(parentBlock: Block, withTransactions: Boolean = true): Future[PendingBlock] = { + def getBlockForMining( + parentBlock: Block, + withTransactions: Boolean = true, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] = None + ): Future[PendingBlockAndState] = { val transactions = if (withTransactions) getTransactionsFromPool else Future.successful(PendingTransactionsResponse(Nil)) - getOmmersFromPool(parentBlock.hash).zip(transactions).flatMap { case (ommers, pendingTxs) => - val pendingBlock = blockGenerator - .generateBlock(parentBlock, pendingTxs.pendingTransactions.map(_.stx.tx), coinbase, ommers.headers) - Future.successful(pendingBlock) + getOmmersFromPool(parentBlock.hash).zip(transactions).map { case (ommers, pendingTxs) => + blockGenerator.generateBlock( + parentBlock, + pendingTxs.pendingTransactions.map(_.stx.tx), + coinbase, + ommers.headers, + initialWorldStateBeforeExecution + ) } } 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 db4fb5610c..e9f2b39cf7 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashMiner.scala @@ -2,11 +2,10 @@ 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 +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 @@ -17,7 +16,6 @@ import io.iohk.ethereum.nodebuilder.Node import io.iohk.ethereum.utils.BigIntExtensionMethods._ import io.iohk.ethereum.utils.{ByteStringUtils, ByteUtils} import org.bouncycastle.util.encoders.Hex - import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scala.util.{Failure, Random, Success, Try} @@ -80,7 +78,7 @@ class EthashMiner( } blockCreator.getBlockForMining(parentBlock) onComplete { - case Success(PendingBlock(block, _)) => + case Success(PendingBlockAndState(PendingBlock(block, _), _)) => val headerHash = crypto.kec256(BlockHeader.getEncodedWithoutNonce(block.header)) val startTime = System.nanoTime() val mineResult = diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala index 63d92c617b..16014b89b5 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala @@ -3,16 +3,16 @@ package io.iohk.ethereum.consensus.ethash 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.PendingBlock +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.wrongConsensusArgument import io.iohk.ethereum.domain.{Block, Blockchain} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.nodebuilder.Node import io.iohk.ethereum.utils.ByteStringUtils - import scala.concurrent.duration._ class MockedMiner( @@ -37,39 +37,41 @@ class MockedMiner( mineBlocks.parentBlock match { case Some(parentHash) => blockchain.getBlockByHash(parentHash) match { - case Some(parentBlock) => - self ! MineBlock - sender() ! MiningOrdered - context.become(working(mineBlocks.numBlocks, mineBlocks.withTransactions, parentBlock)) + case Some(parentBlock) => mineBlock(mineBlocks, parentBlock) case None => val error = s"Unable to get parent block with hash ${ByteStringUtils.hash2string(parentHash)} for mining" sender() ! MiningError(error) } case None => val parentBlock = blockchain.getBestBlock() - self ! MineBlock - sender() ! MiningOrdered - context.become(working(mineBlocks.numBlocks, mineBlocks.withTransactions, parentBlock)) + mineBlock(mineBlocks, parentBlock) } } + private def mineBlock(mineBlocks: MineBlocks, parentBlock: Block) = { + self ! MineBlock + sender() ! MiningOrdered + context.become(working(mineBlocks.numBlocks, mineBlocks.withTransactions, parentBlock, None)) + } + def working( numBlocks: Int, withTransactions: Boolean, - parentBlock: Block + parentBlock: Block, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] ): Receive = { case _: MineBlocks => sender() ! MinerIsWorking case MineBlock => if (numBlocks > 0) { - blockCreator.getBlockForMining(parentBlock, withTransactions) pipeTo self + blockCreator.getBlockForMining(parentBlock, withTransactions, initialWorldStateBeforeExecution) pipeTo self } else { log.info(s"Mining all mocked blocks successful") context.become(waiting()) } - case pendingBlock: PendingBlock => + case PendingBlockAndState(pendingBlock, state) => val minedBlock = pendingBlock.block log.info( s"Mining mocked block {} successful. Included transactions: {}", @@ -79,7 +81,7 @@ class MockedMiner( syncEventListener ! SyncProtocol.MinedBlock(minedBlock) // because of using seconds to calculate block timestamp, we can't mine blocks faster than one block per second context.system.scheduler.scheduleOnce(1.second, self, MineBlock) - context.become(working(numBlocks - 1, withTransactions, minedBlock)) + context.become(working(numBlocks - 1, withTransactions, minedBlock, Some(state))) case Failure(t) => log.error(t, "Unable to get block for mining") diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala index 6a7f2fc63a..14de53f488 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.consensus.ethash.blocks import java.util.function.UnaryOperator - import akka.util.ByteString import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks._ @@ -9,7 +8,7 @@ import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} import io.iohk.ethereum.utils.BlockchainConfig /** Internal API, used for testing (especially mocks) */ @@ -72,8 +71,9 @@ class EthashBlockGeneratorImpl( parent: Block, transactions: Seq[SignedTransaction], beneficiary: Address, - x: Ommers - ): PendingBlock = { + x: Ommers, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] + ): PendingBlockAndState = { val pHeader = parent.header val blockNumber = pHeader.number + 1 val parentHash = pHeader.hash @@ -83,13 +83,21 @@ class EthashBlockGeneratorImpl( case Right(_) => x } - val prepared = prepareBlock(parent, transactions, beneficiary, blockNumber, blockPreparator, ommers) + val prepared = prepareBlock( + parent, + transactions, + beneficiary, + blockNumber, + blockPreparator, + ommers, + initialWorldStateBeforeExecution + ) cache.updateAndGet { t: List[PendingBlockAndState] => (prepared :: t).take(blockCacheSize) } - prepared.pendingBlock + prepared } def withBlockTimestampProvider(blockTimestampProvider: BlockTimestampProvider): EthashBlockGeneratorImpl = diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index 9c9090a62b..7c3c492b19 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.util.{ByteString, Timeout} import cats.syntax.either._ @@ -11,6 +10,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.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.ethash.EthashUtils import io.iohk.ethereum.crypto._ import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation @@ -33,8 +33,7 @@ import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ import io.iohk.ethereum.jsonrpc.{FilterManager => FM} import monix.eval.Task import org.bouncycastle.util.encoders.Hex - -import scala.collection.concurrent.{Map => ConcurrentMap, TrieMap} +import scala.collection.concurrent.{TrieMap, Map => ConcurrentMap} import scala.concurrent.duration.FiniteDuration import scala.language.existentials import scala.reflect.ClassTag @@ -544,11 +543,12 @@ class EthService( val response: ServiceResponse[GetWorkResponse] = Task.parZip2(getOmmersFromPool(bestBlock.hash), getTransactionsFromPool()).map { case (ommers, pendingTxs) => val blockGenerator = ethash.blockGenerator - val pb = blockGenerator.generateBlock( + val PendingBlockAndState(pb, _) = blockGenerator.generateBlock( bestBlock, pendingTxs.pendingTransactions.map(_.stx.tx), consensusConfig.coinbase, - ommers.headers + ommers.headers, + None ) Right( GetWorkResponse( diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala index e6903d8290..13650cf19a 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala @@ -156,9 +156,10 @@ class TestService( parentBlock, pendingTxs.pendingTransactions.map(_.stx.tx), etherbase, - Nil + Nil, + None ) - Task.now(pb) + Task.now(pb.pendingBlock) } .timeout(timeout.duration) } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala index 16967f3964..7b453ae48a 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala @@ -376,14 +376,23 @@ class BlockPreparator( } } - def prepareBlock(block: Block, parent: BlockHeader): PreparedBlock = { - val initialWorld = blockchain.getReadOnlyWorldStateProxy( - None, - blockchainConfig.accountStartNonce, - parent.stateRoot, - noEmptyAccounts = EvmConfig.forBlock(block.header.number, blockchainConfig).noEmptyAccounts, - ethCompatibleStorage = blockchainConfig.ethCompatibleStorage - ) + def prepareBlock( + block: Block, + parent: BlockHeader, + initialWorldStateBeforeExecution: Option[InMemoryWorldStateProxy] + ): PreparedBlock = { + + val initialWorld = + initialWorldStateBeforeExecution.getOrElse( + blockchain.getReadOnlyWorldStateProxy( + None, + blockchainConfig.accountStartNonce, + parent.stateRoot, + noEmptyAccounts = EvmConfig.forBlock(block.header.number, blockchainConfig).noEmptyAccounts, + ethCompatibleStorage = blockchainConfig.ethCompatibleStorage + ) + ) + val prepared = executePreparedTransactions(block.body.transactionList, initialWorld, block.header) prepared match { diff --git a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala index dfd326664f..9a761546b2 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala @@ -118,7 +118,7 @@ class InMemoryWorldStateProxyStorage( override def load(addr: BigInt): BigInt = wrapped.get(addr).getOrElse(0) } -class InMemoryWorldStateProxy private[ledger] ( +class InMemoryWorldStateProxy( // State MPT proxied nodes storage needed to construct the storage MPT when calling [[getStorage]]. // Accounts state and accounts storage states are saved within the same storage val stateStorage: MptStorage, diff --git a/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala index 8178100472..273dadfe10 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/BlockGeneratorSpec.scala @@ -1,12 +1,9 @@ package io.iohk.ethereum.consensus -import java.time.Instant -import java.util.concurrent.Executors - 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, PendingBlock} +import io.iohk.ethereum.consensus.blocks.BlockTimestampProvider import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.crypto @@ -18,22 +15,23 @@ import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.{BlockExecution, BlockQueue, BlockValidation} import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.utils._ +import java.time.Instant +import java.util.concurrent.Executors import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks - import scala.concurrent.duration.Duration import scala.concurrent.{Await, ExecutionContext} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with Logger { implicit val testContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4)) "BlockGenerator" should "generate correct block with empty transactions" in new TestSetup { val pendingBlock = - blockGenerator.generateBlock(bestBlock, Nil, Address(testAddress), blockGenerator.emptyX) + blockGenerator.generateBlock(bestBlock, Nil, Address(testAddress), blockGenerator.emptyX, None).pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("eb49a2da108d63de")) @@ -53,7 +51,9 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper it should "generate correct block with transactions" in new TestSetup { val pendingBlock = - blockGenerator.generateBlock(bestBlock, Seq(signedTransaction.tx), Address(testAddress), blockGenerator.emptyX) + blockGenerator + .generateBlock(bestBlock, Seq(signedTransaction.tx), Address(testAddress), blockGenerator.emptyX, None) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("4139b957dae0488d")) @@ -73,7 +73,9 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper it should "be possible to simulate transaction, on world returned with pending block" in new TestSetup { val pendingBlock = - blockGenerator.generateBlock(bestBlock, Seq(signedTransaction.tx), Address(testAddress), blockGenerator.emptyX) + blockGenerator + .generateBlock(bestBlock, Seq(signedTransaction.tx), Address(testAddress), blockGenerator.emptyX, None) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("4139b957dae0488d")) @@ -88,15 +90,14 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val res = Await.result(ledger.importBlock(fullBlock), Duration.Inf) // Create new pending block, with updated stateRootHash - val newPendingBlock: PendingBlock = blockGenerator.generateBlock( + val pendBlockAndState = blockGenerator.generateBlock( blockchain.getBestBlock(), Seq(signedTransaction.tx), Address(testAddress), - blockGenerator.emptyX + blockGenerator.emptyX, + None ) - val pendBlockAndState = blockGenerator.getPendingBlockAndState.get - // Try to simulate transaction, on world with updated stateRootHash, but not updated storages assertThrows[MPTException] { stxLedger.simulateTransaction(signedTransaction, pendBlockAndState.pendingBlock.block.header, None) @@ -115,12 +116,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper it should "filter out failing transactions" in new TestSetup { val pendingBlock = - blockGenerator.generateBlock( - bestBlock, - Seq(signedTransaction.tx, duplicatedSignedTransaction.tx), - Address(testAddress), - blockGenerator.emptyX - ) + blockGenerator + .generateBlock( + bestBlock, + Seq(signedTransaction.tx, duplicatedSignedTransaction.tx), + Address(testAddress), + blockGenerator.emptyX, + None + ) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("12cb47f9208d1e81")) @@ -151,7 +155,9 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val transactions = Seq(txWitGasTooBigGasLimit, signedTransaction.tx, duplicatedSignedTransaction.tx) val pendingBlock = - blockGenerator.generateBlock(bestBlock, transactions, Address(testAddress), blockGenerator.emptyX) + blockGenerator + .generateBlock(bestBlock, transactions, Address(testAddress), blockGenerator.emptyX, None) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("38026e10fb18b458")) @@ -216,7 +222,9 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper SignedTransaction.sign(transaction.copy(nonce = transaction.nonce + 1), keyPair, Some(0x3d.toByte)).tx val pendingBlock = - blockGenerator.generateBlock(bestBlock, Seq(generalTx, specificTx), Address(testAddress), blockGenerator.emptyX) + blockGenerator + .generateBlock(bestBlock, Seq(generalTx, specificTx), Address(testAddress), blockGenerator.emptyX, None) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("48381cb0cd40936a")) @@ -287,7 +295,9 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val generalTx = SignedTransaction.sign(transaction1, keyPair, None).tx val generatedBlock = - blockGenerator.generateBlock(bestBlock, Seq(generalTx), Address(testAddress), blockGenerator.emptyX) + blockGenerator + .generateBlock(bestBlock, Seq(generalTx), Address(testAddress), blockGenerator.emptyX, None) + .pendingBlock blockExecution.executeAndValidateBlock(generatedBlock.block, true) shouldBe a[Right[_, Seq[Receipt]]] } @@ -296,12 +306,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper val generalTx = SignedTransaction.sign(transaction.copy(nonce = transaction.nonce + 1), keyPair, None).tx val pendingBlock = - blockGenerator.generateBlock( - bestBlock, - Seq(generalTx, signedTransaction.tx), - Address(testAddress), - blockGenerator.emptyX - ) + blockGenerator + .generateBlock( + bestBlock, + Seq(generalTx, signedTransaction.tx), + Address(testAddress), + blockGenerator.emptyX, + None + ) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("39bd50fcbde30b18")) @@ -325,12 +338,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper SignedTransaction.sign(transaction.copy(nonce = signedTransaction.tx.tx.nonce + 1), keyPair, Some(0x3d.toByte)).tx val pendingBlock = - blockGenerator.generateBlock( - bestBlock, - Seq(nextTransaction, signedTransaction.tx), - Address(testAddress), - blockGenerator.emptyX - ) + blockGenerator + .generateBlock( + bestBlock, + Seq(nextTransaction, signedTransaction.tx), + Address(testAddress), + blockGenerator.emptyX, + None + ) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("8f88ec20f1be482f")) @@ -368,12 +384,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper SignedTransaction.sign(failingTransaction, keyPairFromPrvKey(privateKeyWithNoEthere), Some(0x3d.toByte)).tx val pendingBlock = - blockGenerator.generateBlock( - bestBlock, - Seq(nextTransaction, signedFailingTransaction, signedTransaction.tx), - Address(testAddress), - blockGenerator.emptyX - ) + blockGenerator + .generateBlock( + bestBlock, + Seq(nextTransaction, signedFailingTransaction, signedTransaction.tx), + Address(testAddress), + blockGenerator.emptyX, + None + ) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("8f88ec20f1be482f")) @@ -397,12 +416,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper .tx val pendingBlock = - blockGenerator.generateBlock( - bestBlock, - Seq(txWitSameNonceButLowerGasPrice, signedTransaction.tx), - Address(testAddress), - blockGenerator.emptyX - ) + blockGenerator + .generateBlock( + bestBlock, + Seq(txWitSameNonceButLowerGasPrice, signedTransaction.tx), + Address(testAddress), + blockGenerator.emptyX, + None + ) + .pendingBlock //mined with mantis + ethminer val minedNonce = ByteString(Hex.decode("14d7000ac544b38e")) @@ -451,7 +473,8 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper else blockchainConfig.ecip1098BlockNumber / 2 val parentBlock = bestBlock.copy(header = bestBlock.header.copy(number = blockNumber - 1)) - val generatedBlock = blockGenerator.generateBlock(parentBlock, Nil, Address(testAddress), blockGenerator.emptyX) + val generatedBlock = + blockGenerator.generateBlock(parentBlock, Nil, Address(testAddress), blockGenerator.emptyX, None).pendingBlock generatedBlock.block.header.extraFields shouldBe headerExtraFields } diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala index 7a3c04552f..33e3fc09af 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ethash/EthashMinerSpec.scala @@ -4,7 +4,7 @@ package ethash import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{TestActor, TestActorRef, TestKit, TestProbe} import io.iohk.ethereum.Fixtures -import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} import io.iohk.ethereum.consensus.ethash.validators.EthashBlockHeaderValidator import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.domain._ @@ -16,7 +16,6 @@ import monix.eval.Task import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory import org.scalatest.Tag - import scala.concurrent.duration._ import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers @@ -36,8 +35,8 @@ class EthashMinerSpec extends TestKit(ActorSystem("EthashMinerSpec_System")) wit .returns(Task.now(Right(SubmitHashRateResponse(true)))) .atLeastOnce() (blockGenerator.generateBlock _) - .expects(parent, Nil, consensusConfig.coinbase, Nil) - .returning(PendingBlock(bfm, Nil)) + .expects(parent, Nil, consensusConfig.coinbase, Nil, None) + .returning(PendingBlockAndState(PendingBlock(bfm, Nil), fakeWorld)) .atLeastOnce() ommersPool.setAutoPilot((sender: ActorRef, _: Any) => { diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala b/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala index ddd6d143d5..b3f66c8cd6 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ethash/MinerSpecSetup.scala @@ -5,14 +5,14 @@ import akka.testkit.{TestActorRef, TestProbe} import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.{ScenarioSetup, SyncProtocol} -import io.iohk.ethereum.consensus.blocks.PendingBlock +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.domain._ +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.ledger.Ledger.VMImpl import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory - import scala.concurrent.Future import scala.concurrent.duration.{Duration, FiniteDuration} @@ -94,26 +94,28 @@ abstract class MinerSpecSetup(implicit system: ActorSystem) extends ScenarioSetu val parentActor = TestProbe() + val fakeWorld = mock[InMemoryWorldStateProxy] + def blockCreatorBehaviour(parentBlock: Block, withTransactions: Boolean, resultBlock: Block) = { (blockCreator - .getBlockForMining(_: Block, _: Boolean)) - .expects(parentBlock, withTransactions) + .getBlockForMining(_: Block, _: Boolean, _: Option[InMemoryWorldStateProxy])) + .expects(parentBlock, withTransactions, *) .returning( Future - .successful(PendingBlock(resultBlock, Nil)) + .successful(PendingBlockAndState(PendingBlock(resultBlock, Nil), fakeWorld)) ) .atLeastOnce() } def blockCreatorBehaviourExpectingInitialWorld(parentBlock: Block, withTransactions: Boolean, resultBlock: Block) = { (blockCreator - .getBlockForMining(_: Block, _: Boolean)) - .expects(where { (parent, withTxs) => + .getBlockForMining(_: Block, _: Boolean, _: Option[InMemoryWorldStateProxy])) + .expects(where { (parent, withTxs, _) => parent == parentBlock && withTxs == withTransactions }) .returning( Future - .successful(PendingBlock(resultBlock, Nil)) + .successful(PendingBlockAndState(PendingBlock(resultBlock, Nil), fakeWorld)) ) .atLeastOnce() } diff --git a/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala index e35e129d0a..7b892b256a 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ethash/MockedMinerSpec.scala @@ -5,6 +5,7 @@ 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.domain.{Block, SignedTransaction} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.ByteStringUtils import org.scalatest._ import scala.concurrent.Future @@ -44,8 +45,8 @@ class MockedMinerSpec blockCreatorBehaviour(parent, false, bfm1) (blockCreator - .getBlockForMining(_: Block, _: Boolean)) - .expects(bfm1, false) + .getBlockForMining(_: Block, _: Boolean, _: Option[InMemoryWorldStateProxy])) + .expects(bfm1, false, *) .returning( Future .failed(new RuntimeException("error")) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala index 0af7699bb9..7f1cadd4f7 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala @@ -539,7 +539,9 @@ class EthServiceSpec it should "return requested work" in new TestSetup { (ledger.consensus _: (() => Consensus)).expects().returns(consensus).anyNumberOfTimes() - (blockGenerator.generateBlock _).expects(parentBlock, Nil, *, *).returning(PendingBlock(block, Nil)) + (blockGenerator.generateBlock _) + .expects(parentBlock, Nil, *, *, *) + .returning(PendingBlockAndState(PendingBlock(block, Nil), fakeWorld)) blockchain.save(parentBlock, Nil, ChainWeight.totalDifficultyOnly(parentBlock.header.difficulty), true) val response = ethService.getWork(GetWorkRequest()).runSyncUnsafe() @@ -740,7 +742,9 @@ class EthServiceSpec ethService.getMining(GetMiningRequest()).runSyncUnsafe() shouldEqual Right(GetMiningResponse(false)) - (blockGenerator.generateBlock _).expects(parentBlock, *, *, *).returning(PendingBlock(block, Nil)) + (blockGenerator.generateBlock _) + .expects(parentBlock, *, *, *, *) + .returning(PendingBlockAndState(PendingBlock(block, Nil), fakeWorld)) blockchain.storeBlock(parentBlock).commit() ethService.getWork(GetWorkRequest()) @@ -780,7 +784,9 @@ class EthServiceSpec it should "return if node is mining after time out" in new TestSetup { (ledger.consensus _: (() => Consensus)).expects().returns(consensus).anyNumberOfTimes() - (blockGenerator.generateBlock _).expects(parentBlock, *, *, *).returning(PendingBlock(block, Nil)) + (blockGenerator.generateBlock _) + .expects(parentBlock, *, *, *, *) + .returning(PendingBlockAndState(PendingBlock(block, Nil), fakeWorld)) blockchain.storeBlock(parentBlock).commit() ethService.getWork(GetWorkRequest()) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala index 897db69e45..e5f79f8462 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala @@ -6,7 +6,7 @@ import akka.util.ByteString import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress import io.iohk.ethereum.consensus.Consensus -import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} import io.iohk.ethereum.consensus.validators.SignedTransactionValidator import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ @@ -281,8 +281,8 @@ class JsonRpcControllerEthSpec blockchain.save(parentBlock, Nil, ChainWeight.zero.increase(parentBlock.header), true) (blockGenerator.generateBlock _) - .expects(parentBlock, *, *, *) - .returns(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil)) + .expects(parentBlock, *, *, *, *) + .returns(PendingBlockAndState(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil), fakeWorld)) val request: JsonRpcRequest = newJsonRpcRequest("eth_getWork") @@ -320,8 +320,8 @@ class JsonRpcControllerEthSpec blockchain.save(parentBlock, Nil, ChainWeight.zero.increase(parentBlock.header), true) (blockGenerator.generateBlock _) - .expects(parentBlock, *, *, *) - .returns(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil)) + .expects(parentBlock, *, *, *, *) + .returns(PendingBlockAndState(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil), fakeWorld)) val request: JsonRpcRequest = newJsonRpcRequest("eth_getWork") diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala index 6b356d9aa5..761da5cc43 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala @@ -11,7 +11,7 @@ import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1098 -import io.iohk.ethereum.domain.{Block, BlockBody, SignedTransaction} +import io.iohk.ethereum.domain.{Block, BlockBody, SignedTransaction, UInt256} import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.keystore.KeyStore import io.iohk.ethereum.ledger.{BloomFilter, Ledger, StxLedger} @@ -21,7 +21,6 @@ import io.iohk.ethereum.{Fixtures, ObjectGenerators, Timeouts} import org.bouncycastle.util.encoders.Hex import org.json4s.JsonAST.{JArray, JInt, JString, JValue} import org.scalamock.scalatest.MockFactory - import scala.concurrent.duration._ class JsonRpcControllerFixture(implicit system: ActorSystem) @@ -138,4 +137,12 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) def newJsonRpcRequest(method: String) = JsonRpcRequest("2.0", method, None, Some(JInt(1))) + + val fakeWorld = blockchain.getReadOnlyWorldStateProxy( + None, + UInt256.Zero, + ByteString.empty, + noEmptyAccounts = false, + ethCompatibleStorage = true + ) } diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index 5a6124ddb9..8a29f01f66 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -80,7 +80,8 @@ class StxLedgerSpec extends AnyFlatSpec with Matchers with Logger { val newBlock: Block = genesisBlock.copy(header = block.header.copy(number = 1, parentHash = genesisHash)) - val preparedBlock: Ledger.PreparedBlock = consensus.blockPreparator.prepareBlock(newBlock, genesisBlock.header) + val preparedBlock: Ledger.PreparedBlock = + consensus.blockPreparator.prepareBlock(newBlock, genesisBlock.header, None) val preparedWorld: InMemoryWorldStateProxy = preparedBlock.updatedWorld val header: BlockHeader = preparedBlock.block.header.copy(number = 1, stateRoot = preparedBlock.stateRootHash) diff --git a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala index 0b233a7b80..54ac0ff524 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala @@ -25,7 +25,12 @@ import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers // scalastyle:off magic.number -class PeerManagerSpec extends TestKit(ActorSystem("PeerManagerSpec_System")) with AnyFlatSpecLike with Matchers with Eventually with NormalPatience { +class PeerManagerSpec + extends TestKit(ActorSystem("PeerManagerSpec_System")) + with AnyFlatSpecLike + with Matchers + with Eventually + with NormalPatience { "PeerManager" should "try to connect to bootstrap and known nodes on startup" in new TestSetup { start() @@ -175,7 +180,9 @@ class PeerManagerSpec extends TestKit(ActorSystem("PeerManagerSpec_System")) wit val ConnectTo(uriConnectedTo) = peerAsOutgoingProbe.expectMsgClass(classOf[PeerActor.ConnectTo]) val nodeId = ByteString(Hex.decode(uriConnectedTo.getUserInfo)) - peerAsOutgoingProbe.reply(PeerEvent.PeerHandshakeSuccessful(peerAsOutgoing.copy(nodeId = Some(nodeId)), initialPeerInfo)) + peerAsOutgoingProbe.reply( + PeerEvent.PeerHandshakeSuccessful(peerAsOutgoing.copy(nodeId = Some(nodeId)), initialPeerInfo) + ) createdPeers(1).probe.expectMsgClass(classOf[PeerActor.ConnectTo]) @@ -188,7 +195,9 @@ class PeerManagerSpec extends TestKit(ActorSystem("PeerManagerSpec_System")) wit val peerAsIncomingProbe = createdPeers.last.probe val peerAsIncoming = Peer(peerAsIncomingAddress, peerAsIncomingProbe.ref, incomingConnection = true, Some(nodeId)) - peerAsIncomingProbe.expectMsg(PeerActor.HandleConnection(peerAsIncomingTcpConnection.ref, peerAsIncoming.remoteAddress)) + peerAsIncomingProbe.expectMsg( + PeerActor.HandleConnection(peerAsIncomingTcpConnection.ref, peerAsIncoming.remoteAddress) + ) peerAsIncomingProbe.reply(PeerEvent.PeerHandshakeSuccessful(peerAsIncoming, initialPeerInfo)) peerAsIncomingProbe.expectMsg(PeerActor.DisconnectPeer(Disconnect.Reasons.AlreadyConnected)) @@ -215,11 +224,15 @@ class PeerManagerSpec extends TestKit(ActorSystem("PeerManagerSpec_System")) wit val peerAsIncomingProbe = createdPeers.last.probe val peerAsIncoming = Peer(peerAsIncomingAddress, peerAsIncomingProbe.ref, incomingConnection = true, Some(nodeId)) - peerAsIncomingProbe.expectMsg(PeerActor.HandleConnection(peerAsIncomingTcpConnection.ref, peerAsIncoming.remoteAddress)) + peerAsIncomingProbe.expectMsg( + PeerActor.HandleConnection(peerAsIncomingTcpConnection.ref, peerAsIncoming.remoteAddress) + ) peerAsIncomingProbe.reply(PeerEvent.PeerHandshakeSuccessful(peerAsIncoming, initialPeerInfo)) // Handshake with peer as outgoing is finished - peerAsOutgoingProbe.reply(PeerEvent.PeerHandshakeSuccessful(peerAsOutgoing.copy(nodeId = Some(nodeId)), initialPeerInfo)) + peerAsOutgoingProbe.reply( + PeerEvent.PeerHandshakeSuccessful(peerAsOutgoing.copy(nodeId = Some(nodeId)), initialPeerInfo) + ) peerAsOutgoingProbe.expectMsg(PeerActor.DisconnectPeer(Disconnect.Reasons.AlreadyConnected)) } From 51b967a132caf2ef6475619260c9c81d83e4832f Mon Sep 17 00:00:00 2001 From: Michal Mrozek Date: Fri, 13 Nov 2020 12:40:04 +0100 Subject: [PATCH 4/4] [ETCM-301] PR fixes --- .../io/iohk/ethereum/consensus/ethash/MockedMiner.scala | 6 +++--- .../scala/io/iohk/ethereum/ledger/BlockPreparator.scala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala index 16014b89b5..fa3098b0b5 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/MockedMiner.scala @@ -37,18 +37,18 @@ class MockedMiner( mineBlocks.parentBlock match { case Some(parentHash) => blockchain.getBlockByHash(parentHash) match { - case Some(parentBlock) => mineBlock(mineBlocks, parentBlock) + case Some(parentBlock) => startMiningBlocks(mineBlocks, parentBlock) case None => val error = s"Unable to get parent block with hash ${ByteStringUtils.hash2string(parentHash)} for mining" sender() ! MiningError(error) } case None => val parentBlock = blockchain.getBestBlock() - mineBlock(mineBlocks, parentBlock) + startMiningBlocks(mineBlocks, parentBlock) } } - private def mineBlock(mineBlocks: MineBlocks, parentBlock: Block) = { + private def startMiningBlocks(mineBlocks: MineBlocks, parentBlock: Block) = { self ! MineBlock sender() ! MiningOrdered context.become(working(mineBlocks.numBlocks, mineBlocks.withTransactions, parentBlock, None)) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala index 7b453ae48a..cb1a959e67 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala @@ -403,7 +403,7 @@ class BlockPreparator( block.copy(body = block.body.copy(transactionList = txExecuted)), execResult, worldPersisted.stateRootHash, - worldToPersist + worldPersisted ) } }