Skip to content

Commit 49b8a81

Browse files
committed
[ETCM-79] checkpointing QA JRC
1 parent effa2d1 commit 49b8a81

File tree

12 files changed

+514
-50
lines changed

12 files changed

+514
-50
lines changed

insomnia_workspace.json

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,102 @@
139139
"metaSortKey": -1600249374160,
140140
"_type": "request_group"
141141
},
142+
{
143+
"_id": "req_3ae9151dec5b4046b06fdb3408e9ab1f",
144+
"authentication": {},
145+
"body": {
146+
"mimeType": "application/json",
147+
"text": "{\n\t\"jsonrpc\": \"2.0\",\n\t\"id\": 1,\n\t\"method\": \"qa_generateCheckpoint\",\n\t\"params\": [\t\t[\"0x926db397ed35bedee660fe5bf6879679fa71f1fe8c27823f7f6a1e5d96a49b94\"], \"0xe160bdd7664e1b921612a4ed225321bdf3b8f70beb6b968c7a423d6022e39e16\"\n\t]\n}"
148+
},
149+
"created": 1572007151716,
150+
"description": "",
151+
"headers": [
152+
{
153+
"id": "pair_6f2ea2de85ee4eabbbd25bde888e9dc1",
154+
"name": "Content-Type",
155+
"value": "application/json"
156+
}
157+
],
158+
"isPrivate": false,
159+
"metaSortKey": -1566535778023.25,
160+
"method": "POST",
161+
"modified": 1572263390995,
162+
"name": "qa_generateCheckpoint",
163+
"parameters": [],
164+
"parentId": "fld_2b54cbb84e244284b3ef752c5f805376",
165+
"settingDisableRenderRequestBody": false,
166+
"settingEncodeUrl": true,
167+
"settingFollowRedirects": "global",
168+
"settingRebuildPath": true,
169+
"settingSendCookies": true,
170+
"settingStoreCookies": true,
171+
"url": "{{ node_url }}",
172+
"_type": "request"
173+
},
174+
{
175+
"_id": "req_e1287e4fcba348eea9d326bb208092c3",
176+
"authentication": {},
177+
"body": {
178+
"mimeType": "application/json",
179+
"text": "{\n\t\"jsonrpc\": \"2.0\",\n\t\"id\": 1,\n\t\"method\": \"qa_generateCheckpoint\",\n\t\"params\": [\t\t[\"0x926db397ed35bedee660fe5bf6879679fa71f1fe8c27823f7f6a1e5d96a49b94\"]\n\t]\n}"
180+
},
181+
"created": 1573216065706,
182+
"description": "",
183+
"headers": [
184+
{
185+
"id": "pair_6f2ea2de85ee4eabbbd25bde888e9dc1",
186+
"name": "Content-Type",
187+
"value": "application/json"
188+
}
189+
],
190+
"isPrivate": false,
191+
"metaSortKey": -1566394039140.875,
192+
"method": "POST",
193+
"modified": 1573216279799,
194+
"name": "qa_generateCheckpoint (for latest block)",
195+
"parameters": [],
196+
"parentId": "fld_2b54cbb84e244284b3ef752c5f805376",
197+
"settingDisableRenderRequestBody": false,
198+
"settingEncodeUrl": true,
199+
"settingFollowRedirects": "global",
200+
"settingRebuildPath": true,
201+
"settingSendCookies": true,
202+
"settingStoreCookies": true,
203+
"url": "{{ node_url }}",
204+
"_type": "request"
205+
},
206+
{
207+
"_id": "req_f2986c964bf74360878144213ca342a7",
208+
"authentication": {},
209+
"body": {
210+
"mimeType": "application/json",
211+
"text": "{\n\t\"jsonrpc\": \"2.0\",\n\t\"id\": 1,\n\t\"method\": \"qa_getFederationMembersInfo\",\n\t\"params\": []\n}"
212+
},
213+
"created": 1573042743181,
214+
"description": "",
215+
"headers": [
216+
{
217+
"id": "pair_ba5a5914f02a4b27b86a330054582828",
218+
"name": "Content-Type",
219+
"value": "application/json"
220+
}
221+
],
222+
"isPrivate": false,
223+
"metaSortKey": -1568046037126,
224+
"method": "POST",
225+
"modified": 1573042783130,
226+
"name": "qa_getFederationMembersInfo",
227+
"parameters": [],
228+
"parentId": "fld_2b54cbb84e244284b3ef752c5f805376",
229+
"settingDisableRenderRequestBody": false,
230+
"settingEncodeUrl": true,
231+
"settingFollowRedirects": "global",
232+
"settingRebuildPath": true,
233+
"settingSendCookies": true,
234+
"settingStoreCookies": true,
235+
"url": "{{ node_url }}",
236+
"_type": "request"
237+
},
142238
{
143239
"_id": "req_dd6e5c718f974407bb79fe3c953b7106",
144240
"parentId": "fld_72829b866f0441e184e0d1a2030f8220",
@@ -1124,4 +1220,4 @@
11241220
"_type": "environment"
11251221
}
11261222
]
1127-
}
1223+
}

src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ import scala.util.{Failure, Success, Try}
2323
object ScenarioSetup {
2424
val testContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4))
2525
val specificConfig = ethash.EthashConfig(Config.config)
26-
val fullConfig = FullConsensusConfig(ConsensusConfig(Config.config)(null), specificConfig)
27-
28-
def loadEthashConsensus(vm: VMImpl, blockchain: BlockchainImpl, blockchainConfig: BlockchainConfig, validators: ValidatorsExecutor): ethash.EthashConsensus = {
26+
val fullConfig = FullConsensusConfig(ConsensusConfig(Config.config), specificConfig)
27+
28+
def loadEthashConsensus(
29+
vm: VMImpl,
30+
blockchain: BlockchainImpl,
31+
blockchainConfig: BlockchainConfig,
32+
validators: ValidatorsExecutor
33+
): ethash.EthashConsensus = {
2934
val consensus = EthashConsensus(vm, blockchain, blockchainConfig, fullConfig, validators)
3035
consensus
3136
}
@@ -34,7 +39,6 @@ object ScenarioSetup {
3439
override val pruningMode: PruningMode = ArchivePruning
3540
}
3641

37-
3842
def getBlockchain: BlockchainImpl = {
3943
val storagesInstance = new EphemDataSourceComponent with Pruning with Storages.DefaultStorages
4044
BlockchainImpl(storagesInstance.storages)
@@ -61,21 +65,28 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) {
6165
val ledger =
6266
new LedgerImpl(
6367
blockchain,
64-
new BlockQueue(blockchain, 50, 50), blockchainConfig, consensus, ScenarioSetup.testContext)
68+
new BlockQueue(blockchain, 50, 50),
69+
blockchainConfig,
70+
consensus,
71+
ScenarioSetup.testContext
72+
)
6573

6674
def loadGenesis(): Block = {
6775
val genesisBlock = scenario.genesisRLP match {
6876
case Some(rlp) =>
6977
val block = rlp.toArray.toBlock
70-
assert(block.header == scenario.genesisBlockHeader.toBlockHeader,
71-
"decoded genesis block header did not match the expectation")
78+
assert(
79+
block.header == scenario.genesisBlockHeader.toBlockHeader,
80+
"decoded genesis block header did not match the expectation"
81+
)
7282
block
7383

7484
case None =>
7585
Block(scenario.genesisBlockHeader.toBlockHeader, BlockBody(Nil, Nil))
7686
}
7787

78-
blockchain.storeBlock(genesisBlock)
88+
blockchain
89+
.storeBlock(genesisBlock)
7990
.and(blockchain.storeReceipts(genesisBlock.header.hash, Nil))
8091
.and(blockchain.storeTotalDifficulty(genesisBlock.header.hash, genesisBlock.header.difficulty))
8192
.commit()
@@ -85,7 +96,8 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) {
8596

8697
val initialWorld: InMemoryWorldStateProxy = InMemoryWorldStateProxy.persistState(getWorldState(scenario.pre))
8798

88-
val finalWorld: Option[InMemoryWorldStateProxy] = scenario.postState.map(postState => InMemoryWorldStateProxy.persistState(getWorldState(postState)))
99+
val finalWorld: Option[InMemoryWorldStateProxy] =
100+
scenario.postState.map(postState => InMemoryWorldStateProxy.persistState(getWorldState(postState)))
89101

90102
def getBestBlock: Option[Block] = {
91103
val bestBlockNumber = blockchain.getBestBlockNumber()
@@ -123,23 +135,25 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) {
123135
case _ => (FrontierConfig, Validators.frontierValidators)
124136
}
125137

126-
private def withSkippedPoWValidationBlockchainConfig(network: String): (BlockchainConfig, ValidatorsExecutor) = network match {
127-
case "EIP150" => (Eip150Config, ValidatorsWithSkippedPoW.eip150Validators)
128-
case "Frontier" => (FrontierConfig, ValidatorsWithSkippedPoW.frontierValidators)
129-
case "Homestead" => (HomesteadConfig, ValidatorsWithSkippedPoW.homesteadValidators)
130-
case "FrontierToHomesteadAt5" => (FrontierToHomesteadAt5, ValidatorsWithSkippedPoW.frontierToHomesteadValidators)
131-
case "HomesteadToEIP150At5" => (HomesteadToEIP150At5, ValidatorsWithSkippedPoW.homesteadToEipValidators)
132-
case "EIP158" => (Eip158Config, ValidatorsWithSkippedPoW.eip158Validators)
133-
case "HomesteadToDaoAt5" => (HomesteadToDaoAt5, ValidatorsWithSkippedPoW.homesteadToDaoValidators)
134-
case "Byzantium" => (ByzantiumConfig, ValidatorsWithSkippedPoW.byzantiumValidators)
135-
case "Constantinople" => (ConstantinopleConfig, ValidatorsWithSkippedPoW.constantinopleValidators)
136-
case "EIP158ToByzantiumAt5" => (Eip158ToByzantiumAt5Config, ValidatorsWithSkippedPoW.eip158ToByzantiumValidators)
137-
case "ByzantiumToConstantinopleFixAt5" => (ByzantiumToConstantinopleAt5, ValidatorsWithSkippedPoW.byzantiumToConstantinopleAt5)
138-
case "ConstantinopleFix" => (ConstantinopleFixConfig, ValidatorsWithSkippedPoW.constantinopleFixValidators)
139-
case "Istanbul" => (IstanbulConfig, ValidatorsWithSkippedPoW.istanbulValidators)
140-
// Some default config, test will fail or be canceled
141-
case _ => (FrontierConfig, ValidatorsWithSkippedPoW.frontierValidators)
142-
}
138+
private def withSkippedPoWValidationBlockchainConfig(network: String): (BlockchainConfig, ValidatorsExecutor) =
139+
network match {
140+
case "EIP150" => (Eip150Config, ValidatorsWithSkippedPoW.eip150Validators)
141+
case "Frontier" => (FrontierConfig, ValidatorsWithSkippedPoW.frontierValidators)
142+
case "Homestead" => (HomesteadConfig, ValidatorsWithSkippedPoW.homesteadValidators)
143+
case "FrontierToHomesteadAt5" => (FrontierToHomesteadAt5, ValidatorsWithSkippedPoW.frontierToHomesteadValidators)
144+
case "HomesteadToEIP150At5" => (HomesteadToEIP150At5, ValidatorsWithSkippedPoW.homesteadToEipValidators)
145+
case "EIP158" => (Eip158Config, ValidatorsWithSkippedPoW.eip158Validators)
146+
case "HomesteadToDaoAt5" => (HomesteadToDaoAt5, ValidatorsWithSkippedPoW.homesteadToDaoValidators)
147+
case "Byzantium" => (ByzantiumConfig, ValidatorsWithSkippedPoW.byzantiumValidators)
148+
case "Constantinople" => (ConstantinopleConfig, ValidatorsWithSkippedPoW.constantinopleValidators)
149+
case "EIP158ToByzantiumAt5" => (Eip158ToByzantiumAt5Config, ValidatorsWithSkippedPoW.eip158ToByzantiumValidators)
150+
case "ByzantiumToConstantinopleFixAt5" =>
151+
(ByzantiumToConstantinopleAt5, ValidatorsWithSkippedPoW.byzantiumToConstantinopleAt5)
152+
case "ConstantinopleFix" => (ConstantinopleFixConfig, ValidatorsWithSkippedPoW.constantinopleFixValidators)
153+
case "Istanbul" => (IstanbulConfig, ValidatorsWithSkippedPoW.istanbulValidators)
154+
// Some default config, test will fail or be canceled
155+
case _ => (FrontierConfig, ValidatorsWithSkippedPoW.frontierValidators)
156+
}
143157

144158
private def decode(s: String): Array[Byte] = {
145159
val stripped = s.replaceFirst("^0x", "")
@@ -152,7 +166,7 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) {
152166
case Success(block) =>
153167
Some(block)
154168

155-
case Failure(ex) =>
169+
case Failure(ex) =>
156170
ex.printStackTrace()
157171
None
158172
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import akka.util.ByteString
44
import com.typesafe.config.{Config => TypesafeConfig}
55
import io.iohk.ethereum.consensus.validators.BlockHeaderValidator
66
import io.iohk.ethereum.domain.Address
7-
import io.iohk.ethereum.nodebuilder.ShutdownHookBuilder
87
import io.iohk.ethereum.utils.Logger
98

109
/**
@@ -59,7 +58,7 @@ object ConsensusConfig extends Logger {
5958
Protocol(protocol)
6059
}
6160

62-
def apply(mantisConfig: TypesafeConfig)(shutdownHook: ShutdownHookBuilder): ConsensusConfig = {
61+
def apply(mantisConfig: TypesafeConfig): ConsensusConfig = {
6362
val config = mantisConfig.getConfig(Keys.Consensus)
6463

6564
val protocol = readProtocol(config)
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package io.iohk.ethereum.consensus
22

3-
import io.iohk.ethereum.nodebuilder.ShutdownHookBuilder
43
import io.iohk.ethereum.utils.Config
54

6-
trait ConsensusConfigBuilder { self: ShutdownHookBuilder =>
7-
protected def buildConsensusConfig(): ConsensusConfig = ConsensusConfig(Config.config)(this)
5+
trait ConsensusConfigBuilder {
6+
protected def buildConsensusConfig(): ConsensusConfig = ConsensusConfig(Config.config)
87

98
lazy val consensusConfig: ConsensusConfig = buildConsensusConfig()
109
}

src/main/scala/io/iohk/ethereum/crypto/ECDSASignature.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ object ECDSASignature {
3737
None
3838
}
3939

40+
def sign(message: ByteString, prvKey: ByteString): ECDSASignature =
41+
sign(message.toArray, keyPairFromPrvKey(prvKey.toArray), None)
42+
4043
def sign(message: Array[Byte], keyPair: AsymmetricCipherKeyPair, chainId: Option[Byte] = None): ECDSASignature = {
4144
val signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest))
4245
signer.init(true, keyPair.getPrivate)

src/main/scala/io/iohk/ethereum/crypto/package.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ package object crypto {
7979
keyPairFromPrvKey(privateKey)
8080
}
8181

82+
def keyPairFromPrvKey(prvKeyBytes: ByteString): AsymmetricCipherKeyPair = {
83+
val privateKey = BigInt(1, prvKeyBytes.toArray)
84+
keyPairFromPrvKey(privateKey)
85+
}
86+
8287
def keyPairFromPrvKey(prvKey: BigInt): AsymmetricCipherKeyPair = {
8388
val publicKey = curve.getG.multiply(prvKey.bigInteger).normalize()
8489
new AsymmetricCipherKeyPair(

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import org.json4s.JsonDSL._
1111
import com.typesafe.config.{Config => TypesafeConfig}
1212
import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse}
1313
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
14+
import io.iohk.ethereum.jsonrpc.QAService.{
15+
GenerateCheckpointRequest,
16+
GenerateCheckpointResponse,
17+
GetFederationMembersInfoRequest,
18+
GetFederationMembersInfoResponse
19+
}
1420
import io.iohk.ethereum.jsonrpc.TestService._
1521
import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig
1622
import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig
@@ -350,6 +356,12 @@ class JsonRpcController(
350356
private def handleQARequest: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {
351357
case req @ JsonRpcRequest(_, "qa_mineBlocks", _, _) =>
352358
handle[QAService.MineBlocksRequest, QAService.MineBlocksResponse](qaService.mineBlocks, req)
359+
360+
case req @ JsonRpcRequest(_, "qa_generateCheckpoint", _, _) =>
361+
handle[GenerateCheckpointRequest, GenerateCheckpointResponse](qaService.generateCheckpoint, req)
362+
363+
case req @ JsonRpcRequest(_, "qa_getFederationMembersInfo", _, _) =>
364+
handle[GetFederationMembersInfoRequest, GetFederationMembersInfoResponse](qaService.getFederationMembersInfo, req)
353365
}
354366

355367
private def handleCheckpointingRequest: PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = {

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

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package io.iohk.ethereum.jsonrpc
22

3-
import io.iohk.ethereum.jsonrpc.JsonRpcController.Codec
3+
import akka.util.ByteString
4+
import io.iohk.ethereum.jsonrpc.JsonRpcController.JsonDecoder.NoParamsDecoder
5+
import io.iohk.ethereum.jsonrpc.JsonRpcController.{Codec, JsonEncoder}
46
import io.iohk.ethereum.jsonrpc.JsonRpcErrors.InvalidParams
5-
import io.iohk.ethereum.jsonrpc.QAService.{MineBlocksRequest, MineBlocksResponse}
7+
import io.iohk.ethereum.jsonrpc.QAService._
8+
import org.json4s.Extraction
69
import org.json4s.JsonAST._
710

811
object QAJsonMethodsImplicits extends JsonMethodsImplicits {
@@ -29,4 +32,36 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits {
2932
"message" -> t.message.fold[JValue](JNull)(JString)
3033
)
3134
}
35+
36+
implicit val qa_generateCheckpoint: Codec[GenerateCheckpointRequest, GenerateCheckpointResponse] =
37+
new Codec[GenerateCheckpointRequest, GenerateCheckpointResponse] {
38+
def decodeJson(params: Option[JArray]): Either[JsonRpcError, GenerateCheckpointRequest] = {
39+
params match {
40+
case Some(JArray((keys: JArray) :: JString(hash) :: Nil)) =>
41+
for {
42+
blockHash <- extractHash(hash)
43+
keys <- parseKeysList(keys)
44+
} yield GenerateCheckpointRequest(keys, Some(blockHash))
45+
case Some(JArray((keys: JArray) :: Nil)) =>
46+
parseKeysList(keys).map(GenerateCheckpointRequest(_, None))
47+
case _ =>
48+
Left(InvalidParams())
49+
}
50+
}
51+
52+
def encodeJson(t: GenerateCheckpointResponse): JValue = Extraction.decompose(t.checkpoint)
53+
}
54+
55+
private def parseKeysList(arr: JArray): Either[JsonRpcError, List[ByteString]] = {
56+
import cats.implicits._
57+
arr.arr.traverse {
58+
case JString(key) => extractBytes(key)
59+
case other => Left(InvalidParams(msg = s"Unable to parse private key, expected byte data but got: $other"))
60+
}
61+
}
62+
63+
implicit val qa_getFederationMembersInfo: Codec[GetFederationMembersInfoRequest, GetFederationMembersInfoResponse] =
64+
new NoParamsDecoder(GetFederationMembersInfoRequest()) with JsonEncoder[GetFederationMembersInfoResponse] {
65+
def encodeJson(t: GetFederationMembersInfoResponse): JValue = Extraction.decompose(t)
66+
}
3267
}

0 commit comments

Comments
 (0)