-
Notifications
You must be signed in to change notification settings - Fork 835
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
Add withdrawals to PayloadIdentifier to avoid collisions #5321
Conversation
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
|
withdrawals | ||
.map( | ||
ws -> | ||
ws.stream().map(Withdrawal::hashCode).reduce(0, (a, b) -> a ^ (b * 31))) |
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.
great place for a clarifying comment. it isn't clear whether this is determistic or not at first glance.
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.
Which bit should I clarify?
This line attempts to create a deterministic hash and avoid collisions, which I believe is the same as the rest of the method.
I think the forPayloadParams method maybe needs a comment about strategy for creating the hash, but I'm missing the original context. This line is a continuation of the above code I guess.
I'm also concerned about the even numbers used in the bitshifting of the other hashes, e.g. (long) parentHash.toHexString().hashCode()) << 8
I found collisions when I did something similar with withdrawals.
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 might be wise to sort before mapping the list, on the off chance that the order is different but the contents the same.
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.
Withdrawals should be in the same order, but good idea to sort the list just in case as we can't guarantee it at this level. Have committed a fix for that.
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.
the current implementation is basically a custom made hash function, that try to spread hash codes of the input parameters across all the available 8 bytes, but not sure how much collision resistant it is, so we can probably just use a standard hash function that.
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 have a couple questions about the actual Payload Identifier creation, but LGTM. This is a nice way to partition these requests without having to make a value judgement on either of them.
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Jason Frame <jason.frame@consensys.net>
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
ws.stream() | ||
.sorted(Comparator.comparing(Withdrawal::getIndex)) | ||
.map(Withdrawal::hashCode) | ||
.reduce(1, (a, b) -> a ^ (b * 31))) |
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.
LGTM 👍
…#5321) Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
…#5321) Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
…#5321) Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
We have come across a case where certain network conditions cause nimbus to replay an engine_forkchoiceUpdatedV2 (FCU) request with payloadParameters, except with a small change to the Withdrawal amounts (since the validator balances have changed between requests).
This ultimately results in a missed proposal.
No error log present on besu side. Here is the error you would see on nimbus:
Here's how besu behaviour leads to this mismatch:
Eth R&D Discord thread with more details here: https://discord.com/channels/595666850260713488/892088344438255616/1093963476948496455
Note, I have not noticed any other CL behaving like this, all FCU replays I've seen have the same Withdrawal amounts.
Note geth added withdrawals to payloadId
ethereum/go-ethereum#26554
It appears nethermind may have behave the same as besu and therefore also have this bug (in combination with nimbus):
https://github.com/NethermindEth/nethermind/blob/4407c97970e4e392d014f5fdfb5f7773244530d4/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PayloadPreparationService.cs#L77-L89
https://github.com/NethermindEth/nethermind/blob/e4a91624f63ad9f97cc93762da0969f250ab62fc/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PayloadPreparationService.cs#L226-L235
It's not clear from the spec whether FCU(2) should be different to FCU(1) but it seems reasonable for besu to include withdrawals in the payloadId anyway.