Skip to content
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

Merged
merged 7 commits into from
Jan 13, 2023
Merged

Allow for out of order nonce #2710

merged 7 commits into from
Jan 13, 2023

Conversation

cyberj0g
Copy link
Contributor

@cyberj0g cyberj0g commented Jan 5, 2023

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.

@@ -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 {
Copy link
Contributor

@thomshutt thomshutt Jan 5, 2023

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

Copy link
Contributor Author

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.

Copy link
Contributor

@thomshutt thomshutt left a 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)
Copy link
Member

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)
Copy link
Member

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() {
Copy link
Member

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.

@Quintendos
Copy link

Ivan to fix up Yondon's comments and then ready to merge.

@cyberj0g
Copy link
Contributor Author

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
Copy link

codecov bot commented Jan 12, 2023

Codecov Report

Merging #2710 (d5a364f) into master (a5606ca) will increase coverage by 0.01598%.
The diff coverage is 100.00000%.

❗ Current head d5a364f differs from pull request most recent head c6237ae. Consider uploading reports for the commit c6237ae to get more accurate results

Impacted file tree graph

@@                 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                 
Impacted Files Coverage Δ
pm/recipient.go 89.95633% <100.00000%> (+0.31669%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a5606ca...c6237ae. Read the comment docs.

Impacted Files Coverage Δ
pm/recipient.go 89.95633% <100.00000%> (+0.31669%) ⬆️

Copy link
Member

@yondonfu yondonfu left a 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]
Copy link
Member

@yondonfu yondonfu Jan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
Copy link
Member

@yondonfu yondonfu Jan 12, 2023

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.

pm/recipient.go Outdated Show resolved Hide resolved
@cyberj0g cyberj0g merged commit 11af0a6 into master Jan 13, 2023
@cyberj0g cyberj0g deleted the ip/fix-sender-nonce branch January 13, 2023 08:22
@yondonfu yondonfu mentioned this pull request May 31, 2023
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tons of Invalid Ticket senderNonce for the past few months
4 participants