Skip to content

Commit af66053

Browse files
committed
[ETCM-927] enhance BlockchainTests/ValidBlocks/bcMultiChainTest/ChainAtoChainB_difficultyB test
1 parent f340fc5 commit af66053

File tree

10 files changed

+132
-24
lines changed

10 files changed

+132
-24
lines changed

src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ class EthBlocksService(val blockchain: Blockchain, val ledger: Ledger) extends R
7070
*/
7171
def getByBlockHash(request: BlockByBlockHashRequest): ServiceResponse[BlockByBlockHashResponse] = Task {
7272
val BlockByBlockHashRequest(blockHash, fullTxs) = request
73-
val blockOpt = blockchain.getBlockByHash(blockHash)
74-
val weight = blockchain.getChainWeightByHash(blockHash)
73+
val blockOpt = ledger.getBlockByHash(blockHash)
74+
val weight = ledger.getChainWeightByHash(blockHash)
7575

7676
val blockResponseOpt = blockOpt.map(block => BlockResponse(block, weight, fullTxs = fullTxs))
7777
Right(BlockByBlockHashResponse(blockResponseOpt))

src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class TestService(
134134
def setChainParams(request: SetChainParamsRequest): ServiceResponse[SetChainParamsResponse] = {
135135
currentConfig = buildNewConfig(request.chainParams.blockchainParams)
136136

137+
// clear ledger's cache on test start
138+
// setChainParams is expected to be the first remote call for each test
139+
testModeComponentsProvider.clearState()
140+
137141
val genesisData = GenesisData(
138142
nonce = request.chainParams.genesis.nonce,
139143
mixHash = Some(request.chainParams.genesis.mixHash),
@@ -272,15 +276,20 @@ class TestService(
272276
testModeComponentsProvider
273277
.ledger(currentConfig, sealEngine)
274278
.importBlock(value)
275-
.flatMap(handleResult)
279+
.flatMap(handleResult(value))
276280
}
277281
}
278282

279-
private def handleResult(blockImportResult: BlockImportResult): ServiceResponse[ImportRawBlockResponse] = {
283+
private def handleResult(
284+
block: Block
285+
)(blockImportResult: BlockImportResult): ServiceResponse[ImportRawBlockResponse] = {
280286
blockImportResult match {
281287
case BlockImportedToTop(blockImportData) =>
282288
val blockHash = s"0x${ByteStringUtils.hash2string(blockImportData.head.block.header.hash)}"
283289
ImportRawBlockResponse(blockHash).rightNow
290+
case BlockEnqueued =>
291+
val blockHash = s"0x${ByteStringUtils.hash2string(block.hash)}"
292+
ImportRawBlockResponse(blockHash).rightNow
284293
case e =>
285294
log.warn("Block import failed with {}", e)
286295
Task.now(Left(JsonRpcError(-1, "block validation failed!", None)))

src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,28 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val
7676
}
7777
}
7878

79+
/**
80+
* Remove all blocks currently queued
81+
*/
82+
def clear(): Unit = {
83+
blocks.clear()
84+
parentToChildren.clear()
85+
}
86+
7987
def getBlockByHash(hash: ByteString): Option[Block] =
8088
blocks.get(hash).map(_.block)
8189

8290
def isQueued(hash: ByteString): Boolean =
8391
blocks.contains(hash)
8492

93+
/**
94+
* Returns the weight of the block corresponding to the hash, or None if not found
95+
* @param hash the block's hash to get the weight from
96+
* @return the weight of the block corresponding to the hash, or None if not found
97+
*/
98+
def getChainWeightByHash(hash: ByteString): Option[ChainWeight] =
99+
blocks.get(hash).flatMap(_.weight)
100+
85101
/**
86102
* Takes a branch going from descendant block upwards to the oldest ancestor
87103
* @param descendant the youngest block to be removed

src/main/scala/io/iohk/ethereum/ledger/Ledger.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ trait Ledger {
2828
*/
2929
def getBlockByHash(hash: ByteString): Option[Block]
3030

31+
/**
32+
* Returns the chain weight if the block represented by its hash is either stored in the blockchain or enqueued
33+
* @param hash the hash of the block to retrieve the chain weight
34+
* @return the chain weight if the block represented by its hash is either stored in the blockchain or enqueued
35+
*/
36+
def getChainWeightByHash(hash: ByteString): Option[ChainWeight]
37+
3138
/** Tries to import the block as the new best block in the chain or enqueue it for later processing.
3239
*
3340
* The implementation uses [[io.iohk.ethereum.consensus.Consensus]] in order to apply
@@ -117,6 +124,9 @@ class LedgerImpl(
117124
override def getBlockByHash(hash: ByteString): Option[Block] =
118125
blockchain.getBlockByHash(hash) orElse blockQueue.getBlockByHash(hash)
119126

127+
override def getChainWeightByHash(hash: ByteString): Option[ChainWeight] =
128+
blockchain.getChainWeightByHash(hash) orElse blockQueue.getChainWeightByHash(hash)
129+
120130
override def importBlock(
121131
block: Block
122132
)(implicit blockExecutionScheduler: Scheduler): Task[BlockImportResult] =

src/main/scala/io/iohk/ethereum/testmode/TestEthBlockServiceWrapper.scala

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import io.iohk.ethereum.jsonrpc.{
66
BaseBlockResponse,
77
BaseTransactionResponse,
88
EthBlocksService,
9+
JsonRpcError,
910
ServiceResponse,
1011
TransactionData
1112
}
@@ -30,9 +31,18 @@ class TestEthBlockServiceWrapper(blockchain: Blockchain, ledger: Ledger, consens
3031
.getByBlockHash(request)
3132
.map(
3233
_.map(blockByBlockResponse => {
33-
val fullBlock = blockchain.getBlockByNumber(blockByBlockResponse.blockResponse.get.number).get
34-
BlockByBlockHashResponse(blockByBlockResponse.blockResponse.map(response => toEthResponse(fullBlock, response)))
35-
})
34+
blockByBlockResponse.blockResponse
35+
.toRight("missing block response")
36+
.flatMap(baseBlockResponse => baseBlockResponse.hash.toRight(s"missing hash for block $baseBlockResponse"))
37+
.flatMap(hash => ledger.getBlockByHash(hash).toRight(s"unable to find block for hash=$hash"))
38+
.map(fullBlock =>
39+
BlockByBlockHashResponse(
40+
blockByBlockResponse.blockResponse.map(response => toEthResponse(fullBlock, response))
41+
)
42+
)
43+
.left
44+
.map(errorMessage => JsonRpcError.LogicError(errorMessage))
45+
}).flatten
3646
)
3747

3848
/**
@@ -120,9 +130,9 @@ final case class EthTransactionResponse(
120130
gasPrice: BigInt,
121131
gas: BigInt,
122132
input: ByteString,
123-
r: ByteString,
124-
s: ByteString,
125-
v: ByteString
133+
r: BigInt,
134+
s: BigInt,
135+
v: BigInt
126136
) extends BaseTransactionResponse
127137

128138
object EthTransactionResponse {
@@ -147,8 +157,8 @@ object EthTransactionResponse {
147157
gasPrice = stx.tx.gasPrice,
148158
gas = stx.tx.gasLimit,
149159
input = stx.tx.payload,
150-
r = UInt256(stx.signature.r).bytes,
151-
s = UInt256(stx.signature.s).bytes,
152-
v = ByteString(stx.signature.v)
160+
r = stx.signature.r,
161+
s = stx.signature.s,
162+
v = stx.signature.v
153163
)
154164
}

src/main/scala/io/iohk/ethereum/testmode/TestModeComponentsProvider.scala

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package io.iohk.ethereum.testmode
22

33
import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator
4-
import io.iohk.ethereum.consensus.{Consensus, ConsensusConfig}
4+
import io.iohk.ethereum.consensus.ConsensusConfig
55
import io.iohk.ethereum.domain.BlockchainImpl
66
import io.iohk.ethereum.ledger.Ledger.VMImpl
7-
import io.iohk.ethereum.ledger.{Ledger, LedgerImpl, StxLedger}
7+
import io.iohk.ethereum.ledger.{BlockQueue, Ledger, LedgerImpl, StxLedger}
88
import io.iohk.ethereum.utils.BlockchainConfig
99
import io.iohk.ethereum.utils.Config.SyncConfig
1010
import monix.execution.Scheduler
1111

12+
import scala.collection.immutable.HashMap
13+
1214
/** Provides a ledger or consensus instances with modifiable blockchain config (used in test mode). */
1315
class TestModeComponentsProvider(
1416
blockchain: BlockchainImpl,
@@ -19,14 +21,42 @@ class TestModeComponentsProvider(
1921
vm: VMImpl
2022
) {
2123

22-
def ledger(blockchainConfig: BlockchainConfig, sealEngine: SealEngineType): Ledger =
23-
new LedgerImpl(
24-
blockchain,
25-
blockchainConfig,
26-
syncConfig,
27-
consensus(blockchainConfig, sealEngine),
28-
validationExecutionContext
24+
private var cache = HashMap.empty[(BlockchainConfig, SealEngineType), Ledger]
25+
private var blockQueue = BlockQueue(blockchain, syncConfig)
26+
27+
/**
28+
* Clear the internal builder state
29+
*/
30+
def clearState(): Unit = {
31+
blockQueue = BlockQueue(blockchain, syncConfig)
32+
cache = cache.empty
33+
}
34+
35+
/**
36+
* Create a ledger depending on parameters.
37+
* The same instance is returned for multiple calls with the same parameters.
38+
* @see [[io.iohk.ethereum.testmode.TestModeComponentsProvider#clearState]] to clear the cache
39+
* @param blockchainConfig
40+
* @param sealEngine
41+
* @return a ledger instance
42+
*/
43+
def ledger(blockchainConfig: BlockchainConfig, sealEngine: SealEngineType): Ledger = {
44+
cache.getOrElse(
45+
(blockchainConfig, sealEngine), {
46+
val newLedger: Ledger = new LedgerImpl(
47+
blockchain,
48+
blockQueue,
49+
blockchainConfig,
50+
consensus(blockchainConfig, sealEngine),
51+
validationExecutionContext
52+
)
53+
cache += (blockchainConfig, sealEngine) -> newLedger
54+
newLedger
55+
}
2956
)
57+
58+
}
59+
3060
def stxLedger(blockchainConfig: BlockchainConfig, sealEngine: SealEngineType): StxLedger =
3161
new StxLedger(blockchain, blockchainConfig, consensus(blockchainConfig, sealEngine).blockPreparator)
3262
def consensus(

src/main/scala/io/iohk/ethereum/testmode/TestModeServiceBuilder.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,18 @@ trait TestModeServiceBuilder extends LedgerBuilder {
4242
): Task[BlockImportResult] = testLedger.importBlock(block)
4343
override def resolveBranch(headers: NonEmptyList[BlockHeader]): BranchResolutionResult =
4444
testLedger.resolveBranch(headers)
45+
46+
/**
47+
* Returns the chain weight if the block represented by its hash is either stored in the blockchain or enqueued
48+
*
49+
* @param hash the hash of the block to retrieve the chain weight
50+
* @return
51+
*/
52+
override def getChainWeightByHash(hash: ByteString): Option[ChainWeight] = testLedger.getChainWeightByHash(hash)
4553
}
4654

4755
override lazy val ledger: Ledger = new TestLedgerProxy
56+
// override lazy val ledger: Ledger = testModeComponentsProvider.ledger(blockchainConfig, SealEngineType.NoReward)
4857
override lazy val stxLedger: StxLedger =
4958
testModeComponentsProvider.stxLedger(blockchainConfig, SealEngineType.NoReward)
5059
}

src/test/scala/io/iohk/ethereum/Mocks.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ object Mocks {
2828

2929
override def getBlockByHash(hash: ByteString): Option[Block] = ???
3030

31+
override def getChainWeightByHash(hash: ByteString): Option[ChainWeight] = ???
32+
3133
override def importBlock(block: Block)(implicit blockExecutionContext: Scheduler): Task[BlockImportResult] = ???
3234

3335
override def resolveBranch(headers: NonEmptyList[BlockHeader]): BranchResolutionResult = ???

src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,18 @@ class EthBlocksServiceSpec
411411
class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup {
412412
val blockGenerator = mock[PoWBlockGenerator]
413413
val appStateStorage = mock[AppStateStorage]
414-
override lazy val ledger = mock[Ledger]
414+
override lazy val ledger = {
415+
val ledgerMock = mock[Ledger]
416+
// properly mock the getBlockByHash and getChainWeightByHash
417+
// they are needed for handling the json rpc getBlockByHash request
418+
(ledgerMock.getBlockByHash _).expects(*).onCall {
419+
blockchain.getBlockByHash _
420+
}
421+
(ledgerMock.getChainWeightByHash _).expects(*).onCall {
422+
blockchain.getChainWeightByHash _
423+
}
424+
ledgerMock
425+
}
415426
override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator)
416427
override lazy val consensusConfig = ConsensusConfigs.consensusConfig
417428

src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,18 @@ class JsonRpcControllerFixture(implicit system: ActorSystem)
4444
val blockGenerator = mock[PoWBlockGenerator]
4545

4646
val syncingController = TestProbe()
47-
override lazy val ledger = mock[Ledger]
47+
override lazy val ledger = {
48+
val ledgerMock = mock[Ledger]
49+
// properly mock the getBlockByHash and getChainWeightByHash
50+
// they are needed for handling the json rpc getBlockByHash request
51+
(ledgerMock.getBlockByHash _).expects(*).onCall {
52+
blockchain.getBlockByHash _
53+
}
54+
(ledgerMock.getChainWeightByHash _).expects(*).onCall {
55+
blockchain.getChainWeightByHash _
56+
}
57+
ledgerMock
58+
}
4859
override lazy val stxLedger = mock[StxLedger]
4960
override lazy val validators = mock[ValidatorsExecutor]
5061
override lazy val consensus: TestConsensus = buildTestConsensus()

0 commit comments

Comments
 (0)