Skip to content

Commit 5bf26ac

Browse files
[ETCM-355] Send fork id in the Status message
1 parent 8780e8c commit 5bf26ac

File tree

10 files changed

+144
-18
lines changed

10 files changed

+144
-18
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
@@ -192,6 +192,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu
192192
override val blockchain: Blockchain = CommonFakePeer.this.bl
193193
override val blockchainReader: BlockchainReader = CommonFakePeer.this.blockchainReader
194194
override val appStateStorage: AppStateStorage = storagesInstance.storages.appStateStorage
195+
override val blockchainConfig: BlockchainConfig = Config.blockchains.blockchainConfig
195196
override val capabilities: List[Capability] = blockchainConfig.capabilities
196197
}
197198

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration
4949
import io.iohk.ethereum.nodebuilder.AuthHandshakerBuilder
5050
import io.iohk.ethereum.nodebuilder.NodeKeyBuilder
5151
import io.iohk.ethereum.security.SecureRandomBuilder
52+
import io.iohk.ethereum.utils.BlockchainConfig
5253
import io.iohk.ethereum.utils.Config
5354
import io.iohk.ethereum.utils.NodeStatus
5455
import io.iohk.ethereum.utils.ServerStatus
@@ -121,6 +122,7 @@ object DumpChainApp
121122
override val blockchain: Blockchain = DumpChainApp.blockchain
122123
override val blockchainReader: BlockchainReader = DumpChainApp.blockchainReader
123124
override val appStateStorage: AppStateStorage = storagesInstance.storages.appStateStorage
125+
override val blockchainConfig: BlockchainConfig = Config.blockchains.blockchainConfig
124126
override val capabilities: List[Capability] = blockchainConfig.capabilities
125127
}
126128

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock
2626
import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders
2727
import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders
2828
import io.iohk.ethereum.network.p2p.messages.ETH62.NewBlockHashes
29+
import io.iohk.ethereum.network.p2p.messages.ETH64
2930
import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect
3031
import io.iohk.ethereum.utils.ByteStringUtils
3132

@@ -256,6 +257,15 @@ object EtcPeerManagerActor {
256257
}
257258

258259
object RemoteStatus {
260+
def apply(status: ETH64.Status): RemoteStatus =
261+
RemoteStatus(
262+
status.protocolVersion,
263+
status.networkId,
264+
ChainWeight.totalDifficultyOnly(status.totalDifficulty),
265+
status.bestHash,
266+
status.genesisHash
267+
)
268+
259269
def apply(status: ETC64.Status): RemoteStatus =
260270
RemoteStatus(status.protocolVersion, status.networkId, status.chainWeight, status.bestHash, status.genesisHash)
261271

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.iohk.ethereum.network.ForkResolver
1010
import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration
1111
import io.iohk.ethereum.network.p2p.messages.Capability
1212
import io.iohk.ethereum.utils.NodeStatus
13+
import io.iohk.ethereum.utils.BlockchainConfig
1314

1415
case class EtcHandshaker private (
1516
handshakerState: HandshakerState[PeerInfo],
@@ -38,4 +39,5 @@ trait EtcHandshakerConfiguration {
3839
val peerConfiguration: PeerConfiguration
3940
val forkResolverOpt: Option[ForkResolver]
4041
val capabilities: List[Capability]
42+
val blockchainConfig: BlockchainConfig
4143
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ case class EtcHelloExchangeState(handshakerConfiguration: EtcHandshakerConfigura
3333
Capability.negotiate(hello.capabilities.toList, handshakerConfiguration.capabilities) match {
3434
case Some(ProtocolVersions.ETC64) => EtcNodeStatus64ExchangeState(handshakerConfiguration)
3535
case Some(ProtocolVersions.ETH63) => EtcNodeStatus63ExchangeState(handshakerConfiguration)
36+
case Some(ProtocolVersions.ETH64) => EthNodeStatus64ExchangeState(handshakerConfiguration)
3637
case _ =>
3738
log.debug(
38-
s"Connected peer does not support {} / {} protocol. Disconnecting.",
39+
s"Connected peer does not support {} / {} / {} protocol. Disconnecting.",
3940
ProtocolVersions.ETH63,
41+
ProtocolVersions.ETH64,
4042
ProtocolVersions.ETC64
4143
)
4244
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/network/p2p/MessageDecoders.scala

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,23 @@ object ETH64MessageDecoder extends MessageDecoder {
5959
import io.iohk.ethereum.network.p2p.messages.ETH64.Status._
6060
import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock._
6161

62-
def fromBytes(msgCode: Int, payload: Array[Byte]): Message = {
62+
def fromBytes(msgCode: Int, payload: Array[Byte]): Message =
6363
msgCode match {
64-
case Codes.GetNodeDataCode => payload.toGetNodeData
65-
case Codes.NodeDataCode => payload.toNodeData
66-
case Codes.GetReceiptsCode => payload.toGetReceipts
67-
case Codes.ReceiptsCode => payload.toReceipts
68-
case Codes.NewBlockHashesCode => payload.toNewBlockHashes
69-
case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders
70-
case Codes.BlockHeadersCode => payload.toBlockHeaders
71-
case Codes.GetBlockBodiesCode => payload.toGetBlockBodies
72-
case Codes.BlockBodiesCode => payload.toBlockBodies
64+
case Codes.GetNodeDataCode => payload.toGetNodeData
65+
case Codes.NodeDataCode => payload.toNodeData
66+
case Codes.GetReceiptsCode => payload.toGetReceipts
67+
case Codes.ReceiptsCode => payload.toReceipts
68+
case Codes.NewBlockHashesCode => payload.toNewBlockHashes
69+
case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders
70+
case Codes.BlockHeadersCode => payload.toBlockHeaders
71+
case Codes.GetBlockBodiesCode => payload.toGetBlockBodies
72+
case Codes.BlockBodiesCode => payload.toBlockBodies
7373
case Codes.BlockHashesFromNumberCode => payload.toBlockHashesFromNumber
74-
case Codes.StatusCode => payload.toStatus
75-
case Codes.NewBlockCode => payload.toNewBlock
76-
case Codes.SignedTransactionsCode => payload.toSignedTransactions
77-
case _ => throw new RuntimeException(s"Unknown message type: $msgCode")
74+
case Codes.StatusCode => payload.toStatus
75+
case Codes.NewBlockCode => payload.toNewBlock
76+
case Codes.SignedTransactionsCode => payload.toSignedTransactions
77+
case _ => throw new RuntimeException(s"Unknown message type: $msgCode")
7878
}
79-
}
8079
}
8180

8281
object ETH63MessageDecoder extends MessageDecoder {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ trait HandshakerBuilder {
238238
override val blockchainReader: BlockchainReader = self.blockchainReader
239239
override val appStateStorage: AppStateStorage = self.storagesInstance.storages.appStateStorage
240240
override val capabilities: List[Capability] = self.blockchainConfig.capabilities
241+
override val blockchainConfig: BlockchainConfig = self.blockchainConfig
241242
}
242243

243244
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
@@ -12,6 +12,7 @@ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup
1212
import io.iohk.ethereum.crypto.generateKeyPair
1313
import io.iohk.ethereum.db.storage.AppStateStorage
1414
import io.iohk.ethereum.domain._
15+
import io.iohk.ethereum.forkid.ForkId
1516
import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo
1617
import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus
1718
import io.iohk.ethereum.network.ForkResolver
@@ -26,6 +27,7 @@ import io.iohk.ethereum.network.p2p.messages.ETC64
2627
import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders
2728
import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders
2829
import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders.GetBlockHeadersEnc
30+
import io.iohk.ethereum.network.p2p.messages.ETH64
2931
import io.iohk.ethereum.network.p2p.messages.ProtocolVersions
3032
import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect
3133
import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello
@@ -190,6 +192,40 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
190192
}
191193
}
192194

195+
it should "send status with fork id when peer supports ETH64" in new LocalPeerETH64Setup
196+
with RemotePeerETH64Setup {
197+
198+
val newChainWeight = ChainWeight.zero.increase(genesisBlock.header).increase(firstBlock.header)
199+
200+
blockchain.save(firstBlock, Nil, newChainWeight, saveAsBestBlock = true)
201+
202+
val newLocalStatusMsg =
203+
localStatusMsg
204+
.copy(
205+
bestHash = firstBlock.header.hash,
206+
totalDifficulty = newChainWeight.totalDifficulty,
207+
forkId = ForkId(0xfc64ec04L, Some(1150000))
208+
)
209+
210+
initHandshakerWithoutResolver.nextMessage.map(_.messageToSend) shouldBe Right(localHello: HelloEnc)
211+
212+
val handshakerAfterHelloOpt = initHandshakerWithoutResolver.applyMessage(remoteHello)
213+
assert(handshakerAfterHelloOpt.isDefined)
214+
215+
handshakerAfterHelloOpt.get.nextMessage.map(_.messageToSend.underlyingMsg) shouldBe Right(newLocalStatusMsg)
216+
217+
val handshakerAfterStatusOpt = handshakerAfterHelloOpt.get.applyMessage(remoteStatusMsg)
218+
assert(handshakerAfterStatusOpt.isDefined)
219+
220+
handshakerAfterStatusOpt.get.nextMessage match {
221+
case Left(HandshakeSuccess(peerInfo)) =>
222+
peerInfo.remoteStatus.protocolVersion shouldBe localStatus.protocolVersion
223+
224+
case other =>
225+
fail(s"Invalid handshaker state: $other")
226+
}
227+
}
228+
193229
it should "fail if a timeout happened during hello exchange" in new TestSetup {
194230
val handshakerAfterTimeout = initHandshakerWithoutResolver.processTimeout
195231
handshakerAfterTimeout.nextMessage.map(_.messageToSend) shouldBe Left(
@@ -287,6 +323,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
287323
override val appStateStorage: AppStateStorage = TestSetup.this.storagesInstance.storages.appStateStorage
288324
override val capabilities: List[Capability] = pv
289325
override val blockchainReader: BlockchainReader = TestSetup.this.blockchainReader
326+
override val blockchainConfig: BlockchainConfig = TestSetup.this.blockchainConfig
290327
}
291328

292329
val etcHandshakerConfigurationWithResolver: MockEtcHandshakerConfiguration = new MockEtcHandshakerConfiguration {
@@ -296,7 +333,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
296333
}
297334

298335
val initHandshakerWithoutResolver: EtcHandshaker = EtcHandshaker(
299-
new MockEtcHandshakerConfiguration(List(ProtocolVersions.ETC64, ProtocolVersions.ETH63))
336+
new MockEtcHandshakerConfiguration(List(ProtocolVersions.ETC64, ProtocolVersions.ETH63, ProtocolVersions.ETH64))
300337
)
301338

302339
val initHandshakerWithResolver: EtcHandshaker = EtcHandshaker(etcHandshakerConfigurationWithResolver)
@@ -309,7 +346,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
309346
val localHello: Hello = Hello(
310347
p2pVersion = EtcHelloExchangeState.P2pVersion,
311348
clientId = Config.clientId,
312-
capabilities = Seq(Etc64Capability, Eth63Capability),
349+
capabilities = Seq(Etc64Capability, Eth63Capability, Eth64Capability),
313350
listenPort = 0, //Local node not listening
314351
nodeId = ByteString(nodeStatus.nodeId)
315352
)
@@ -329,6 +366,18 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
329366
val localStatus: RemoteStatus = RemoteStatus(localStatusMsg)
330367
}
331368

369+
trait LocalPeerETH64Setup extends LocalPeerSetup {
370+
val localStatusMsg = ETH64.Status(
371+
protocolVersion = ProtocolVersions.ETH64.version,
372+
networkId = Config.Network.peer.networkId,
373+
totalDifficulty = genesisBlock.header.difficulty,
374+
bestHash = genesisBlock.header.hash,
375+
genesisHash = genesisBlock.header.hash,
376+
forkId = ForkId(1L, None)
377+
)
378+
val localStatus = RemoteStatus(localStatusMsg)
379+
}
380+
332381
trait LocalPeerETC64Setup extends LocalPeerSetup {
333382
val localStatusMsg: ETC64.Status = ETC64.Status(
334383
protocolVersion = ProtocolVersions.ETC64.version,
@@ -387,4 +436,25 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers {
387436
genesisHash = genesisBlock.header.hash
388437
)
389438
}
439+
440+
trait RemotePeerETH64Setup extends RemotePeerSetup {
441+
val remoteHello = Hello(
442+
p2pVersion = EtcHelloExchangeState.P2pVersion,
443+
clientId = "remote-peer",
444+
capabilities = Seq(Eth64Capability),
445+
listenPort = remotePort,
446+
nodeId = ByteString(remoteNodeStatus.nodeId)
447+
)
448+
449+
val remoteStatusMsg = ETH64.Status(
450+
protocolVersion = ProtocolVersions.ETH64.version,
451+
networkId = Config.Network.peer.networkId,
452+
totalDifficulty = 0,
453+
bestHash = genesisBlock.header.hash,
454+
genesisHash = genesisBlock.header.hash,
455+
forkId = ForkId(2L, Some(3L))
456+
)
457+
458+
val remoteStatus = RemoteStatus(remoteStatusMsg)
459+
}
390460
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import io.iohk.ethereum.network.p2p.messages.WireProtocol._
5858
import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler
5959
import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration
6060
import io.iohk.ethereum.security.SecureRandomBuilder
61+
import io.iohk.ethereum.utils.BlockchainConfig
6162
import io.iohk.ethereum.utils.Config
6263
import io.iohk.ethereum.utils.NodeStatus
6364
import io.iohk.ethereum.utils.ServerStatus
@@ -587,6 +588,7 @@ class PeerActorSpec
587588
override val blockchainReader: BlockchainReader = self.blockchainReader
588589
override val appStateStorage: AppStateStorage = self.storagesInstance.storages.appStateStorage
589590
override val capabilities: List[Capability] = List(protocol)
591+
override val blockchainConfig: BlockchainConfig = self.blockchainConfig
590592
}
591593

592594
val handshaker: EtcHandshaker = EtcHandshaker(handshakerConfiguration)

0 commit comments

Comments
 (0)