Skip to content

Commit

Permalink
[ETCM-533] fix comments
Browse files Browse the repository at this point in the history
  • Loading branch information
AnastasiiaL authored and bsuieric committed Jan 26, 2021
1 parent 6bcc444 commit 8416b01
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 28 deletions.
Expand Up @@ -2,7 +2,6 @@ package io.iohk.ethereum.txExecTest.util

import java.time.Clock
import java.util.concurrent.atomic.AtomicReference

import akka.actor.ActorSystem
import akka.util.ByteString
import com.typesafe.config.ConfigFactory
Expand All @@ -15,6 +14,7 @@ import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode}
import io.iohk.ethereum.db.storage.{AppStateStorage, StateStorage}
import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty
import io.iohk.ethereum.domain.{Blockchain, UInt256, _}
import io.iohk.ethereum.jsonrpc.ProofService.{StorageProof, StorageValueProof}
import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage}
import io.iohk.ethereum.mpt.MptNode
import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo
Expand Down Expand Up @@ -150,7 +150,7 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain {
rootHash: NodeHash,
position: BigInt,
ethCompatibleStorage: Boolean
): (BigInt, Seq[MptNode]) = (BigInt(0), Seq.empty)
): StorageProof = StorageValueProof(position)

override protected def getHashByBlockNumber(number: BigInt): Option[ByteString] = Some(genesisHash)

Expand Down
19 changes: 12 additions & 7 deletions src/main/scala/io/iohk/ethereum/domain/Blockchain.scala
@@ -1,7 +1,6 @@
package io.iohk.ethereum.domain

import java.util.concurrent.atomic.AtomicReference

import akka.util.ByteString
import cats.syntax.flatMap._
import cats.instances.option._
Expand All @@ -13,6 +12,7 @@ import io.iohk.ethereum.db.storage._
import io.iohk.ethereum.db.storage.pruning.PruningMode
import io.iohk.ethereum.domain
import io.iohk.ethereum.domain.BlockchainImpl.BestBlockLatestCheckpointNumbers
import io.iohk.ethereum.jsonrpc.ProofService.{StorageProof, StorageValueProof}
import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage}
import io.iohk.ethereum.mpt.{MerklePatriciaTrie, MptNode}
import io.iohk.ethereum.utils.{ByteStringUtils, Logger}
Expand Down Expand Up @@ -105,7 +105,7 @@ trait Blockchain {
rootHash: ByteString,
position: BigInt,
ethCompatibleStorage: Boolean
): (BigInt, Seq[MptNode])
): StorageProof

/**
* Returns the receipts based on a block hash
Expand Down Expand Up @@ -313,16 +313,21 @@ class BlockchainImpl(
rootHash: ByteString,
position: BigInt,
ethCompatibleStorage: Boolean
): (BigInt, Seq[MptNode]) = {
val defaultValue = BigInt(0)
): StorageProof = {
val storage: MptStorage = stateStorage.getBackingStorage(0)
val mpt: MerklePatriciaTrie[BigInt, BigInt] = {
if (ethCompatibleStorage) domain.EthereumUInt256Mpt.storageMpt(rootHash, storage)
else domain.ArbitraryIntegerMpt.storageMpt(rootHash, storage)
}
val value = mpt.get(position).getOrElse(defaultValue)
val proof = mpt.getProof(position).getOrElse(Seq.empty)
(value, proof)
val value = mpt.get(position)
val proof = mpt.getProof(position)

(value, proof) match {
case (Some(value), Some(proof)) => StorageValueProof(position, value, proof)
case (None, Some(proof)) => StorageValueProof(position, proof = proof)
case (Some(value), None) => StorageValueProof(position, value)
case (None, None) => StorageValueProof(position)
}
}

private def persistBestBlocksData(): Unit = {
Expand Down
38 changes: 21 additions & 17 deletions src/main/scala/io/iohk/ethereum/jsonrpc/EthProofService.scala
Expand Up @@ -4,13 +4,7 @@ import akka.util.ByteString
import cats.implicits._
import io.iohk.ethereum.consensus.blocks.BlockGenerator
import io.iohk.ethereum.domain.{Account, Address, Block, Blockchain, UInt256}
import io.iohk.ethereum.jsonrpc.ProofService.{
GetProofRequest,
GetProofResponse,
ProofAccount,
StorageProof,
StorageProofKey
}
import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, GetProofResponse, ProofAccount, StorageProof, StorageProofKey, StorageValueProof}
import io.iohk.ethereum.mpt.{MptNode, MptTraversals}
import monix.eval.Task

Expand All @@ -30,21 +24,33 @@ object ProofService {

case class GetProofResponse(proofAccount: ProofAccount)

/** The key used to get the storage slot in its account tree */
case class StorageProofKey(v: BigInt) extends AnyVal

trait StorageProof {
val key: StorageProofKey
val value: BigInt
val proof: Seq[ByteString]
}
/**
* Object proving a relationship of a storage value to an account's storageHash
*
* @param key storage proof key
* @param value the value of the storage slot in its account tree
* @param proof the set of node values needed to traverse a patricia merkle tree (from root to leaf) to retrieve a value
*/
case class StorageProof(
case class StorageValueProof(
key: StorageProofKey,
value: BigInt,
proof: Seq[ByteString]
)
proof: Seq[ByteString]) extends StorageProof

object StorageValueProof {
def apply(key: BigInt, value: BigInt = BigInt(0), proof: => Seq[MptNode] = Seq.empty[MptNode]): StorageValueProof =
new StorageValueProof(StorageProofKey(key), value, proof.map(asRlpSerializedNode))

def asRlpSerializedNode(node: MptNode): ByteString =
ByteString(MptTraversals.encodeNode(node))
}

/** The key used to get the storage slot in its account tree */
case class StorageProofKey(v: BigInt) extends AnyVal

/**
* The merkle proofs of the specified account connecting them to the blockhash of the block specified.
Expand Down Expand Up @@ -143,7 +149,7 @@ class EthProofService(blockchain: Blockchain, blockGenerator: BlockGenerator, et
blockchain.getAccountProof(address, blockNumber).map(_.map(asRlpSerializedNode)),
noAccountProof(address, blockNumber)
)
storageProof <- Either.right(getStorageProof(account, storageKeys))
storageProof = getStorageProof(account, storageKeys)
} yield ProofAccount(account, accountProof, storageProof, address)
}

Expand All @@ -158,9 +164,7 @@ class EthProofService(blockchain: Blockchain, blockGenerator: BlockGenerator, et
rootHash = account.storageRoot,
position = storageKey.v,
ethCompatibleStorage = ethCompatibleStorage
) match {
case (value, proof) => StorageProof(storageKey, value, proof.map(asRlpSerializedNode))
}
)
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala
Expand Up @@ -165,6 +165,24 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh
}
}

it should "return proof for non-existent account" in new EphemBlockchainTestSetup {
val emptyMpt = MerklePatriciaTrie[Address, Account](
storagesInstance.storages.stateStorage.getBackingStorage(0)
)
val mptWithAcc = emptyMpt.put(Address(42), Account.empty(UInt256(7)))

val headerWithAcc = Fixtures.Blocks.ValidBlock.header.copy(stateRoot = ByteString(mptWithAcc.getRootHash))

blockchain.storeBlockHeader(headerWithAcc).commit()

val wrongAddress = Address(666)
val retrievedAccountProofWrong = blockchain.getAccountProof(wrongAddress, headerWithAcc.number)
//the account doesn't exist, so we can't retrieve it, but we do receive a proof of non-existence with a full path of nodes that we iterated
retrievedAccountProofWrong.isDefined shouldBe true
retrievedAccountProofWrong.size shouldBe 1
mptWithAcc.get(wrongAddress) shouldBe None
}

it should "return correct best block number after applying and rollbacking blocks" in new TestSetup {
forAll(intGen(min = 1: Int, max = maxNumberBlocksToImport)) { numberBlocksToImport =>
val testSetup = newSetup()
Expand Down
Expand Up @@ -18,7 +18,7 @@ import io.iohk.ethereum.jsonrpc.ProofService.{
GetProofRequest,
GetProofResponse,
ProofAccount,
StorageProof,
StorageValueProof,
StorageProofKey
}
import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.{
Expand Down Expand Up @@ -835,7 +835,7 @@ class JsonRpcControllerEthSpec
nonce = 0,
storageHash = ByteString(Hex.decode("1a2b3c")),
storageProof = Seq(
StorageProof(
StorageValueProof(
key = StorageProofKey(42),
value = BigInt(2000),
proof = Seq(
Expand Down
Expand Up @@ -573,6 +573,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks
val proof: Option[Vector[MptNode]] = trie.getProof(key4)
// then
assert(proof.isDefined)
assert(proof.get.nonEmpty)
}

test("getProof returns valid proof for existing key") {
Expand Down

0 comments on commit 8416b01

Please sign in to comment.