-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ETCM-280] Use capabilities when sending checkpoint related network messages #793
Conversation
3135e5a
to
928d2b3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how this is all looking! I still have pending taking a look at the test changes, some comments before that:
src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/network/p2p/messages/PV64.scala
Outdated
Show resolved
Hide resolved
@@ -24,10 +26,14 @@ case class EtcHelloExchangeState(handshakerConfiguration: EtcHandshakerConfigura | |||
|
|||
override def applyResponseMessage: PartialFunction[Message, HandshakerState[PeerInfo]] = { case hello: Hello => | |||
log.debug("Protocol handshake finished with peer ({})", hello) | |||
if (hello.capabilities.contains(Capability("eth", Versions.PV63.toByte))) | |||
EtcNodeStatusExchangeState(handshakerConfiguration) | |||
if (handshakerConfiguration.protocolVersion == Versions.PV64 && hello.capabilities.contains(Eth64Capability)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something that I'm thinking about this now... this will be all fine and well for a testnet with Mantis only nodes, but when we open it up for any other client to implement checkpointing/treasury and connect to it, this will sound like a hack very difficult for them to do so.
And I don't see any way of working our way around it... if you agree with what I'm saying I'll share this with Dragan and Juli so that they know about it and maybe give higher priority to implementing eth64 and eth65
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - current PV64 version should be temporary, only for our testnet usage and ultimately it should be PV65/PV66 (I'm not sure what is last ETC PV)
src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala
Show resolved
Hide resolved
0c09056
to
5a36702
Compare
chainWeight.totalDifficulty, | ||
bestHash, | ||
genesisHash, | ||
chainWeight.lastCheckpointNumber |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really minor, but I see you keep insisting on having this as last field in the RLP. I really don't see the point in this. This is not an extension, all the fields could be totally different. It would make much more sense to me to keep relevant fields close together.
requestSender.expectMsg(PeerInfoResponse(Some(peer1Info.withChainWeight(ChainWeight.totalDifficultyOnly(newBlock.totalDifficulty))))) | ||
} | ||
|
||
it should "update the peer total difficulty when receiving a PV64.NewBlock" in new TestSetup { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
total diff -> chain weight ?
case (PV62 | PV63, pv62.BlockHeaders.code) => payload.toBlockHeaders | ||
case (PV62 | PV63, pv62.GetBlockBodies.code) => payload.toGetBlockBodies | ||
case (PV62 | PV63, pv62.BlockBodies.code) => payload.toBlockBodies | ||
case (PV62 | PV63, Codes.NewBlockHashesCode) => payload.toNewBlockHashes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't these messages be handled for PV64 as well? This code is getting a bit out of control so I would suggest to refactor as follows:
def fromBytes(protocolVersion, msgCode, payload) = {
protocolVersion match {
case PV64 => handlePV64(msgCode, payload)
case PV63 => handlePV63(msgCode, payload)
...
case PV60 => handlePV60(msgCode, payload)
case _ => fail()
}
}
private def handlePV64(msgCode, payload) = msgCode match {
case pv64msg1 => decode(payload)
case pv64msg2 => decode(payload)
case msgObsoletedByPV64 => fail() // not sure if we need this case for any PV**
...
case _ => handlePV63(msg, payload)
}
private def handlePV63(msgCode, payload) = msgCode match {
case pv63msg1 => decode(payload)
case pv63msg2 => decode(payload)
...
case _ => handlePV62(msg, payload)
}
...
private def handlePV60(msgCode, payload) = msgCode match {
case pv60msg1 => decode(payload)
case pv60msg2 => decode(payload)
...
case _ => fail()
}
This introduces PV60 as the version for common messages. Perhaps we should even rename CommonMessages
to PV60
as this would give us more consistent naming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my initial version, Status and NewBlock were part of PV63, but I decided later to move them to CommonMessages again. The true is PV61 Status is different than other ones, but we have not supported it and just use that common Status everywhere besides new PV. I don't know if we want to clean it up or not? @ntallar ? If yes, we can do this in the different PR, as this one is already big one.
c33def8
to
d88ac8f
Compare
@@ -38,45 +35,87 @@ object NetworkMessageDecoder extends MessageDecoder { | |||
// scalastyle:off | |||
object EthereumMessageDecoder extends MessageDecoder { | |||
|
|||
override def fromBytes(msgCode: Int, payload: Array[Byte], protocolVersion: Version): Message = | |||
private type MessageHandler = PartialFunction[(Int, Array[Byte]), Message] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this approach better/cleaner than what I proposed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is far more composable - with your approach I can't just do case _ => handlePV63(msg, payload)
because it isn't true, we are handling NewBlock/Status differently than PV63, so it ends up with copying all those PV63 and PV62 messages or doing similar partition as I did and instead of orElse
use case _ => nextHandler(msg, payload)
where nextHandler will have another call with wildcard etc. For me it's just the perfect fit for PartialFunction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't just do case _ => handlePV63(msg, payload) because it isn't true
What isn't true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok you right, I can do this with simple matching, I forgot that those new messages would be matched firstly and the bad path is not reachable
src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala
Outdated
Show resolved
Hide resolved
1591596
to
ec3b952
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only major comment regarding the block broadcasting compatibility issue
Apart from this comments, LGTM!
src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala
Outdated
Show resolved
Hide resolved
src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcast.scala
Show resolved
Hide resolved
eb04693
to
80d17db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the two comments above, LGTM!
b1307b7
to
fa3d0d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
.\\ //.
. \ \ / /.
.\ ,\ /` /,.-
-. \ /'/ / .
` - `-' \ -
'. /.\`
- .-
:`//.'
.`.'
.' BP
fa3d0d2
to
298934b
Compare
I reviewed this in the following one(#810), where i wrote some comments...But in general, the code LGTM! |
case (PV62 | PV63, pv62.BlockHeaders.code) => payload.toBlockHeaders | ||
case (PV62 | PV63, pv62.GetBlockBodies.code) => payload.toGetBlockBodies | ||
case (PV62 | PV63, pv62.BlockBodies.code) => payload.toBlockBodies | ||
private def handleCommonMessages(msgCode: Int, payload: Array[Byte]): Message = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we not want to call them PV60?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think CommonMessages
may be misleading. Since PV64 overrides Status
and NewBlock
, they are not common anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can refactor it in ETCM-402
case PV61 => handlePV61(msgCode, payload) | ||
case PV62 => handlePV62(msgCode, payload) | ||
case PV63 => handlePV63(msgCode, payload) | ||
case PV64 => handlePV64(msgCode, payload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor optimization: higher PVs will be matched more often, so they could be matched first
case (_, NewBlock.code63 | NewBlock.code64) => payload.toNewBlock(msgCode) | ||
|
||
case (PV61, t) => handlePV61(t, payload) | ||
override def fromBytes(msgCode: Int, payload: Array[Byte], protocolVersion: Version): Message = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very tidy now <3
case Disconnect.code => payload.toDisconnect | ||
case Ping.code => payload.toPing | ||
case Pong.code => payload.toPong | ||
case Hello.code => payload.toHello |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
…kpoint-related messages
298934b
to
ee982e8
Compare
Description
The version of the message to send should be determined by peer capabilities
Proposed Solution
During the handshake, the peer is introducing its capabilities to supported protocols. Base on that mantis is deciding which version of message use.
Important Changes Introduced
network.protocol-version
)Testing
Enable PV64 and try to sync with PV63 client and PV64 client