Skip to content

Commit

Permalink
[ECTM-212] Fix block preparation (taking into account EIP-161)
Browse files Browse the repository at this point in the history
  • Loading branch information
Michal Mrozek committed Oct 15, 2020
1 parent 5fb0b41 commit ba5a6e5
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 216 deletions.
99 changes: 59 additions & 40 deletions src/main/scala/io/iohk/ethereum/domain/Blockchain.scala
Expand Up @@ -178,17 +178,21 @@ trait Blockchain {

def genesisBlock: Block = getBlockByNumber(0).get

def getWorldStateProxy(blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): WS

def getReadOnlyWorldStateProxy(blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): WS
def getWorldStateProxy(
blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean
): WS

def getReadOnlyWorldStateProxy(
blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean
): WS

def getStateStorage: StateStorage
}
Expand Down Expand Up @@ -259,7 +263,11 @@ class BlockchainImpl(
mpt.get(address)
}

override def getAccountStorageAt(rootHash: ByteString, position: BigInt, ethCompatibleStorage: Boolean): ByteString = {
override def getAccountStorageAt(
rootHash: ByteString,
position: BigInt,
ethCompatibleStorage: Boolean
): ByteString = {
val storage = stateStorage.getBackingStorage(0)
val mpt =
if (ethCompatibleStorage) domain.EthereumUInt256Mpt.storageMpt(rootHash, storage)
Expand All @@ -268,7 +276,8 @@ class BlockchainImpl(
}

private def persistBestBlocksData(): Unit = {
appStateStorage.putBestBlockNumber(getBestBlockNumber())
appStateStorage
.putBestBlockNumber(getBestBlockNumber())
.and(appStateStorage.putLatestCheckpointBlockNumber(getLatestCheckpointBlockNumber()))
.commit()
}
Expand Down Expand Up @@ -298,7 +307,8 @@ class BlockchainImpl(
override def getMptNodeByHash(hash: ByteString): Option[MptNode] =
stateStorage.getNode(hash)

override def getTransactionLocation(txHash: ByteString): Option[TransactionLocation] = transactionMappingStorage.get(txHash)
override def getTransactionLocation(txHash: ByteString): Option[TransactionLocation] =
transactionMappingStorage.get(txHash)

override def storeBlockBody(blockHash: ByteString, blockBody: BlockBody): DataSourceBatchUpdate = {
blockBodiesStorage.put(blockHash, blockBody).and(saveTxsLocations(blockHash, blockBody))
Expand Down Expand Up @@ -351,14 +361,15 @@ class BlockchainImpl(
val bestBlocks = bestKnownBlockAndLatestCheckpoint.get()
// as we are decreasing block numbers in memory more often than in storage,
// we can't use here getBestBlockNumber / getLatestCheckpointBlockNumber
val bestBlockNumber = if(bestBlocks.bestBlockNumber != 0) bestBlocks.bestBlockNumber else appStateStorage.getBestBlockNumber()
val bestBlockNumber =
if (bestBlocks.bestBlockNumber != 0) bestBlocks.bestBlockNumber else appStateStorage.getBestBlockNumber()
val latestCheckpointNumber = {
if(bestBlocks.latestCheckpointNumber != 0) bestBlocks.latestCheckpointNumber
if (bestBlocks.latestCheckpointNumber != 0) bestBlocks.latestCheckpointNumber
else appStateStorage.getLatestCheckpointBlockNumber()
}

val blockNumberMappingUpdates = {
maybeBlockHeader.fold(blockNumberMappingStorage.emptyBatchUpdate)( h =>
maybeBlockHeader.fold(blockNumberMappingStorage.emptyBatchUpdate)(h =>
if (getHashByBlockNumber(h.number).contains(blockHash))
removeBlockNumberMapping(h.number)
else blockNumberMappingStorage.emptyBatchUpdate
Expand All @@ -369,19 +380,22 @@ class BlockchainImpl(
case Some(header) =>
if (header.hasCheckpoint && header.number == latestCheckpointNumber) {
val prev = findPreviousCheckpointBlockNumber(header.number, header.number)
prev.map { num =>
(appStateStorage.putLatestCheckpointBlockNumber(num), Some(num))
}.getOrElse {
(appStateStorage.removeLatestCheckpointBlockNumber(), Some(0))
}
prev
.map { num =>
(appStateStorage.putLatestCheckpointBlockNumber(num), Some(num))
}
.getOrElse {
(appStateStorage.removeLatestCheckpointBlockNumber(), Some(0))
}
} else (appStateStorage.emptyBatchUpdate, None)
case None =>
(appStateStorage.emptyBatchUpdate, None)
}

val newBestBlockNumber: BigInt = if(bestBlockNumber >= 1) bestBlockNumber - 1 else 0
val newBestBlockNumber: BigInt = if (bestBlockNumber >= 1) bestBlockNumber - 1 else 0

blockHeadersStorage.remove(blockHash)
blockHeadersStorage
.remove(blockHash)
.and(blockBodiesStorage.remove(blockHash))
.and(totalDifficultyStorage.remove(blockHash))
.and(receiptStorage.remove(blockHash))
Expand All @@ -394,7 +408,8 @@ class BlockchainImpl(

maybeBlockHeader.foreach { h =>
if (withState) {
val bestBlocksUpdates = appStateStorage.putBestBlockNumber(newBestBlockNumber)
val bestBlocksUpdates = appStateStorage
.putBestBlockNumber(newBestBlockNumber)
.and(checkpointUpdates)
stateStorage.onBlockRollback(h.number, bestBlockNumber)(() => bestBlocksUpdates.commit())
}
Expand All @@ -408,8 +423,8 @@ class BlockchainImpl(
*/
@tailrec
private def findPreviousCheckpointBlockNumber(
blockNumberToCheck: BigInt,
latestCheckpointBlockNumber: BigInt
blockNumberToCheck: BigInt,
latestCheckpointBlockNumber: BigInt
): Option[BigInt] = {
if (blockNumberToCheck > 0) {
val maybePreviousCheckpointBlockNumber = for {
Expand All @@ -432,19 +447,21 @@ class BlockchainImpl(
}

private def removeTxsLocations(stxs: Seq[SignedTransaction]): DataSourceBatchUpdate = {
stxs.map(_.hash).foldLeft(transactionMappingStorage.emptyBatchUpdate) {
case (updates, hash) => updates.and(transactionMappingStorage.remove(hash))
stxs.map(_.hash).foldLeft(transactionMappingStorage.emptyBatchUpdate) { case (updates, hash) =>
updates.and(transactionMappingStorage.remove(hash))
}
}

override type S = InMemoryWorldStateProxyStorage
override type WS = InMemoryWorldStateProxy

override def getWorldStateProxy(blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): InMemoryWorldStateProxy =
override def getWorldStateProxy(
blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean
): InMemoryWorldStateProxy =
InMemoryWorldStateProxy(
evmCodeStorage,
stateStorage.getBackingStorage(blockNumber),
Expand All @@ -456,18 +473,20 @@ class BlockchainImpl(
)

//FIXME Maybe we can use this one in regular execution too and persist underlying storage when block execution is successful
override def getReadOnlyWorldStateProxy(blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): InMemoryWorldStateProxy =
override def getReadOnlyWorldStateProxy(
blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean
): InMemoryWorldStateProxy =
InMemoryWorldStateProxy(
evmCodeStorage,
stateStorage.getReadOnlyStorage,
accountStartNonce,
(number: BigInt) => getBlockHeaderByNumber(number).map(_.hash),
stateRootHash,
noEmptyAccounts = false,
noEmptyAccounts = noEmptyAccounts,
ethCompatibleStorage = ethCompatibleStorage
)

Expand Down

0 comments on commit ba5a6e5

Please sign in to comment.