Skip to content

Commit b9f3c0b

Browse files
author
Aurélien Richez
authored
[ETCM-1042] Switch to a case class implementation for blockchain branch (#1073)
* [ETCM-1042] store only hash and number in best branch * [ETCM-1042] move getBlockByNumber to BlockchainReader and out of Branch interface * [ETCM-1042] move getHashByBlockNumber to BlockchainReader and out of Branch interface * [ETCM-1042] move isInChain to BlockchainReader and out of Branch interface * [ETCM-1042] remove old branch interface * [ETCM-1042] rename BestBranchSubset to BestBranch
1 parent 4db8224 commit b9f3c0b

File tree

24 files changed

+93
-132
lines changed

24 files changed

+93
-132
lines changed

src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
124124
_ <- peer2.importBlocksUntil(30)(IdentityUpdate)
125125
_ <- peer1.startRegularSync()
126126
_ <- peer2.startRegularSync()
127-
_ <- peer2.addCheckpointedBlock(peer2.blockchainReader.getBestBranch().getBlockByNumber(25).get)
127+
_ <- peer2.addCheckpointedBlock(
128+
peer2.blockchainReader.getBlockByNumber(peer2.blockchainReader.getBestBranch(), 25).get
129+
)
128130
_ <- peer2.waitForRegularSyncLoadLastBlock(length)
129131
_ <- peer1.connectToPeers(Set(peer2.node))
130132
_ <- peer1.waitForRegularSyncLoadLastBlock(length)
@@ -181,8 +183,8 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
181183
)
182184
)
183185
(
184-
peer1.blockchainReader.getBestBranch().getBlockByNumber(blockNumer + 1),
185-
peer2.blockchainReader.getBestBranch().getBlockByNumber(blockNumer + 1)
186+
peer1.blockchainReader.getBlockByNumber(peer1.blockchainReader.getBestBranch(), blockNumer + 1),
187+
peer2.blockchainReader.getBlockByNumber(peer2.blockchainReader.getBestBranch(), blockNumer + 1)
186188
) match {
187189
case (Some(blockP1), Some(blockP2)) =>
188190
assert(peer1.bl.getChainWeightByHash(blockP1.hash) == peer2.bl.getChainWeightByHash(blockP2.hash))

src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,7 @@ object RegularSyncItSpecUtils {
189189
Task(blockNumber match {
190190
case Some(bNumber) =>
191191
blockchainReader
192-
.getBestBranch()
193-
.getBlockByNumber(bNumber)
192+
.getBlockByNumber(blockchainReader.getBestBranch(), bNumber)
194193
.getOrElse(throw new RuntimeException(s"block by number: $bNumber doesn't exist"))
195194
case None => blockchainReader.getBestBlock().get
196195
}).flatMap { block =>

src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import io.iohk.ethereum.db.storage.pruning.PruningMode
2626
import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty
2727
import io.iohk.ethereum.domain.Blockchain
2828
import io.iohk.ethereum.domain._
29-
import io.iohk.ethereum.domain.branch.Branch
3029
import io.iohk.ethereum.jsonrpc.ProofService.EmptyStorageValueProof
3130
import io.iohk.ethereum.jsonrpc.ProofService.StorageProof
3231
import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey
@@ -102,9 +101,7 @@ object DumpChainApp
102101

103102
val blockchain: Blockchain = new BlockchainMock(genesisHash)
104103
val blockchainReader: BlockchainReader = mock[BlockchainReader]
105-
val bestChain: Branch = mock[Branch]
106-
(blockchainReader.getBestBranch _).expects().anyNumberOfTimes().returning(bestChain)
107-
(bestChain.getHashByBlockNumber _).expects(*).returning(Some(genesisHash))
104+
(blockchainReader.getHashByBlockNumber _).expects(*, *).returning(Some(genesisHash))
108105

109106
val nodeStatus: NodeStatus =
110107
NodeStatus(key = nodeKey, serverStatus = ServerStatus.NotListening, discoveryStatus = ServerStatus.NotListening)

src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ trait OmmersValidator {
3434
val getNBlocksBack: (ByteString, Int) => List[Block] =
3535
(_, n) =>
3636
((blockNumber - n) until blockNumber).toList
37-
.flatMap(nb => bestBranch.getBlockByNumber(nb))
37+
.flatMap(nb => blockchainReader.getBlockByNumber(bestBranch, nb))
3838

3939
validate(parentHash, blockNumber, ommers, getBlockHeaderByHash, getNBlocksBack)
4040
}

src/main/scala/io/iohk/ethereum/domain/Blockchain.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class BlockchainImpl(
211211
val latestCheckpointNumber = getLatestCheckpointBlockNumber()
212212

213213
val blockNumberMappingUpdates =
214-
if (blockchainReader.getBestBranch().getHashByBlockNumber(block.number).contains(blockHash))
214+
if (blockchainReader.getHashByBlockNumber(blockchainReader.getBestBranch(), block.number).contains(blockHash))
215215
removeBlockNumberMapping(block.number)
216216
else blockNumberMappingStorage.emptyBatchUpdate
217217

@@ -280,7 +280,7 @@ class BlockchainImpl(
280280
): BigInt =
281281
if (blockNumberToCheck > 0) {
282282
val maybePreviousCheckpointBlockNumber = for {
283-
currentBlock <- blockchainReader.getBestBranch().getBlockByNumber(blockNumberToCheck)
283+
currentBlock <- blockchainReader.getBlockByNumber(blockchainReader.getBestBranch(), blockNumberToCheck)
284284
if currentBlock.hasCheckpoint &&
285285
currentBlock.number < latestCheckpointBlockNumber
286286
} yield currentBlock.number

src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import io.iohk.ethereum.db.storage.ReceiptStorage
1010
import io.iohk.ethereum.db.storage.StateStorage
1111
import io.iohk.ethereum.domain.branch.BestBranch
1212
import io.iohk.ethereum.domain.branch.Branch
13-
import io.iohk.ethereum.domain.branch.EmptyBranch$
13+
import io.iohk.ethereum.domain.branch.EmptyBranch
1414
import io.iohk.ethereum.mpt.MptNode
1515
import io.iohk.ethereum.utils.Logger
1616

@@ -71,16 +71,14 @@ class BlockchainReader(
7171
def getReceiptsByHash(blockhash: ByteString): Option[Seq[Receipt]] = receiptStorage.get(blockhash)
7272

7373
/** get the current best stored branch */
74-
def getBestBranch(): Branch =
75-
getBestBlock()
76-
.map { block =>
77-
new BestBranch(
78-
block.header,
79-
blockNumberMappingStorage,
80-
this
81-
)
82-
}
83-
.getOrElse(EmptyBranch$)
74+
def getBestBranch(): Branch = {
75+
val number = getBestBlockNumber()
76+
blockNumberMappingStorage
77+
.get(number)
78+
.orElse(blockNumberMappingStorage.get(appStateStorage.getBestBlockNumber()))
79+
.map(hash => BestBranch(hash, number))
80+
.getOrElse(EmptyBranch)
81+
}
8482

8583
def getBestBlockNumber(): BigInt = {
8684
val bestSavedBlockNumber = appStateStorage.getBestBlockNumber()
@@ -113,6 +111,36 @@ class BlockchainReader(
113111
def genesisBlock: Block =
114112
getBlockByNumber(0).get
115113

114+
/** Returns a block inside this branch based on its number */
115+
def getBlockByNumber(branch: Branch, number: BigInt): Option[Block] = branch match {
116+
case BestBranch(_, tipBlockNumber) if tipBlockNumber >= number && number >= 0 =>
117+
for {
118+
hash <- getHashByBlockNumber(number)
119+
block <- getBlockByHash(hash)
120+
} yield block
121+
case EmptyBranch | BestBranch(_, _) => None
122+
}
123+
124+
/** Returns a block hash for the block at the given height if any */
125+
def getHashByBlockNumber(branch: Branch, number: BigInt): Option[ByteString] = branch match {
126+
case BestBranch(_, tipBlockNumber) =>
127+
if (tipBlockNumber >= number && number >= 0) {
128+
blockNumberMappingStorage.get(number)
129+
} else None
130+
131+
case EmptyBranch => None
132+
}
133+
134+
/** Checks if given block hash is in this chain. (i.e. is an ancestor of the tip block) */
135+
def isInChain(branch: Branch, hash: ByteString): Boolean = branch match {
136+
case BestBranch(_, tipBlockNumber) =>
137+
(for {
138+
header <- getBlockHeaderByHash(hash) if header.number <= tipBlockNumber
139+
hashFromBestChain <- getHashByBlockNumber(branch, header.number)
140+
} yield header.hash == hashFromBestChain).getOrElse(false)
141+
case EmptyBranch => false
142+
}
143+
116144
/** Allows to query for a block based on it's number
117145
*
118146
* @param number Block number

src/main/scala/io/iohk/ethereum/domain/branch/BestBranch.scala

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/main/scala/io/iohk/ethereum/domain/branch/Branch.scala

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,8 @@ package io.iohk.ethereum.domain.branch
22

33
import akka.util.ByteString
44

5-
import io.iohk.ethereum.domain.Block
5+
sealed trait Branch
66

7-
/** An interface to manipulate blockchain branches */
8-
trait Branch {
7+
case class BestBranch(tipBlockHash: ByteString, tipBlockNumber: BigInt) extends Branch
98

10-
/** Returns a block inside this branch based on its number */
11-
def getBlockByNumber(number: BigInt): Option[Block]
12-
13-
/** Returns a block hash for the block at the given height if any */
14-
def getHashByBlockNumber(number: BigInt): Option[ByteString]
15-
16-
/** Checks if given block hash is in this chain. (i.e. is an ancestor of the tip block) */
17-
def isInChain(hash: ByteString): Boolean
18-
}
9+
case object EmptyBranch extends Branch

src/main/scala/io/iohk/ethereum/domain/branch/EmptyBranch$.scala

Lines changed: 0 additions & 13 deletions
This file was deleted.

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint
99
import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator
1010
import io.iohk.ethereum.crypto.ECDSASignature
1111
import io.iohk.ethereum.domain.Block
12-
import io.iohk.ethereum.domain.Blockchain
1312
import io.iohk.ethereum.domain.BlockchainReader
1413
import io.iohk.ethereum.domain.Checkpoint
1514
import io.iohk.ethereum.ledger.BlockQueue
1615
import io.iohk.ethereum.utils.ByteStringUtils
1716
import io.iohk.ethereum.utils.Logger
1817

1918
class CheckpointingService(
20-
blockchain: Blockchain,
2119
blockchainReader: BlockchainReader,
2220
blockQueue: BlockQueue,
2321
checkpointBlockGenerator: CheckpointBlockGenerator,
@@ -36,7 +34,7 @@ class CheckpointingService(
3634
req.parentCheckpoint.forall(blockchainReader.getBlockHeaderByHash(_).exists(_.number < blockToReturnNum))
3735

3836
Task {
39-
blockchainReader.getBestBranch().getBlockByNumber(blockToReturnNum)
37+
blockchainReader.getBlockByNumber(blockchainReader.getBestBranch(), blockToReturnNum)
4038
}.flatMap {
4139
case Some(b) if isValidParent =>
4240
Task.now(Right(GetLatestBlockResponse(Some(BlockInfo(b.hash, b.number)))))

0 commit comments

Comments
 (0)