diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala index 1d6c2ea999..947a178803 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala @@ -3,7 +3,6 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.{Mocks, ObjectGenerators} import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainImpl, Receipt} import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError import io.iohk.ethereum.ledger.BlockQueue.Leaf @@ -11,14 +10,16 @@ import io.iohk.ethereum.network.p2p.messages.PV62.BlockBody import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.{BlockchainConfig, Config} import io.iohk.ethereum.validators.BlockHeaderError.{HeaderDifficultyError, HeaderParentNotFoundError} -import io.iohk.ethereum.validators.BlockHeaderValidator +import io.iohk.ethereum.validators.OmmersValidator.{GetBlockHeaderByHash, GetNBlocksBack} +import io.iohk.ethereum.validators.{BlockHeaderValidator, OmmersValidator, OmmersValidatorImpl} +import io.iohk.ethereum.{Mocks, ObjectGenerators} //import io.iohk.ethereum.validators.BlockHeaderError.HeaderDifficultyError //import io.iohk.ethereum.validators._ import org.scalamock.scalatest.MockFactory import org.scalatest.{FlatSpec, Matchers} -import scala.language.reflectiveCalls import scala.collection.mutable +import scala.language.reflectiveCalls class BlockImportSpec extends FlatSpec with Matchers with MockFactory { @@ -249,6 +250,45 @@ class BlockImportSpec extends FlatSpec with Matchers with MockFactory { } + it should "correctly import block with ommers and ancestor in block queue " in new OmmersTestSetup { + val ancestorForValidation = getBlock(0, difficulty = 1) + val ancestorForValidation1 = getBlock(1, difficulty = 2, parent = ancestorForValidation.header.hash) + val ancestorForValidation2 = getBlock(2, difficulty = 3, parent = ancestorForValidation1.header.hash) + + val block1 = getBlock(bestNum - 2, difficulty = 100, parent = ancestorForValidation2.header.hash) + val ommerBlock = getBlock(bestNum - 1, difficulty = 101, parent = block1.header.hash) + val oldBlock2 = getBlock(bestNum - 1, difficulty = 102, parent = block1.header.hash) + val oldBlock3 = getBlock(bestNum, difficulty = 103, parent = oldBlock2.header.hash) + val newBlock2 = getBlock(bestNum - 1, difficulty = 102, parent = block1.header.hash) + + val newBlock3WithOmmer = getBlock(bestNum, difficulty = 105, parent = newBlock2.header.hash, ommers = Seq(ommerBlock.header)) + + + val td1 = block1.header.difficulty + 999 + val oldTd2 = td1 + oldBlock2.header.difficulty + val oldTd3 = oldTd2 + oldBlock3.header.difficulty + + val newTd2 = td1 + newBlock2.header.difficulty + val newTd3 = newTd2 + newBlock3WithOmmer.header.difficulty + + blockchain.save(ancestorForValidation, Nil, 1, false) + blockchain.save(ancestorForValidation1, Nil, 3, false) + blockchain.save(ancestorForValidation2, Nil, 6, false) + + blockchain.save(block1, Nil, td1, true) + blockchain.save(oldBlock2, receipts, oldTd2, true) + blockchain.save(oldBlock3, Nil, oldTd3, true) + + ledger.setExecutionResult(newBlock2, Right(Nil)) + ledger.setExecutionResult(newBlock3WithOmmer, Right(receipts)) + + ledger.importBlock(newBlock2) shouldEqual BlockEnqueued + ledger.importBlock(newBlock3WithOmmer) shouldEqual + ChainReorganised(List(oldBlock2, oldBlock3), List(newBlock2, newBlock3WithOmmer), List(newTd2, newTd3)) + + blockchain.getBestBlock() shouldEqual newBlock3WithOmmer + } + trait TestSetup { val blockchainConfig = BlockchainConfig(Config.config) val blockQueue: BlockQueue @@ -291,14 +331,15 @@ class BlockImportSpec extends FlatSpec with Matchers with MockFactory { number: BigInt = 1, difficulty: BigInt = 100, parent: ByteString = randomHash(), - salt: ByteString = randomHash()): Block = + salt: ByteString = randomHash(), + ommers: Seq[BlockHeader] = Nil): Block = Block( defaultHeader.copy( parentHash = parent, difficulty = difficulty, number = number, extraData = salt), - BlockBody(Nil, Nil)) + BlockBody(Nil, ommers)) def getChain(from: BigInt, to: BigInt, parent: ByteString = randomHash()): List[Block] = if (from > to) @@ -363,4 +404,26 @@ class BlockImportSpec extends FlatSpec with Matchers with MockFactory { setHeaderByHash(header.parentHash, None) } } + + trait OmmersTestSetup extends EphemBlockchain with TestSetup { + object OmmerValidation extends Mocks.MockValidatorsAlwaysSucceed { + override val ommersValidator: OmmersValidator = + (parentHash: ByteString, + blockNumber: BigInt, + ommers: Seq[BlockHeader], + getBlockHeaderByHash: GetBlockHeaderByHash, + getNBlocksBack: GetNBlocksBack) => + new OmmersValidatorImpl(blockchainConfig, blockHeaderValidator).validate(parentHash, blockNumber, ommers, getBlockHeaderByHash, getNBlocksBack) + } + + override lazy val ledger = new LedgerImpl(new Mocks.MockVM(), blockchain, blockQueue, blockchainConfig, OmmerValidation) { + private val results = mutable.Map[ByteString, Either[BlockExecutionError, Seq[Receipt]]]() + + override def executeBlock(block: Block, alreadyValidated: Boolean = false): Either[BlockExecutionError, Seq[Receipt]] = + results(block.header.hash) + + def setExecutionResult(block: Block, result: Either[BlockExecutionError, Seq[Receipt]]): Unit = + results(block.header.hash) = result + } + } }