-
Notifications
You must be signed in to change notification settings - Fork 177
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
Allow for out of order nonce #2710
Conversation
pm/recipient_test.go
Outdated
@@ -224,8 +225,8 @@ func TestReceiveTicket_ValidNonWinningTicket(t *testing.T) { | |||
recipientRand := genRecipientRand(sender, secret, params) | |||
senderNonce := r.(*recipient).senderNonces[recipientRand.String()] | |||
|
|||
if senderNonce.nonce != newSenderNonce { | |||
t.Errorf("expected senderNonce to be %d, got %d", newSenderNonce, senderNonce.nonce) | |||
if senderNonce.Front().Key != newSenderNonce { |
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 probably me misunderstanding, but I'd expect this be .Back()
to look at the most recent one
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.
Right, Back()
would be most recent nonce, but in this test we test only one ticket anyway.
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, probably good to wait for Yondon's approval too since he originally documented this issue
pm/recipient.go
Outdated
r.senderNonces[randStr].Set(ticket.SenderNonce, ticket.ParamsExpirationBlock) | ||
// delete first seen nonce, if ordered map exceeds max size | ||
if r.senderNonces[randStr].Len() > maxSenderNonces { | ||
r.senderNonces[randStr].Delete(r.senderNonces[randStr].Front().Key) |
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.
Seems simpler to just return an error if the max size is hit. If we delete the first seen nonce, then that means that in theory B could re-use that deleted nonce after the max size is hit and if we return an error if the max size is hit we at least wouldn't need to reason about this scenario. This would mean that once the max size is hit, B would need a new set of ticket params with a fresh recipientRandHash
, but as mentioned in the original issue at the moment this should happen after B receives a response for each transcoded segment.
If we don't need to delete the first seen senderNonce value I think that would also simplify the data struct impl s.t. we might not need to depend on the custom ordered map package.
WDYT?
pm/recipient.go
Outdated
r.senderNonces[randStr] = orderedmap.NewOrderedMap() | ||
} | ||
// add new nonce | ||
r.senderNonces[randStr].Set(ticket.SenderNonce, ticket.ParamsExpirationBlock) |
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 don't think we need to track an expiration block per senderNonce - we only need to track an expiration block per recipientRandHash (aka randStr
in this function). And we only need to track seen senderNonce values associated with a particular recipientRandHash until that recipientRandHash expires.
I think this would simplify the state tracking since we can track an expiration block per recipientRandHash instead of an expiration block for every senderNonce value. With the current impl I think the map ends up looking like { key: 1 value: X, key: 2 value: X, key 3 value: X }
.
pm/recipient.go
Outdated
if sn.expirationBlock.Cmp(latestL1Block) <= 0 { | ||
delete(r.senderNonces, recipientRand) | ||
for recipientRand, nonceMap := range r.senderNonces { | ||
for _, key := range nonceMap.Keys() { |
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.
If we track a single expiration block per recipientRandHash then we wouldn't need the nested loop here and instead could just clear all senderNonce values for the recipientRandHash once the expirationBlock is reached.
Ivan to fix up Yondon's comments and then ready to merge. |
07b1a3a
to
d3a7d7d
Compare
Thanks for reviews @yondonfu @thomshutt, if we don't want FIFO and don't need to track expiration block number per nonce, that makes the logic simpler and removes sorted hash map dependency. I still used map instead of slice to have O(1) retrieval. |
Codecov Report
@@ Coverage Diff @@
## master #2710 +/- ##
===================================================
+ Coverage 56.33265% 56.34863% +0.01598%
===================================================
Files 88 88
Lines 19131 19138 +7
===================================================
+ Hits 10777 10784 +7
Misses 7765 7765
Partials 589 589
Continue to review full report at Codecov.
|
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.
Left a few nits. Feel free to address prior to merging.
Other than that LGTM.
pm/recipient.go
Outdated
sn, ok := r.senderNonces[randStr] | ||
if ok && ticket.SenderNonce <= sn.nonce { | ||
return errors.Errorf("invalid ticket senderNonce sender=%v nonce=%v highest=%v", ticket.Sender.Hex(), ticket.SenderNonce, sn.nonce) | ||
senderNonce, randKeySeen := r.senderNonces[randStr] |
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.
senderNonce, randKeySeen := r.senderNonces[randStr] | |
senderNonces, randKeySeen := r.senderNonces[randStr] |
Nit: The plural feels a bit clearer here since the map is tracking a collection of nonces as opposed to a single one.
pm/recipient.go
Outdated
@@ -86,7 +89,7 @@ type recipient struct { | |||
maxfacevalue *big.Int | |||
|
|||
senderNonces map[string]*struct { | |||
nonce uint32 | |||
nonceSeen map[uint32]byte |
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.
Nit: Is there an advantage of using byte
here instead of a bool
?
IIUC a bool
should be 1 byte which would be the same size as a byte
[1] so I don't think there are any storage benefits of using byte
. If this is the case, I suggest using a bool
as I think using true/false values will be clearer for code readability than using 0/1.
[1] Can verify using unsafe.Sizeof()
on a bool
var and a byte
var.
734de92
to
fc436be
Compare
Implementation of #2661 to fix #2614 based on introducing sorted hash map to store seen nonce values. Also added @yondonfu's test from corresponding branch, which now passes.