Skip to content

Commit c627fe8

Browse files
[ETCM-355] Send fork id in the Status message
1 parent 73840f5 commit c627fe8

File tree

9 files changed

+130
-6
lines changed

9 files changed

+130
-6
lines changed

src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu
172172
override val blockchain: Blockchain = CommonFakePeer.this.bl
173173
override val blockchainReader: BlockchainReader = CommonFakePeer.this.blockchainReader
174174
override val appStateStorage: AppStateStorage = storagesInstance.storages.appStateStorage
175+
override val blockchainConfig: BlockchainConfig = Config.blockchains.blockchainConfig
175176
override val capabilities: List[Capability] = blockchainConfig.capabilities
176177
}
177178

src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration
2727
import io.iohk.ethereum.network.{ForkResolver, PeerEventBusActor, PeerManagerActor}
2828
import io.iohk.ethereum.nodebuilder.{AuthHandshakerBuilder, NodeKeyBuilder}
2929
import io.iohk.ethereum.security.SecureRandomBuilder
30-
import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus}
30+
import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus, BlockchainConfig}
3131
import org.bouncycastle.util.encoders.Hex
3232
import org.scalamock.scalatest.MockFactory
3333

@@ -99,6 +99,7 @@ object DumpChainApp
9999
override val blockchain: Blockchain = DumpChainApp.blockchain
100100
override val blockchainReader: BlockchainReader = DumpChainApp.blockchainReader
101101
override val appStateStorage: AppStateStorage = storagesInstance.storages.appStateStorage
102+
override val blockchainConfig: BlockchainConfig = Config.blockchains.blockchainConfig
102103
override val capabilities: List[Capability] = blockchainConfig.capabilities
103104
}
104105

src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult
1313
import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders, NewBlockHashes}
1414
import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock
1515
import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect
16-
import io.iohk.ethereum.network.p2p.messages.{Codes, BaseETH6XMessages, ETC64}
16+
import io.iohk.ethereum.network.p2p.messages.{Codes, BaseETH6XMessages, ETC64, ETH64}
1717
import io.iohk.ethereum.network.p2p.{Message, MessageSerializable}
1818
import io.iohk.ethereum.utils.ByteStringUtils
1919

@@ -259,6 +259,15 @@ object EtcPeerManagerActor {
259259
}
260260

261261
object RemoteStatus {
262+
def apply(status: ETH64.Status): RemoteStatus = {
263+
RemoteStatus(
264+
status.protocolVersion,
265+
status.networkId,
266+
ChainWeight.totalDifficultyOnly(status.totalDifficulty),
267+
status.bestHash,
268+
status.genesisHash
269+
)
270+
}
262271
def apply(status: ETC64.Status): RemoteStatus = {
263272
RemoteStatus(status.protocolVersion, status.networkId, status.chainWeight, status.bestHash, status.genesisHash)
264273
}

src/main/scala/io/iohk/ethereum/network/handshaker/EtcHandshaker.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import io.iohk.ethereum.network.ForkResolver
88
import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration
99
import io.iohk.ethereum.network.p2p.messages.Capability
1010
import io.iohk.ethereum.utils.NodeStatus
11+
import io.iohk.ethereum.utils.BlockchainConfig
1112

1213
case class EtcHandshaker private (
1314
handshakerState: HandshakerState[PeerInfo],
@@ -37,4 +38,5 @@ trait EtcHandshakerConfiguration {
3738
val peerConfiguration: PeerConfiguration
3839
val forkResolverOpt: Option[ForkResolver]
3940
val capabilities: List[Capability]
41+
val blockchainConfig: BlockchainConfig
4042
}

src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ case class EtcHelloExchangeState(handshakerConfiguration: EtcHandshakerConfigura
3030
Capability.negotiate(hello.capabilities.toList, handshakerConfiguration.capabilities) match {
3131
case Some(ProtocolVersions.ETC64) => EtcNodeStatus64ExchangeState(handshakerConfiguration)
3232
case Some(ProtocolVersions.ETH63) => EtcNodeStatus63ExchangeState(handshakerConfiguration)
33+
case Some(ProtocolVersions.ETH64) => EthNodeStatus64ExchangeState(handshakerConfiguration)
3334
case _ =>
3435
log.debug(
35-
s"Connected peer does not support {} / {} protocol. Disconnecting.",
36+
s"Connected peer does not support {} / {} / {} protocol. Disconnecting.",
3637
ProtocolVersions.ETH63,
38+
ProtocolVersions.ETH64,
3739
ProtocolVersions.ETC64
3840
)
3941
DisconnectedState(Disconnect.Reasons.IncompatibleP2pProtocolVersion)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.iohk.ethereum.network.handshaker
2+
3+
import io.iohk.ethereum.forkid.ForkId
4+
import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus}
5+
import io.iohk.ethereum.network.p2p.messages.{BaseETH6XMessages, ProtocolVersions, ETH64}
6+
import io.iohk.ethereum.network.p2p.{Message, MessageSerializable}
7+
8+
case class EthNodeStatus64ExchangeState(
9+
handshakerConfiguration: EtcHandshakerConfiguration
10+
) extends EtcNodeStatusExchangeState[ETH64.Status] {
11+
12+
import handshakerConfiguration._
13+
14+
def applyResponseMessage: PartialFunction[Message, HandshakerState[PeerInfo]] = { case status: ETH64.Status =>
15+
// TODO: validate fork id of the remote peer
16+
applyRemoteStatusMessage(RemoteStatus(status))
17+
}
18+
19+
override protected def createStatusMsg(): MessageSerializable = {
20+
val bestBlockHeader = getBestBlockHeader()
21+
val chainWeight = blockchain.getChainWeightByHash(bestBlockHeader.hash).get
22+
val genesisHash = blockchain.genesisHeader.hash
23+
24+
val status = ETH64.Status(
25+
protocolVersion = ProtocolVersions.ETH64.version,
26+
networkId = peerConfiguration.networkId,
27+
totalDifficulty = chainWeight.totalDifficulty,
28+
bestHash = bestBlockHeader.hash,
29+
genesisHash = genesisHash,
30+
forkId = ForkId.create(genesisHash, blockchainConfig)(blockchain.getBestBlockNumber())
31+
)
32+
33+
log.debug(s"Sending status $status")
34+
status
35+
}
36+
37+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ trait HandshakerBuilder {
220220
override val blockchainReader: BlockchainReader = self.blockchainReader
221221
override val appStateStorage: AppStateStorage = self.storagesInstance.storages.appStateStorage
222222
override val capabilities: List[Capability] = self.blockchainConfig.capabilities
223+
override val blockchainConfig: BlockchainConfig = self.blockchainConfig
223224
}
224225

225226
lazy val handshaker: Handshaker[PeerInfo] = EtcHandshaker(handshakerConfiguration)

src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup
88
import io.iohk.ethereum.crypto.generateKeyPair
99
import io.iohk.ethereum.db.storage.AppStateStorage
1010
import io.iohk.ethereum.domain._
11+
import io.iohk.ethereum.forkid.ForkId
1112
import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus}
1213
import io.iohk.ethereum.network.ForkResolver
1314
import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration
1415
import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.{HandshakeFailure, HandshakeSuccess}
1516
import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._
1617
import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status.StatusEnc
18+
import io.iohk.ethereum.network.p2p.messages.ETH64
1719
import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders.GetBlockHeadersEnc
1820
import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders}
1921
import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello.HelloEnc
@@ -181,6 +183,40 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
181183
}
182184
}
183185

186+
it should "send status with fork id when peer supports ETH64" in new LocalPeerETH64Setup
187+
with RemotePeerETH64Setup {
188+
189+
val newChainWeight = ChainWeight.zero.increase(genesisBlock.header).increase(firstBlock.header)
190+
191+
blockchain.save(firstBlock, Nil, newChainWeight, saveAsBestBlock = true)
192+
193+
val newLocalStatusMsg =
194+
localStatusMsg
195+
.copy(
196+
bestHash = firstBlock.header.hash,
197+
totalDifficulty = newChainWeight.totalDifficulty,
198+
forkId = ForkId(0xfc64ec04L, Some(1150000))
199+
)
200+
201+
initHandshakerWithoutResolver.nextMessage.map(_.messageToSend) shouldBe Right(localHello: HelloEnc)
202+
203+
val handshakerAfterHelloOpt = initHandshakerWithoutResolver.applyMessage(remoteHello)
204+
assert(handshakerAfterHelloOpt.isDefined)
205+
206+
handshakerAfterHelloOpt.get.nextMessage.map(_.messageToSend.underlyingMsg) shouldBe Right(newLocalStatusMsg)
207+
208+
val handshakerAfterStatusOpt = handshakerAfterHelloOpt.get.applyMessage(remoteStatusMsg)
209+
assert(handshakerAfterStatusOpt.isDefined)
210+
211+
handshakerAfterStatusOpt.get.nextMessage match {
212+
case Left(HandshakeSuccess(peerInfo)) =>
213+
peerInfo.remoteStatus.protocolVersion shouldBe localStatus.protocolVersion
214+
215+
case other =>
216+
fail(s"Invalid handshaker state: $other")
217+
}
218+
}
219+
184220
it should "fail if a timeout happened during hello exchange" in new TestSetup {
185221
val handshakerAfterTimeout = initHandshakerWithoutResolver.processTimeout
186222
handshakerAfterTimeout.nextMessage.map(_.messageToSend) shouldBe Left(
@@ -278,6 +314,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
278314
override val appStateStorage: AppStateStorage = TestSetup.this.storagesInstance.storages.appStateStorage
279315
override val capabilities: List[Capability] = pv
280316
override val blockchainReader: BlockchainReader = TestSetup.this.blockchainReader
317+
override val blockchainConfig: BlockchainConfig = TestSetup.this.blockchainConfig
281318
}
282319

283320
val etcHandshakerConfigurationWithResolver = new MockEtcHandshakerConfiguration {
@@ -287,7 +324,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
287324
}
288325

289326
val initHandshakerWithoutResolver = EtcHandshaker(
290-
new MockEtcHandshakerConfiguration(List(ProtocolVersions.ETC64, ProtocolVersions.ETH63))
327+
new MockEtcHandshakerConfiguration(List(ProtocolVersions.ETC64, ProtocolVersions.ETH63, ProtocolVersions.ETH64))
291328
)
292329

293330
val initHandshakerWithResolver = EtcHandshaker(etcHandshakerConfigurationWithResolver)
@@ -300,7 +337,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
300337
val localHello = Hello(
301338
p2pVersion = EtcHelloExchangeState.P2pVersion,
302339
clientId = Config.clientId,
303-
capabilities = Seq(Etc64Capability, Eth63Capability),
340+
capabilities = Seq(Etc64Capability, Eth63Capability, Eth64Capability),
304341
listenPort = 0, //Local node not listening
305342
nodeId = ByteString(nodeStatus.nodeId)
306343
)
@@ -320,6 +357,18 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
320357
val localStatus = RemoteStatus(localStatusMsg)
321358
}
322359

360+
trait LocalPeerETH64Setup extends LocalPeerSetup {
361+
val localStatusMsg = ETH64.Status(
362+
protocolVersion = ProtocolVersions.ETH64.version,
363+
networkId = Config.Network.peer.networkId,
364+
totalDifficulty = genesisBlock.header.difficulty,
365+
bestHash = genesisBlock.header.hash,
366+
genesisHash = genesisBlock.header.hash,
367+
forkId = ForkId(1L, None)
368+
)
369+
val localStatus = RemoteStatus(localStatusMsg)
370+
}
371+
323372
trait LocalPeerETC64Setup extends LocalPeerSetup {
324373
val localStatusMsg = ETC64.Status(
325374
protocolVersion = ProtocolVersions.ETC64.version,
@@ -378,4 +427,25 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
378427
genesisHash = genesisBlock.header.hash
379428
)
380429
}
430+
431+
trait RemotePeerETH64Setup extends RemotePeerSetup {
432+
val remoteHello = Hello(
433+
p2pVersion = EtcHelloExchangeState.P2pVersion,
434+
clientId = "remote-peer",
435+
capabilities = Seq(Eth64Capability),
436+
listenPort = remotePort,
437+
nodeId = ByteString(remoteNodeStatus.nodeId)
438+
)
439+
440+
val remoteStatusMsg = ETH64.Status(
441+
protocolVersion = ProtocolVersions.ETH64.version,
442+
networkId = Config.Network.peer.networkId,
443+
totalDifficulty = 0,
444+
bestHash = genesisBlock.header.hash,
445+
genesisHash = genesisBlock.header.hash,
446+
forkId = ForkId(2L, Some(3L))
447+
)
448+
449+
val remoteStatus = RemoteStatus(remoteStatusMsg)
450+
}
381451
}

src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler
3131
import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration
3232
import io.iohk.ethereum.network.{ForkResolver, PeerActor, PeerEventBusActor, _}
3333
import io.iohk.ethereum.security.SecureRandomBuilder
34-
import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus}
34+
import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus, BlockchainConfig}
3535
import org.bouncycastle.crypto.AsymmetricCipherKeyPair
3636
import org.bouncycastle.crypto.params.ECPublicKeyParameters
3737
import org.bouncycastle.util.encoders.Hex
@@ -566,6 +566,7 @@ class PeerActorSpec
566566
override val blockchainReader: BlockchainReader = self.blockchainReader
567567
override val appStateStorage: AppStateStorage = self.storagesInstance.storages.appStateStorage
568568
override val capabilities: List[Capability] = List(protocol)
569+
override val blockchainConfig: BlockchainConfig = self.blockchainConfig
569570
}
570571

571572
val handshaker = EtcHandshaker(handshakerConfiguration)

0 commit comments

Comments
 (0)