Skip to content

Commit adb8e6c

Browse files
author
Aurélien Richez
committed
Adds bestBlock hash in app state
1 parent 5dc67e6 commit adb8e6c

21 files changed

+117
-71
lines changed

bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.iohk.ethereum.utils
22

3+
import akka.util.ByteString
4+
35
object Hex {
46
def toHexString(bytes: Array[Byte]): String =
57
bytes.map("%02x".format(_)).mkString

src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class BlockImporterItSpec
107107
blockchainWriter.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true)
108108
blockchainWriter.save(oldBlock4, Nil, oldWeight4, saveAsBestBlock = true)
109109
// simulation of node restart
110-
blockchain.saveBestKnownBlocks(blockchainReader.getBestBlockNumber() - 1)
110+
blockchain.saveBestKnownBlocks(oldBlock3.header.hash, oldBlock3.number)
111111
blockchainWriter.save(newBlock4ParentOldBlock3, Nil, newBlock4WeightParentOldBlock3, saveAsBestBlock = true)
112112

113113
//not reorganising anymore until oldBlock4(not part of the chain anymore), no block/ommer validation when not part of the chain, resolveBranch is returning UnknownBranch

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,5 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain {
205205
override def getBackingMptStorage(blockNumber: BigInt): MptStorage = ???
206206

207207
override def getReadOnlyMptStorage(): MptStorage = ???
208+
208209
}

src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,9 @@ class ConsensusImpl(
302302
case BlockData(block, _, _) if block.hasCheckpoint => block.number
303303
}.maximumOption
304304

305-
val bestNumber = oldBranch.last.block.header.number
306-
blockchain.saveBestKnownBlocks(bestNumber, checkpointNumber)
307-
executedBlocks.foreach(data => blockQueue.enqueueBlock(data.block, bestNumber))
305+
val bestHeader = oldBranch.last.block.header
306+
blockchain.saveBestKnownBlocks(bestHeader.hash, bestHeader.number, checkpointNumber)
307+
executedBlocks.foreach(data => blockQueue.enqueueBlock(data.block, bestHeader.number))
308308

309309
newBranch.diff(executedBlocks.map(_.block)).headOption.foreach { block =>
310310
blockQueue.removeSubtree(block.header.hash)

src/main/scala/io/iohk/ethereum/db/storage/AppStateStorage.scala

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
package io.iohk.ethereum.db.storage
22

3-
import java.math.BigInteger
3+
import akka.util.ByteString
4+
import boopickle.Default.Unpickle
5+
import boopickle.Pickler
6+
import boopickle.DefaultBasic._
47

8+
import java.math.BigInteger
59
import scala.collection.immutable.ArraySeq
6-
710
import io.iohk.ethereum.db.dataSource.DataSource
811
import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate
912
import io.iohk.ethereum.db.storage.AppStateStorage._
13+
import io.iohk.ethereum.domain.appstate.BestBlockInfo
14+
import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes}
15+
import io.iohk.ethereum.utils.Hex
16+
import io.iohk.ethereum.utils.Picklers._
1017

1118
/** This class is used to store app state variables
1219
* Key: see AppStateStorage.Keys
@@ -27,6 +34,16 @@ class AppStateStorage(val dataSource: DataSource) extends TransactionalKeyValueS
2734
def getBestBlockNumber(): BigInt =
2835
getBigInt(Keys.BestBlockNumber)
2936

37+
def getBestBlockData(): BestBlockInfo =
38+
BestBlockInfo( // FIXME default value for hash ?
39+
get(Keys.BestBlockHash).map(v => ByteString(Hex.decode(v))).getOrElse(ByteString.empty),
40+
getBigInt(Keys.BestBlockNumber)
41+
)
42+
43+
def putBestBlockData(b: BestBlockInfo): DataSourceBatchUpdate =
44+
put(Keys.BestBlockNumber, b.number.toString)
45+
.and(put(Keys.BestBlockHash, Hex.toHexString(b.hash.toArray)))
46+
3047
def putBestBlockNumber(bestBlockNumber: BigInt): DataSourceBatchUpdate =
3148
put(Keys.BestBlockNumber, bestBlockNumber.toString)
3249

@@ -72,9 +89,17 @@ object AppStateStorage {
7289

7390
object Keys {
7491
val BestBlockNumber = "BestBlockNumber"
92+
val BestBlockHash = "BestBlockHash"
7593
val FastSyncDone = "FastSyncDone"
7694
val EstimatedHighestBlock = "EstimatedHighestBlock"
7795
val SyncStartingBlock = "SyncStartingBlock"
7896
val LatestCheckpointBlockNumber = "LatestCheckpointBlockNumber"
7997
}
98+
99+
implicit private val bestBlockDataPickler: Pickler[BestBlockInfo] = generatePickler[BestBlockInfo]
100+
private val bestBlockDataSerializer = (bestBlockData: BestBlockInfo) =>
101+
compactPickledBytes(Pickle.intoBytes(bestBlockData))
102+
private val bestBlockDataDeserializer =
103+
(byteSequenceToBuffer _).andThen(Unpickle[BestBlockInfo].fromBytes)
104+
80105
}

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

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package io.iohk.ethereum.domain
22

33
import akka.util.ByteString
4-
54
import scala.annotation.tailrec
6-
75
import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate
86
import io.iohk.ethereum.db.storage._
97
import io.iohk.ethereum.domain
8+
import io.iohk.ethereum.domain.appstate.BestBlockInfo
109
import io.iohk.ethereum.jsonrpc.ProofService.StorageProof
1110
import io.iohk.ethereum.ledger.InMemoryWorldStateProxy
1211
import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage
@@ -64,7 +63,11 @@ trait Blockchain {
6463

6564
def removeBlock(hash: ByteString): Unit
6665

67-
def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit
66+
def saveBestKnownBlocks(
67+
bestBlockHash: ByteString,
68+
bestBlockNumber: BigInt,
69+
latestCheckpointNumber: Option[BigInt] = None
70+
): Unit
6871

6972
}
7073

@@ -126,20 +129,28 @@ class BlockchainImpl(
126129

127130
def getReadOnlyMptStorage(): MptStorage = stateStorage.getReadOnlyStorage
128131

129-
override def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit =
132+
override def saveBestKnownBlocks(
133+
bestBlockHash: ByteString,
134+
bestBlockNumber: BigInt,
135+
latestCheckpointNumber: Option[BigInt] = None
136+
): Unit =
130137
latestCheckpointNumber match {
131138
case Some(number) =>
132-
saveBestKnownBlockAndLatestCheckpointNumber(bestBlockNumber, number)
139+
saveBestKnownBlockAndLatestCheckpointNumber(bestBlockHash, bestBlockNumber, number)
133140
case None =>
134-
saveBestKnownBlock(bestBlockNumber)
141+
saveBestKnownBlock(bestBlockHash, bestBlockNumber)
135142
}
136143

137-
private def saveBestKnownBlock(bestBlockNumber: BigInt): Unit =
138-
appStateStorage.putBestBlockNumber(bestBlockNumber).commit()
144+
private def saveBestKnownBlock(bestBlockHash: ByteString, bestBlockNumber: BigInt): Unit =
145+
appStateStorage.putBestBlockData(BestBlockInfo(bestBlockHash, bestBlockNumber)).commit()
139146

140-
private def saveBestKnownBlockAndLatestCheckpointNumber(number: BigInt, latestCheckpointNumber: BigInt): Unit =
147+
private def saveBestKnownBlockAndLatestCheckpointNumber(
148+
bestBlockHash: ByteString,
149+
number: BigInt,
150+
latestCheckpointNumber: BigInt
151+
): Unit =
141152
appStateStorage
142-
.putBestBlockNumber(number)
153+
.putBestBlockData(BestBlockInfo(bestBlockHash, number))
143154
.and(appStateStorage.putLatestCheckpointBlockNumber(latestCheckpointNumber))
144155
.commit()
145156

@@ -171,7 +182,8 @@ class BlockchainImpl(
171182
removeBlockNumberMapping(block.number)
172183
else blockNumberMappingStorage.emptyBatchUpdate
173184

174-
val newBestBlockNumber: BigInt = (bestBlockNumber - 1).max(0)
185+
val potientialNewBestBlockNumber: BigInt = (block.number - 1).max(0)
186+
val potientialNewBestBlockHash: ByteString = block.header.parentHash
175187
val newLatestCheckpointNumber: BigInt =
176188
if (block.hasCheckpoint && block.number == latestCheckpointNumber) {
177189
findPreviousCheckpointBlockNumber(block.number, block.number)
@@ -187,8 +199,8 @@ class BlockchainImpl(
187199
into the case of having an incomplete best block and so an inconsistent db
188200
*/
189201
val bestBlockNumberUpdates =
190-
if (appStateStorage.getBestBlockNumber() > newBestBlockNumber)
191-
appStateStorage.putBestBlockNumber(newBestBlockNumber)
202+
if (appStateStorage.getBestBlockNumber() > potientialNewBestBlockNumber)
203+
appStateStorage.putBestBlockData(BestBlockInfo(potientialNewBestBlockHash, potientialNewBestBlockNumber))
192204
else appStateStorage.emptyBatchUpdate
193205
val latestCheckpointNumberUpdates =
194206
if (appStateStorage.getLatestCheckpointBlockNumber() > newLatestCheckpointNumber)
@@ -197,7 +209,7 @@ class BlockchainImpl(
197209

198210
log.debug(
199211
"Persisting app info data into database. Persisted block number is {}. Persisted checkpoint number is {}",
200-
newBestBlockNumber,
212+
potientialNewBestBlockNumber,
201213
newLatestCheckpointNumber
202214
)
203215

@@ -215,7 +227,7 @@ class BlockchainImpl(
215227
log.debug(
216228
"Removed block with hash {}. New best block number - {}, new best checkpoint block number - {}",
217229
ByteStringUtils.hash2string(blockHash),
218-
newBestBlockNumber,
230+
potientialNewBestBlockNumber,
219231
newLatestCheckpointNumber
220232
)
221233
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.iohk.ethereum.domain
22

33
import akka.util.ByteString
4-
54
import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate
65
import io.iohk.ethereum.db.storage.AppStateStorage
76
import io.iohk.ethereum.db.storage.BlockBodiesStorage
@@ -11,6 +10,7 @@ import io.iohk.ethereum.db.storage.ChainWeightStorage
1110
import io.iohk.ethereum.db.storage.ReceiptStorage
1211
import io.iohk.ethereum.db.storage.TransactionMappingStorage
1312
import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation
13+
import io.iohk.ethereum.domain.appstate.BestBlockInfo
1414
import io.iohk.ethereum.utils.Logger
1515

1616
class BlockchainWriter(
@@ -31,14 +31,14 @@ class BlockchainWriter(
3131
block.header.number
3232
)
3333
appStateStorage
34-
.putBestBlockNumber(block.header.number)
34+
.putBestBlockData(BestBlockInfo(block.header.hash, block.header.number))
3535
.and(appStateStorage.putLatestCheckpointBlockNumber(block.header.number))
3636
} else if (saveAsBestBlock) {
3737
log.debug(
3838
"New best known block number - {}",
3939
block.header.number
4040
)
41-
appStateStorage.putBestBlockNumber(block.header.number)
41+
appStateStorage.putBestBlockData(BestBlockInfo(block.header.hash, block.header.number))
4242
} else {
4343
appStateStorage.emptyBatchUpdate
4444
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.iohk.ethereum.domain.appstate
2+
3+
import akka.util.ByteString
4+
5+
case class BestBlockInfo(hash: ByteString, number: BigInt)

src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.iohk.ethereum.blockchain.sync
22

3+
import io.iohk.ethereum.Fixtures
34
import io.iohk.ethereum.db.components.EphemDataSourceComponent
45
import io.iohk.ethereum.db.components.Storages
56
import io.iohk.ethereum.db.storage.pruning.ArchivePruning

src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class SyncStateSchedulerSpec
252252
buildScheduler()
253253
val header = Fixtures.Blocks.ValidBlock.header.copy(stateRoot = worldHash, number = 1)
254254
schedulerBlockchainWriter.storeBlockHeader(header).commit()
255-
schedulerBlockchain.saveBestKnownBlocks(1)
255+
schedulerBlockchain.saveBestKnownBlocks(header.hash, 1)
256256
var state = scheduler.initState(worldHash).get
257257
while (state.activeRequest.nonEmpty) {
258258
val (allMissingNodes1, state2) = scheduler.getAllMissingNodes(state)

src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ class RegularSyncSpec
738738
goToTop()
739739

740740
val num: BigInt = 42
741-
blockchain.saveBestKnownBlocks(num, Some(num))
741+
blockchain.saveBestKnownBlocks(testBlocks.head.hash, num, Some(num))
742742

743743
etcPeerManager.expectMsg(GetHandshakedPeers)
744744
etcPeerManager.reply(HandshakedPeers(handshakedPeers))

src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr
464464
.and(blockchainWriter.storeBlock(block95))
465465
.and(blockchainWriter.storeBlock(block96))
466466
.commit()
467-
blockchain.saveBestKnownBlocks(block96.number)
467+
blockchain.saveBestKnownBlocks(block96.hash, block96.number)
468468

469469
}
470470
}

src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
4444
it should "be able to store a block and retrieve it by number" in new EphemBlockchainTestSetup {
4545
val validBlock = Fixtures.Blocks.ValidBlock.block
4646
blockchainWriter.storeBlock(validBlock).commit()
47-
blockchain.saveBestKnownBlocks(validBlock.number)
47+
blockchain.saveBestKnownBlocks(validBlock.hash, validBlock.number)
4848
val block = blockchainReader.getBlockByNumber(blockchainReader.getBestBranch(), validBlock.header.number)
4949
block.isDefined should ===(true)
5050
validBlock should ===(block.get)
@@ -61,7 +61,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
6161
blockchainWriter.save(validBlock, Seq.empty, ChainWeight(100, 100), saveAsBestBlock = true)
6262
blockchainReader.isInChain(blockchainReader.getBestBranch(), validBlock.hash) should ===(true)
6363
// simulation of node restart
64-
blockchain.saveBestKnownBlocks(validBlock.header.number - 1)
64+
blockchain.saveBestKnownBlocks(validBlock.header.parentHash, validBlock.header.number - 1)
6565
blockchainReader.isInChain(blockchainReader.getBestBranch(), validBlock.hash) should ===(false)
6666
}
6767

@@ -151,7 +151,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
151151
val headerWithAcc = validHeader.copy(stateRoot = ByteString(mptWithAcc.getRootHash))
152152

153153
blockchainWriter.storeBlockHeader(headerWithAcc).commit()
154-
blockchain.saveBestKnownBlocks(headerWithAcc.number)
154+
blockchain.saveBestKnownBlocks(headerWithAcc.hash, headerWithAcc.number)
155155

156156
val retrievedAccount = blockchainReader.getAccount(blockchainReader.getBestBranch(), address, headerWithAcc.number)
157157
retrievedAccount shouldEqual Some(account)
@@ -171,7 +171,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
171171
val headerWithAcc = validHeader.copy(stateRoot = ByteString(mptWithAcc.getRootHash))
172172

173173
blockchainWriter.storeBlockHeader(headerWithAcc).commit()
174-
blockchain.saveBestKnownBlocks(headerWithAcc.number)
174+
blockchain.saveBestKnownBlocks(headerWithAcc.hash, headerWithAcc.number)
175175

176176
//unhappy path
177177
val wrongAddress = Address(666)
@@ -200,7 +200,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
200200
val headerWithAcc = Fixtures.Blocks.ValidBlock.header.copy(stateRoot = ByteString(mptWithAcc.getRootHash))
201201

202202
blockchainWriter.storeBlockHeader(headerWithAcc).commit()
203-
blockchain.saveBestKnownBlocks(headerWithAcc.number)
203+
blockchain.saveBestKnownBlocks(headerWithAcc.hash, headerWithAcc.number)
204204

205205
val wrongAddress = Address(666)
206206
val retrievedAccountProofWrong =

0 commit comments

Comments
 (0)