Skip to content

Commit

Permalink
move getAccount into BlockchainReader
Browse files Browse the repository at this point in the history
  • Loading branch information
Aurélien Richez committed Jul 22, 2021
1 parent 30caf6b commit 0c7ddd0
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 42 deletions.
10 changes: 0 additions & 10 deletions src/main/scala/io/iohk/ethereum/domain/Blockchain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ trait Blockchain {
type S <: Storage[S]
type WS <: WorldStateProxy[WS, S]

/** Get an account for an address and a block number
*
* @param address address of the account
* @param blockNumber the block that determines the state of the account
*/
def getAccount(address: Address, blockNumber: BigInt): Option[Account]

def getAccountProof(address: Address, blockNumber: BigInt): Option[Vector[MptNode]]

/** Get account storage at given position
Expand Down Expand Up @@ -99,9 +92,6 @@ class BlockchainImpl(
override def getLatestCheckpointBlockNumber(): BigInt =
blockchainMetadata.bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber

override def getAccount(address: Address, blockNumber: BigInt): Option[Account] =
getAccountMpt(blockNumber) >>= (_.get(address))

override def getAccountProof(address: Address, blockNumber: BigInt): Option[Vector[MptNode]] =
getAccountMpt(blockNumber) >>= (_.getProof(address))

Expand Down
27 changes: 25 additions & 2 deletions src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.iohk.ethereum.domain

import akka.util.ByteString

import io.iohk.ethereum.db.storage.AppStateStorage
import io.iohk.ethereum.db.storage.BlockBodiesStorage
import io.iohk.ethereum.db.storage.BlockHeadersStorage
Expand All @@ -11,7 +10,7 @@ import io.iohk.ethereum.db.storage.StateStorage
import io.iohk.ethereum.domain.branch.BestBranchSubset
import io.iohk.ethereum.domain.branch.Branch
import io.iohk.ethereum.domain.branch.EmptyBranch
import io.iohk.ethereum.mpt.MptNode
import io.iohk.ethereum.mpt.{MerklePatriciaTrie, MptNode}
import io.iohk.ethereum.utils.Logger

class BlockchainReader(
Expand Down Expand Up @@ -142,6 +141,21 @@ class BlockchainReader(
case EmptyBranch => false
}

/** Get an account for an address and a block number
*
* @param branch branch for which we want to get the account
* @param address address of the account
* @param blockNumber the block that determines the state of the account
*/
def getAccount(branch: Branch, address: Address, blockNumber: BigInt): Option[Account] = branch match {
case BestBranchSubset(_, tipBlockNumber) =>
if (blockNumber <= tipBlockNumber)
getAccountMpt(blockNumber).flatMap(_.get(address))
else
None
case EmptyBranch => None
}

/** Allows to query for a block based on it's number
*
* @param number Block number
Expand All @@ -160,6 +174,15 @@ class BlockchainReader(
*/
private def getHashByBlockNumber(number: BigInt): Option[ByteString] =
blockNumberMappingStorage.get(number)

private def getAccountMpt(blockNumber: BigInt): Option[MerklePatriciaTrie[Address, Account]] =
getBlockHeaderByNumber(blockNumber).map { bh =>
val storage = stateStorage.getBackingStorage(blockNumber)
MerklePatriciaTrie[Address, Account](
rootHash = bh.stateRoot.toArray,
source = storage
)
}
}

object BlockchainReader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class EthProofService(
for {
blockNumber <- resolveBlock(block).map(_.block.number)
account <- Either.fromOption(
blockchain.getAccount(address, blockNumber),
blockchainReader.getAccount(blockchainReader.getBestBranch(), address, blockNumber),
noAccount(address, blockNumber)
)
accountProof <- Either.fromOption(
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/io/iohk/ethereum/jsonrpc/EthUserService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ class EthUserService(
Task {
resolveBlock(blockParam)
.map { case ResolvedBlock(block, _) =>
blockchain
.getAccount(address, block.header.number)
blockchainReader
.getAccount(blockchainReader.getBestBranch(), address, block.header.number)
.getOrElse(Account.empty(blockchainConfig.accountStartNonce))
}
.map(makeResponse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class PersonalService(
}

private def getCurrentAccount(address: Address): Option[Account] =
blockchain.getAccount(address, blockchainReader.getBestBlockNumber())
blockchainReader.getAccount(blockchainReader.getBestBranch(), address, blockchainReader.getBestBlockNumber())

private def getMessageToSign(message: ByteString) = {
val prefixed: Array[Byte] =
Expand Down
12 changes: 10 additions & 2 deletions src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,11 @@ class TestService(
} else {
val accountBatch: Seq[(ByteString, Address)] = accountHashWithAdresses.view
.dropWhile { case (hash, _) => UInt256(hash) < UInt256(request.parameters.addressHash) }
.filter { case (_, address) => blockchain.getAccount(address, blockOpt.get.header.number).isDefined }
.filter { case (_, address) =>
blockchainReader
.getAccount(blockchainReader.getBestBranch(), address, blockOpt.get.header.number)
.isDefined
}
.take(request.parameters.maxResults + 1)
.to(Seq)

Expand Down Expand Up @@ -414,7 +418,11 @@ class TestService(

(for {
block <- blockOpt.toRight(StorageRangeResponse(complete = false, Map.empty, None))
accountOpt = blockchain.getAccount(Address(request.parameters.address), block.header.number)
accountOpt = blockchainReader.getAccount(
blockchainReader.getBestBranch(),
Address(request.parameters.address),
block.header.number
)
account <- accountOpt.toRight(StorageRangeResponse(complete = false, Map.empty, None))

} yield {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ object StateSyncUtils extends EphemBlockchainTestSetup {
def checkAllDataExists(
nodeData: List[MptNodeData],
blockchain: Blockchain,
blockchainReader: BlockchainReader,
evmCodeStorage: EvmCodeStorage,
blNumber: BigInt
): Boolean = {
Expand All @@ -108,7 +109,8 @@ object StateSyncUtils extends EphemBlockchainTestSetup {
true
} else {
val dataToCheck = remaining.head
val address = blockchain.getAccount(dataToCheck.accountAddress, blNumber)
val address =
blockchainReader.getAccount(blockchainReader.getBestBranch(), dataToCheck.accountAddress, blNumber)
val code = address.flatMap(a => evmCodeStorage.get(a.codeHash))

val storageCorrect = dataToCheck.accountStorage.forall { case (key, value) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class SyncStateSchedulerSpec
"SyncStateScheduler" should "sync with mptTrie with one account (1 leaf node)" in new TestSetup {
val prov = getTrieProvider
val worldHash = prov.buildWorld(Seq(MptNodeData(Address(1), None, Seq(), 20)))
val (syncStateScheduler, _, _, schedulerDb) = buildScheduler()
val (syncStateScheduler, _, _, _, schedulerDb) = buildScheduler()
val initialState = syncStateScheduler.initState(worldHash).get
val (missingNodes, newState) = syncStateScheduler.getMissingNodes(initialState, 1)
val responses = prov.getNodes(missingNodes)
Expand All @@ -57,7 +57,7 @@ class SyncStateSchedulerSpec
val worldHash = prov.buildWorld(
Seq(MptNodeData(Address(1), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20))
)
val (syncStateScheduler, _, _, schedulerDb) = buildScheduler()
val (syncStateScheduler, _, _, _, schedulerDb) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val state1 = exchangeSingleNode(initState, syncStateScheduler, prov).value
val state2 = exchangeSingleNode(state1, syncStateScheduler, prov).value
Expand All @@ -80,7 +80,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20)
)
)
val (syncStateScheduler, _, _, _) = buildScheduler()
val (syncStateScheduler, _, _, _, _) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val stateAfterExchange = exchangeAllNodes(initState, syncStateScheduler, prov)
assert(stateAfterExchange.numberOfPendingRequests == 0)
Expand Down Expand Up @@ -112,7 +112,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3, 4)), Seq((2, 2)), 20)
)
)
val (syncStateScheduler, _, _, schedulerDb) = buildScheduler()
val (syncStateScheduler, _, _, _, schedulerDb) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
assert(schedulerDb.dataSource.storage.isEmpty)
val state1 = exchangeSingleNode(initState, syncStateScheduler, prov).value
Expand Down Expand Up @@ -156,7 +156,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20)
)
)
val (syncStateScheduler, _, _, schedulerDb) = buildScheduler()
val (syncStateScheduler, _, _, _, schedulerDb) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val state1 = exchangeSingleNode(initState, syncStateScheduler, prov).value
val (allMissingNodes1, state2) = syncStateScheduler.getAllMissingNodes(state1)
Expand Down Expand Up @@ -188,7 +188,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20)
)
)
val (syncStateScheduler, _, _, _) = buildScheduler()
val (syncStateScheduler, _, _, _, _) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val (_, state1) = syncStateScheduler.getMissingNodes(initState, 1)
val result1 = syncStateScheduler.processResponse(state1, SyncResponse(ByteString(1), ByteString(2)))
Expand All @@ -205,7 +205,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20)
)
)
val (syncStateScheduler, _, _, _) = buildScheduler()
val (syncStateScheduler, _, _, _, _) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val (firstMissing, state1) = syncStateScheduler.getMissingNodes(initState, 1)
val firstMissingResponse = prov.getNodes(firstMissing)
Expand All @@ -227,7 +227,7 @@ class SyncStateSchedulerSpec
MptNodeData(Address(2), Some(ByteString(1, 2, 3)), Seq((1, 1)), 20)
)
)
val (syncStateScheduler, _, _, _) = buildScheduler()
val (syncStateScheduler, _, _, _, _) = buildScheduler()
val initState = syncStateScheduler.initState(worldHash).get
val (firstMissing, state1) = syncStateScheduler.getMissingNodes(initState, 1)
val firstMissingResponse = prov.getNodes(firstMissing)
Expand All @@ -248,9 +248,11 @@ class SyncStateSchedulerSpec
forAll(nodeDataGen) { nodeData =>
val prov = getTrieProvider
val worldHash = prov.buildWorld(nodeData)
val (scheduler, schedulerBlockchain, schedulerBlockchainWriter, allStorages) = buildScheduler()
val (scheduler, schedulerBlockchain, schedulerBlockchainWriter, schedulerBlockchainReader, allStorages) =
buildScheduler()
val header = Fixtures.Blocks.ValidBlock.header.copy(stateRoot = worldHash, number = 1)
schedulerBlockchainWriter.storeBlockHeader(header).commit()
schedulerBlockchain.saveBestKnownBlocks(1)
var state = scheduler.initState(worldHash).get
while (state.activeRequest.nonEmpty) {
val (allMissingNodes1, state2) = scheduler.getAllMissingNodes(state)
Expand All @@ -263,7 +265,15 @@ class SyncStateSchedulerSpec
assert(finalState.memBatch.isEmpty)
assert(finalState.activeRequest.isEmpty)
assert(finalState.queue.isEmpty)
assert(checkAllDataExists(nodeData, schedulerBlockchain, allStorages.storages.evmCodeStorage, 1))
assert(
checkAllDataExists(
nodeData,
schedulerBlockchain,
schedulerBlockchainReader,
allStorages.storages.evmCodeStorage,
1
)
)
}
}

Expand Down Expand Up @@ -296,6 +306,7 @@ class SyncStateSchedulerSpec
SyncStateScheduler,
BlockchainImpl,
BlockchainWriter,
BlockchainReader,
EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages
) = {
val freshStorage = getNewStorages
Expand All @@ -314,6 +325,7 @@ class SyncStateSchedulerSpec
),
freshBlockchain,
freshBlockchainWriter,
freshBlockchainReader,
freshStorage
)
}
Expand Down
3 changes: 2 additions & 1 deletion src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
val headerWithAcc = validHeader.copy(stateRoot = ByteString(mptWithAcc.getRootHash))

blockchainWriter.storeBlockHeader(headerWithAcc).commit()
blockchain.saveBestKnownBlocks(headerWithAcc.number)

val retrievedAccount = blockchain.getAccount(address, headerWithAcc.number)
val retrievedAccount = blockchainReader.getAccount(blockchainReader.getBestBranch(), address, headerWithAcc.number)
retrievedAccount shouldEqual Some(account)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package io.iohk.ethereum.jsonrpc

import java.time.Duration

import akka.actor.ActorSystem
import akka.testkit.TestKit
import akka.testkit.TestProbe
import akka.util.ByteString

import monix.execution.Scheduler.Implicits.global

import scala.concurrent.duration.FiniteDuration
import scala.reflect.ClassTag

import com.miguno.akka.testing.VirtualTime
import org.bouncycastle.util.encoders.Hex
import org.scalamock.matchers.MatcherBase
Expand All @@ -21,14 +18,15 @@ import org.scalatest.concurrent.ScalaFutures
import org.scalatest.flatspec.AnyFlatSpecLike
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks

import io.iohk.ethereum.Fixtures
import io.iohk.ethereum.NormalPatience
import io.iohk.ethereum.Timeouts
import io.iohk.ethereum.WithActorSystemShutDown
import io.iohk.ethereum.blockchain.sync.StateSyncUtils.blockchainReader
import io.iohk.ethereum.crypto.ECDSASignature
import io.iohk.ethereum.domain.UInt256
import io.iohk.ethereum.domain._
import io.iohk.ethereum.domain.branch.EmptyBranch
import io.iohk.ethereum.jsonrpc.JsonRpcError._
import io.iohk.ethereum.jsonrpc.PersonalService._
import io.iohk.ethereum.keystore.KeyStore
Expand Down Expand Up @@ -125,7 +123,7 @@ class PersonalServiceSpec
.returning(Right(wallet))

(blockchainReader.getBestBlockNumber _).expects().returning(1234)
(blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getAccount _).expects(*, address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getBestBlockNumber _).expects().returning(forkBlockNumbers.eip155BlockNumber - 1)

val req = SendTransactionWithPassphraseRequest(tx, passphrase)
Expand All @@ -146,7 +144,7 @@ class PersonalServiceSpec
.returning(Right(wallet))

(blockchainReader.getBestBlockNumber _).expects().returning(1234)
(blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getAccount _).expects(*, address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getBestBlockNumber _).expects().returning(forkBlockNumbers.eip155BlockNumber - 1)

val req = SendTransactionWithPassphraseRequest(tx, passphrase)
Expand Down Expand Up @@ -179,7 +177,7 @@ class PersonalServiceSpec
personal.unlockAccount(UnlockAccountRequest(address, passphrase, None)).runSyncUnsafe(taskTimeout)

(blockchainReader.getBestBlockNumber _).expects().returning(1234)
(blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getAccount _).expects(*, address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getBestBlockNumber _).expects().returning(forkBlockNumbers.eip155BlockNumber - 1)

val req = SendTransactionRequest(tx)
Expand Down Expand Up @@ -338,7 +336,7 @@ class PersonalServiceSpec
.returning(Right(wallet))

(blockchainReader.getBestBlockNumber _).expects().returning(1234)
(blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getAccount _).expects(*, address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getBestBlockNumber _).expects().returning(forkBlockNumbers.eip155BlockNumber - 1)

val req = SendTransactionWithPassphraseRequest(tx, passphrase)
Expand All @@ -357,7 +355,7 @@ class PersonalServiceSpec
.returning(Right(wallet))

(blockchainReader.getBestBlockNumber _).expects().returning(1234)
(blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
(blockchainReader.getAccount _).expects(*, address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue)))
new Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body)
(blockchainReader.getBestBlockNumber _).expects().returning(forkBlockNumbers.eip155BlockNumber)

Expand Down Expand Up @@ -451,6 +449,7 @@ class PersonalServiceSpec

val txPool: TestProbe = TestProbe()
val blockchainReader: BlockchainReader = mock[BlockchainReader]
(blockchainReader.getBestBranch _).expects().returning(EmptyBranch).anyNumberOfTimes()
val blockchain: BlockchainImpl = mock[BlockchainImpl]
val personal =
new PersonalService(
Expand Down
Loading

0 comments on commit 0c7ddd0

Please sign in to comment.