-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[ETCM-143] Redefine block header structure and encoding #709
Conversation
355e8ec
to
7d2c569
Compare
7d2c569
to
357e5ad
Compare
|
||
sealed trait HeaderExtraFields | ||
object HeaderExtraFields { | ||
case object HefPreEcip1098 extends HeaderExtraFields |
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 a better name would be HefEmpty
- it would immediately stand out from the others and be associated with the default case, whereas the current name requires some attention to be distinguished from others.
} | ||
|
||
// scalastyle:off parameter.number | ||
def buildPreECIP1098Header(parentHash: ByteString, |
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.
Is it worth adding all these methods? Maybe we could just have a default param extraFields: HeaderExtraFields = HefEmpty
on the default constructor? And as for the extra fields, I don't think wrapping them in the HEF-constructor is that tedious to necessitate these methods
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 found them useful when changing the block header structure as that required less changes. Given that and that we might eventually further change it (in case we want 3 different header structures) I saw no reason to delete them once I had them
But I don't have too much of a strong opinions right now, if you have stronger opinions on deleting them I can do so
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.
Well, I think that using a default arg for extraFields
would result in even fewer changes. Any future changes should also require less maintenance. Do you think there is another advantage to having these factories?
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.
Tbh I don't like much default arg in general (exceptuating some use cases) as I see them too error prone... but given the subjectivity of this and that the PR has been open for a long time I'll change this
@@ -77,7 +78,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) | |||
_ <- validateGasUsed(blockHeader) | |||
_ <- validateGasLimit(blockHeader, parentHeader) | |||
_ <- validateNumber(blockHeader, parentHeader) | |||
_ <- validateOptOut(blockHeader) | |||
_ <- validateExtraFields(blockHeader) |
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.
not sure if this is important, but this is basically validating if the whole structure of header is valid. Should't we do it as first thing ?
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.
For attack purposes or for facilitating our usage of it?
I'm not sure if the order of the validations should matter that much here as they all are quite simple and easy to check (except from the PoW validation that probably takes more). So I'm not convinced if it would be better for them to have a particular order
val rlpItemsWithoutNonce = blockHeader.extraFields match { | ||
case HefPostEcip1097(_ , _) => | ||
// Post ECIP1098 & ECIP1097 block | ||
rlpList.items.dropRight(4) ++ rlpList.items.takeRight(2) |
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.
those constants could be defined somwhere and named, as i am not sure what this rlpList.items.takeRight(2)
bit means
@@ -139,6 +141,16 @@ trait ObjectGenerators { | |||
td <- bigIntGen | |||
} yield NewBlock(Block(blockHeader, BlockBody(stxs, uncles)), td) | |||
|
|||
def extraFieldsGen: Gen[HeaderExtraFields] = for { |
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 know we have property tests for it, but maybe it is wortth while to create some specific encoding cases like in: https://github.com/input-output-hk/mantis/blob/develop/src/test/scala/io/iohk/ethereum/network/p2p/messages/ReceiptsSpec.scala#L38, it will give someone inspecting it in the future idea how encoded payload looks like.
…getEncodedWithoutNonce for greater readability
Description
Improves both the block header structure and the way it's encoded
Changes are strongly based on the assumption that ECIP1098 will be activated before ECIP1097. However, if that assumption is not true, it can be easily re-adjusted, for that reason I'd consider an overkill providing a full mechanism to support both orders. [1]
Important Changes Introduced
Block header encoding
Block header encoding is done as if we had 3 different types of headers:
In this way the type of the block can be determined exclusively by the number of fields the block has. Note that this (with the block number validations) is identical to determining the block header type through the block number
This mechanism is based on the fact that each ECIP activated added new fields to the block header, if future ECIPs want to also remove fields they should follow other mechanisms [1]
Block header structure
Instead of having 3 different block headers structures, as mentioned on the encoding section, this is analogously done as an extra fields field on the block header, with one possible value for each of the 3 header structures
Testing
Pending
Notes
[1] Two possible mechanism that would allow ECIP1097 to be activated before ECIP1098 as well as removing fields: