-
Notifications
You must be signed in to change notification settings - Fork 0
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
fix: registrar key/list update race condition #22
Conversation
LCOV of commit
|
Changes to gas cost
🧾 Summary (20% most significant diffs)
Full diff report 👇
|
Why are idempotent actions being sequenced? Without sequencing, the possibility of "unordered" messages is that some messages would need to be resent in order for Spoke value to converge on the Hub values. Now, with sequencing, the possibility of "unordered" messages is that some messages would need to be resent in order for Spoke value to converge on the Hub values. And it's worse because, without sequencing, all messages arrive. Now with sequencing, if the last message arrives first (mistake or abuse), all other messages silently fail and need to be resent (costing more gas). I believe this is a suboptimal solution to a non-problem, that actually creates more problems. |
@deluca-mike it's not idempotent if values in the Registrar on the Hub were updated. |
Idempotent means that a message or action on its own will always result in the same outcome. If the current value on the hub goes from X to Y, the message to set the spoke value to X will set the spoke value to X, and the message to set the spoke value to Y will set the spoke value to Y, regardless how many times they are processed, respectively or together. The wormhole messages themselves are unique and cannot be reprocessed, but the valid actions/intents are idempotent. An old lingering message to set the spoke value to X when the hub's current value is Y:
With sequencing, batches of messages being unordered:
So the problem is "Bob's wormhole message to set himself as an earner, that was created before the registrar was updated to disable him as an earner, but was not yet processed, got processed after the message to disable Bob as an earner is both created and processed". It could be solved on a case-by-case basis by simply having anybody resend the message to remove Bob from the earners list. Sequencing solves this rare problem, but now creates problems that are more likely to occur, and will result in more need to replay messages. It would be frustrating, costly, and more likely when sending five messages to enable five earners at the spoke resulted in four of them failing because the last one got processed first. Perhaps the nonces should be tied to individual index actions or registrar key values (i.e. a mapping of nonces where the key is the action or registrar key) so that a handful of completely irrelevant messages don't get invalidated because of one. Edit: I just read Kirill's audit, and this is exactly what he suggests "Consider caching the last message sequence for each particular registrar key". |
src/SpokePortal.sol
Outdated
|
||
IRegistrarLike(registrar).setKey(key_, value_); | ||
// Update the key only if the incoming message has the higher sequence or is the fist 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.
// Update the key only if the incoming message has the higher sequence or is the fist message | |
// Update the key only if the incoming message has the higher sequence or is the first message |
src/SpokePortal.sol
Outdated
} else { | ||
IRegistrarLike(registrar).removeFromList(listName_, account_); | ||
uint64 lastUpdateListSequence_ = lastUpdateListSequence; | ||
// Update the status only if the incoming message has the higher sequence or is the fist 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.
// Update the status only if the incoming message has the higher sequence or is the fist message | |
// Update the status only if the incoming message has the higher sequence or is the first 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.
Some architecture decisions needs to be approved
- one sequence variable can be used for all messages with custom payload. It will allow to avoid basic copy-paste
- emission of events when registrar keys are actually updated. Right now there is no way to see from event logs if value was only received or received and set
I've cleaned up the implementation by using only one |
Proposed changes
HubPortal
.SpokePortal
and update Registrar Key and Registrar List Status only if the incoming sequence is greater than the current one to prevent race condition as Wormhole Relayer doesn't enforce message ordering. Kirill L-03 and AR M-01