Skip to content

Commit 00cb050

Browse files
Igor Grahovacdzajkowski
authored andcommitted
ETCM-697: Added TestEthBlockServiceWrapper to accommodate response according to eth spec for retesteth. Fixed genesis loading for regular node
1 parent 9c52217 commit 00cb050

File tree

9 files changed

+181
-29
lines changed

9 files changed

+181
-29
lines changed

src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package io.iohk.ethereum.blockchain.data
22

33
import java.io.FileNotFoundException
4-
54
import akka.util.ByteString
6-
import io.iohk.ethereum.blockchain.data.GenesisDataLoader.JsonSerializers.ByteStringJsonSerializer
5+
import io.iohk.ethereum.blockchain.data.GenesisDataLoader.JsonSerializers.{
6+
ByteStringJsonSerializer,
7+
UInt256JsonSerializer
8+
}
79
import io.iohk.ethereum.db.storage.StateStorage.GenesisDataLoad
810
import io.iohk.ethereum.rlp.RLPList
911
import io.iohk.ethereum.utils.BlockchainConfig
1012
import io.iohk.ethereum.utils.Logger
1113
import io.iohk.ethereum.{crypto, rlp}
1214
import io.iohk.ethereum.domain._
15+
import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits
1316
import io.iohk.ethereum.mpt.MerklePatriciaTrie
1417
import io.iohk.ethereum.rlp.RLPImplicits._
1518
import org.json4s.{CustomSerializer, DefaultFormats, Formats, JString, JValue}
@@ -75,7 +78,7 @@ class GenesisDataLoader(blockchain: Blockchain, blockchainConfig: BlockchainConf
7578

7679
private def loadGenesisData(genesisJson: String): Try[Unit] = {
7780
import org.json4s.native.JsonMethods.parse
78-
implicit val formats: Formats = DefaultFormats + ByteStringJsonSerializer
81+
implicit val formats: Formats = DefaultFormats + ByteStringJsonSerializer + UInt256JsonSerializer
7982
for {
8083
genesisData <- Try(parse(genesisJson).extract[GenesisData])
8184
_ <- loadGenesisData(genesisData)
@@ -96,7 +99,11 @@ class GenesisDataLoader(blockchain: Blockchain, blockchainConfig: BlockchainConf
9699
val stateRoot = mpt
97100
.put(
98101
crypto.kec256(Hex.decode(paddedAddress)),
99-
Account(nonce = genesisAccount.nonce, balance = genesisAccount.balance)
102+
Account(
103+
nonce = genesisAccount.nonce
104+
.getOrElse(blockchainConfig.accountStartNonce),
105+
balance = genesisAccount.balance
106+
)
100107
)
101108
.getRootHash
102109
stateRoot
@@ -178,5 +185,23 @@ object GenesisDataLoader {
178185
)
179186
)
180187

188+
def deserializeUint256String(jv: JValue): UInt256 = jv match {
189+
case JString(s) =>
190+
Try(UInt256(BigInt(1, Implicits.decode(s)))) match {
191+
case Failure(_) => throw new RuntimeException("Cannot parse hex string: " + s)
192+
case Success(value) => value
193+
}
194+
case other => throw new RuntimeException("Expected hex string, but got: " + other)
195+
}
196+
197+
object UInt256JsonSerializer
198+
extends CustomSerializer[UInt256](formats =>
199+
(
200+
{ case jv => deserializeUint256String(jv) },
201+
PartialFunction.empty
202+
)
203+
)
181204
}
182205
}
206+
207+
object Implicits extends JsonMethodsImplicits

src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ case class PrecompiledAccountConfig(name: String)
88
case class GenesisAccount(
99
precompiled: Option[PrecompiledAccountConfig],
1010
balance: UInt256,
11-
code: ByteString,
12-
nonce: UInt256,
13-
storage: Map[UInt256, UInt256]
11+
code: Option[ByteString],
12+
nonce: Option[UInt256],
13+
storage: Option[Map[UInt256, UInt256]]
1414
)
1515

1616
case class GenesisData(

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,52 @@ import io.iohk.ethereum.utils.ByteStringUtils
99

1010
case class CheckpointResponse(signatures: Seq[ECDSASignature], signers: Seq[ByteString])
1111

12+
trait BaseBlockResponse {
13+
def number: BigInt
14+
def hash: Option[ByteString]
15+
def mixHash: Option[ByteString]
16+
def parentHash: ByteString
17+
def nonce: Option[ByteString]
18+
def sha3Uncles: ByteString
19+
def logsBloom: ByteString
20+
def transactionsRoot: ByteString
21+
def stateRoot: ByteString
22+
def receiptsRoot: ByteString
23+
def miner: Option[ByteString]
24+
def difficulty: BigInt
25+
def totalDifficulty: Option[BigInt]
26+
def extraData: ByteString
27+
def size: BigInt
28+
def gasLimit: BigInt
29+
def gasUsed: BigInt
30+
def timestamp: BigInt
31+
def transactions: Either[Seq[ByteString], Seq[TransactionResponse]]
32+
def uncles: Seq[ByteString]
33+
}
34+
35+
case class EthBlockResponse(
36+
number: BigInt,
37+
hash: Option[ByteString],
38+
mixHash: Option[ByteString],
39+
parentHash: ByteString,
40+
nonce: Option[ByteString],
41+
sha3Uncles: ByteString,
42+
logsBloom: ByteString,
43+
transactionsRoot: ByteString,
44+
stateRoot: ByteString,
45+
receiptsRoot: ByteString,
46+
miner: Option[ByteString],
47+
difficulty: BigInt,
48+
totalDifficulty: Option[BigInt],
49+
extraData: ByteString,
50+
size: BigInt,
51+
gasLimit: BigInt,
52+
gasUsed: BigInt,
53+
timestamp: BigInt,
54+
transactions: Either[Seq[ByteString], Seq[TransactionResponse]],
55+
uncles: Seq[ByteString]
56+
) extends BaseBlockResponse
57+
1258
//scalastyle:off method.length
1359
case class BlockResponse(
1460
number: BigInt,
@@ -36,7 +82,7 @@ case class BlockResponse(
3682
uncles: Seq[ByteString],
3783
signature: String,
3884
signer: String
39-
) {
85+
) extends BaseBlockResponse {
4086
val chainWeight: Option[ChainWeight] = for {
4187
lcn <- lastCheckpointNumber
4288
td <- totalDifficulty

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ object EthBlocksService {
1515
case class TxCountByBlockHashResponse(txsQuantity: Option[Int])
1616

1717
case class BlockByBlockHashRequest(blockHash: ByteString, fullTxs: Boolean)
18-
case class BlockByBlockHashResponse(blockResponse: Option[BlockResponse])
18+
case class BlockByBlockHashResponse(blockResponse: Option[BaseBlockResponse])
1919

2020
case class BlockByNumberRequest(block: BlockParam, fullTxs: Boolean)
21-
case class BlockByNumberResponse(blockResponse: Option[BlockResponse])
21+
case class BlockByNumberResponse(blockResponse: Option[BaseBlockResponse])
2222

2323
case class GetBlockTransactionCountByNumberRequest(block: BlockParam)
2424
case class GetBlockTransactionCountByNumberResponse(result: BigInt)
2525

2626
case class UncleByBlockHashAndIndexRequest(blockHash: ByteString, uncleIndex: BigInt)
27-
case class UncleByBlockHashAndIndexResponse(uncleBlockResponse: Option[BlockResponse])
27+
case class UncleByBlockHashAndIndexResponse(uncleBlockResponse: Option[BaseBlockResponse])
2828

2929
case class UncleByBlockNumberAndIndexRequest(block: BlockParam, uncleIndex: BigInt)
30-
case class UncleByBlockNumberAndIndexResponse(uncleBlockResponse: Option[BlockResponse])
30+
case class UncleByBlockNumberAndIndexResponse(uncleBlockResponse: Option[BaseBlockResponse])
3131

3232
case class GetUncleCountByBlockNumberRequest(block: BlockParam)
3333
case class GetUncleCountByBlockNumberResponse(result: BigInt)

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@ object TestJsonMethodsImplicits extends JsonMethodsImplicits {
2121
private def extractAccount(accountJson: JValue): Either[JsonRpcError, GenesisAccount] =
2222
for {
2323
storageObject <- Try((accountJson \ "storage").extract[JObject]).toEither.left.map(e =>
24-
InvalidParams(e.toString())
24+
InvalidParams(e.toString)
2525
)
2626
storage <- storageObject.obj.traverse {
2727
case (key, JString(value)) =>
28-
Try(UInt256(decode(key)) -> UInt256(decode(value))).toEither.left.map(e => InvalidParams(e.toString()))
28+
Try(UInt256(decode(key)) -> UInt256(decode(value))).toEither.left.map(e => InvalidParams(e.toString))
2929
case _ => Left(InvalidParams())
3030
}
3131
balance = UInt256(decode((accountJson \ "balance").extract[String]))
32-
code = ByteString(decode((accountJson \ "code").extract[String]))
33-
nonce = UInt256(decode((accountJson \ "nonce").extract[String]))
32+
code = Some(ByteString(decode((accountJson \ "code").extract[String])))
33+
nonce = Some(UInt256(decode((accountJson \ "nonce").extract[String])))
3434
} yield GenesisAccount(
3535
None,
3636
balance,
3737
code,
3838
nonce,
39-
storage.toMap
39+
Some(storage.toMap)
4040
)
4141

4242
private def extractAccounts(accountsJson: JValue): Either[JsonRpcError, Map[ByteString, GenesisAccount]] =

src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import io.iohk.ethereum.network.p2p.EthereumMessageDecoder
2828
import io.iohk.ethereum.network.rlpx.AuthHandshaker
2929
import io.iohk.ethereum.network.{PeerManagerActor, ServerActor, _}
3030
import io.iohk.ethereum.ommers.OmmersPool
31-
import io.iohk.ethereum.testmode.{TestLedgerBuilder, TestmodeConsensusBuilder}
31+
import io.iohk.ethereum.testmode.{TestEthBlockServiceWrapper, TestLedgerBuilder, TestmodeConsensusBuilder}
3232
import io.iohk.ethereum.transactions.{PendingTransactionsManager, TransactionHistoryService}
3333
import io.iohk.ethereum.utils.Config.SyncConfig
3434
import io.iohk.ethereum.utils._
@@ -367,6 +367,11 @@ trait TestServiceBuilder {
367367
new TestService(blockchain, pendingTransactionsManager, consensusConfig, consensus, testLedgerWrapper)(scheduler)
368368
}
369369

370+
trait TestEthBlockServiceBuilder extends EthBlocksServiceBuilder {
371+
self: BlockchainBuilder with TestLedgerBuilder =>
372+
override lazy val ethBlocksService = new TestEthBlockServiceWrapper(blockchain, ledger)
373+
}
374+
370375
trait EthProofServiceBuilder {
371376
self: StorageBuilder with BlockchainBuilder with BlockchainConfigBuilder with ConsensusBuilder =>
372377

src/main/scala/io/iohk/ethereum/nodebuilder/StdNode.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,9 @@ abstract class BaseNode extends Node {
104104
}
105105

106106
class StdNode extends BaseNode with StdLedgerBuilder with StdConsensusBuilder
107-
class TestNode extends BaseNode with TestLedgerBuilder with TestmodeConsensusBuilder with TestServiceBuilder
107+
class TestNode
108+
extends BaseNode
109+
with TestLedgerBuilder
110+
with TestmodeConsensusBuilder
111+
with TestServiceBuilder
112+
with TestEthBlockServiceBuilder
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package io.iohk.ethereum.testmode
2+
3+
import io.iohk.ethereum.domain.Blockchain
4+
import io.iohk.ethereum.jsonrpc.EthBlocksService.{BlockByBlockHashResponse, BlockByNumberResponse}
5+
import io.iohk.ethereum.jsonrpc.{BaseBlockResponse, EthBlockResponse, EthBlocksService, ServiceResponse}
6+
import io.iohk.ethereum.ledger.Ledger
7+
import io.iohk.ethereum.utils.Logger
8+
9+
class TestEthBlockServiceWrapper(blockchain: Blockchain, ledger: Ledger)
10+
extends EthBlocksService(blockchain, ledger)
11+
with Logger {
12+
13+
/**
14+
* Implements the eth_getBlockByHash method that fetches a requested block.
15+
*
16+
* @param request with the hash of the block requested
17+
* @return the block requested or None if the client doesn't have the block
18+
*/
19+
override def getByBlockHash(
20+
request: EthBlocksService.BlockByBlockHashRequest
21+
): ServiceResponse[EthBlocksService.BlockByBlockHashResponse] = super
22+
.getByBlockHash(request)
23+
.map(
24+
_.map(blockByBlockResponse =>
25+
BlockByBlockHashResponse(
26+
blockByBlockResponse.blockResponse.map(response => toEthResponse(response))
27+
)
28+
)
29+
)
30+
31+
/**
32+
* Implements the eth_getBlockByNumber method that fetches a requested block.
33+
*
34+
* @param request with the block requested (by it's number or by tag)
35+
* @return the block requested or None if the client doesn't have the block
36+
*/
37+
override def getBlockByNumber(
38+
request: EthBlocksService.BlockByNumberRequest
39+
): ServiceResponse[EthBlocksService.BlockByNumberResponse] = super
40+
.getBlockByNumber(request)
41+
.map(
42+
_.map(blockByBlockResponse =>
43+
BlockByNumberResponse(
44+
blockByBlockResponse.blockResponse.map(response => toEthResponse(response))
45+
)
46+
)
47+
)
48+
49+
private def toEthResponse(response: BaseBlockResponse) = EthBlockResponse(
50+
response.number,
51+
response.hash,
52+
response.mixHash,
53+
response.parentHash,
54+
response.nonce,
55+
response.sha3Uncles,
56+
response.logsBloom,
57+
response.transactionsRoot,
58+
response.stateRoot,
59+
response.receiptsRoot,
60+
response.miner,
61+
response.difficulty,
62+
response.totalDifficulty,
63+
response.extraData,
64+
response.size,
65+
response.gasLimit,
66+
response.gasUsed,
67+
response.timestamp,
68+
response.transactions,
69+
response.uncles
70+
)
71+
}

src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class EthBlocksServiceSpec
8383
response.blockResponse shouldBe Some(
8484
BlockResponse(blockToRequest, fullTxs = true, weight = Some(blockWeight))
8585
)
86-
response.blockResponse.get.chainWeight shouldBe Some(blockWeight)
86+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(blockWeight)
8787
response.blockResponse.get.transactions.toOption shouldBe Some(stxResponses)
8888
}
8989

@@ -98,7 +98,7 @@ class EthBlocksServiceSpec
9898
}
9999

100100
response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true))
101-
response.blockResponse.get.chainWeight shouldBe None
101+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe None
102102
response.blockResponse.get.transactions.toOption shouldBe Some(stxResponses)
103103
}
104104

@@ -115,7 +115,7 @@ class EthBlocksServiceSpec
115115
response.blockResponse shouldBe Some(
116116
BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))
117117
)
118-
response.blockResponse.get.chainWeight shouldBe Some(blockWeight)
118+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(blockWeight)
119119
response.blockResponse.get.transactions.left.toOption shouldBe Some(blockToRequest.body.transactionList.map(_.hash))
120120
}
121121

@@ -178,7 +178,7 @@ class EthBlocksServiceSpec
178178
response.blockResponse shouldBe Some(
179179
BlockResponse(blockToRequest, fullTxs = true, weight = Some(blockWeight))
180180
)
181-
response.blockResponse.get.chainWeight shouldBe Some(blockWeight)
181+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(blockWeight)
182182
response.blockResponse.get.transactions.toOption shouldBe Some(stxResponses)
183183
}
184184

@@ -194,7 +194,7 @@ class EthBlocksServiceSpec
194194
}
195195

196196
response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true))
197-
response.blockResponse.get.chainWeight shouldBe None
197+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe None
198198
response.blockResponse.get.transactions.toOption shouldBe Some(stxResponses)
199199
}
200200

@@ -212,7 +212,7 @@ class EthBlocksServiceSpec
212212
response.blockResponse shouldBe Some(
213213
BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))
214214
)
215-
response.blockResponse.get.chainWeight shouldBe Some(blockWeight)
215+
response.blockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(blockWeight)
216216
response.blockResponse.get.transactions.left.toOption shouldBe Some(blockToRequest.body.transactionList.map(_.hash))
217217
}
218218

@@ -289,7 +289,7 @@ class EthBlocksServiceSpec
289289
val response = ethBlocksService.getUncleByBlockHashAndIndex(request).runSyncUnsafe(Duration.Inf).toOption.get
290290

291291
response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, None, pendingBlock = false))
292-
response.uncleBlockResponse.get.chainWeight shouldBe None
292+
response.uncleBlockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe None
293293
response.uncleBlockResponse.get.transactions shouldBe Left(Nil)
294294
response.uncleBlockResponse.get.uncles shouldBe Nil
295295
}
@@ -305,7 +305,7 @@ class EthBlocksServiceSpec
305305
val response = ethBlocksService.getUncleByBlockHashAndIndex(request).runSyncUnsafe(Duration.Inf).toOption.get
306306

307307
response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleWeight), pendingBlock = false))
308-
response.uncleBlockResponse.get.chainWeight shouldBe Some(uncleWeight)
308+
response.uncleBlockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(uncleWeight)
309309
response.uncleBlockResponse.get.transactions shouldBe Left(Nil)
310310
response.uncleBlockResponse.get.uncles shouldBe Nil
311311
}
@@ -363,7 +363,7 @@ class EthBlocksServiceSpec
363363
val response = ethBlocksService.getUncleByBlockNumberAndIndex(request).runSyncUnsafe(Duration.Inf).toOption.get
364364

365365
response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, None, pendingBlock = false))
366-
response.uncleBlockResponse.get.chainWeight shouldBe None
366+
response.uncleBlockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe None
367367
response.uncleBlockResponse.get.transactions shouldBe Left(Nil)
368368
response.uncleBlockResponse.get.uncles shouldBe Nil
369369
}
@@ -380,7 +380,7 @@ class EthBlocksServiceSpec
380380
val response = ethBlocksService.getUncleByBlockNumberAndIndex(request).runSyncUnsafe(Duration.Inf).toOption.get
381381

382382
response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleWeight), pendingBlock = false))
383-
response.uncleBlockResponse.get.chainWeight shouldBe Some(uncleWeight)
383+
response.uncleBlockResponse.get.asInstanceOf[BlockResponse].chainWeight shouldBe Some(uncleWeight)
384384
response.uncleBlockResponse.get.transactions shouldBe Left(Nil)
385385
response.uncleBlockResponse.get.uncles shouldBe Nil
386386
}

0 commit comments

Comments
 (0)