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

fix: Add entropy to counter CRDT type updates #2186

Merged

Conversation

fredcarle
Copy link
Collaborator

Relevant issue(s)

Resolves #2179

Description

Counters need to be incrementable independently from different nodes. Initially, if two nodes incremented by the same amount from the same synced state, then the update CID would be the same and thus taken as a the same operation when syncing. So starting from 10 if both node A and B increment by 5 simultaneously, because they would generate the same CID for the update, the end result would be 15. We want it to be 20.

This PR adds entropy to the PN Counter delta so that a situation like described above would result in 20.

Note that the entropy is only added on update so that a document can be instantiated on multiple nodes with exactly the same CID.

Tasks

  • I made sure the code is well commented, particularly hard-to-understand areas.
  • I made sure the repository-held documentation is changed accordingly.
  • I made sure the pull request title adheres to the conventional commit style (the subset used in the project can be found in tools/configs/chglog/config.yml).
  • I made sure to discuss its limitations such as threats to validity, vulnerability to mistake and misuse, robustness to invalidation of assumptions, resource requirements, ...

How has this been tested?

make test

Specify the platform(s) on which this was tested:

  • MacOS

@fredcarle fredcarle added the area/crdt Related to the (Merkle) CRDT system label Jan 10, 2024
@fredcarle fredcarle added this to the DefraDB v0.9 milestone Jan 10, 2024
@fredcarle fredcarle requested a review from a team January 10, 2024 18:55
@fredcarle fredcarle self-assigned this Jan 10, 2024
@fredcarle fredcarle changed the title fix: add entropy to counter CRDT type updates fix: Add entropy to counter CRDT type updates Jan 10, 2024
func (reg PNCounter[T]) Increment(ctx context.Context, value T) (*PNCounterDelta[T], error) {
// To ensure that the dag block is unique, we add a random number to the delta.
// This is done only on update (if the doc doesn't already exist) to ensure that the
// initial dag block of a document can be reproducible.
Copy link
Contributor

Choose a reason for hiding this comment

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

praise: Good catch :)

question: Do we have any tests that target this and ensure that the docID is consistent (e.g. by hard coding it in the test)? If not, please consider this a todo :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Should have read first, there are tests that cover this, but they are complicated by cids and updates. Can you please add a simple one that makes it clear why such a test is needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If the docID wasn't consistent, the updates wouldn't sync over P2P.

Copy link
Contributor

Choose a reason for hiding this comment

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

True :) Thanks for pointing out

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm adding a docID assertion on the mutation create test just to make it more obvious.

Copy link
Contributor

@AndrewSisley AndrewSisley left a comment

Choose a reason for hiding this comment

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

LGTM, one test todo first before merge though please :)

Copy link

codecov bot commented Jan 10, 2024

Codecov Report

Attention: 9 lines in your changes are missing coverage. Please review.

Comparison is base (2953a28) 74.16% compared to head (c7399bc) 74.28%.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2186      +/-   ##
===========================================
+ Coverage    74.16%   74.28%   +0.13%     
===========================================
  Files          256      256              
  Lines        25479    25497      +18     
===========================================
+ Hits         18894    18940      +46     
+ Misses        5292     5271      -21     
+ Partials      1293     1286       -7     
Flag Coverage Δ
all-tests 74.28% <57.14%> (+0.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
merkle/crdt/pncounter.go 68.42% <25.00%> (-12.83%) ⬇️
core/crdt/pncounter.go 57.28% <64.71%> (+0.46%) ⬆️

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

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

@@ -45,6 +48,9 @@ type PNCounterDelta[T Incrementable] struct {
DocID []byte
FieldName string
Priority uint64
// Entropy is an added randomly generated number that ensures
// that each increment operation is unique.
Entropy int64
Copy link
Member

Choose a reason for hiding this comment

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

todo: Lets rename this to Nonce as its more cryptographically accurate, and slightly more common

Copy link
Contributor

Choose a reason for hiding this comment

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

Lol... Whoever introduced that to crypto was probably not British... It is not very polite. If it is only slightly more common I'd suggest sticking with Entropy.

Copy link
Member

Choose a reason for hiding this comment

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

FWIW nonce is fairly common in the cryptography world, so I have a slight pref for it.

return nil, err
}
var entropy int64
if exists {
Copy link
Member

Choose a reason for hiding this comment

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

question: When creating a new PNCounter field, this is going to produce an entropy value of 0. Is this intended? Or do we want to omit the entropy field entirely when creating? (IE: not include in the cbor marshal)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is indeed intended. Instead of having a different struct for create vs update, using 0 gives us the same result with less complexity.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A clarification. The entropy will be 0 only when creating the document.

@fredcarle fredcarle force-pushed the fredcarle/fix/I2179-counter-entropy branch 2 times, most recently from f5b6019 to 1485530 Compare January 10, 2024 22:32
Copy link
Member

@shahzadlone shahzadlone left a comment

Choose a reason for hiding this comment

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

Neat fix, LGTM

@fredcarle fredcarle force-pushed the fredcarle/fix/I2179-counter-entropy branch from 472dc2c to c7399bc Compare January 12, 2024 15:22
@fredcarle fredcarle merged commit 31a2988 into sourcenetwork:develop Jan 12, 2024
30 of 31 checks passed
@fredcarle fredcarle deleted the fredcarle/fix/I2179-counter-entropy branch January 12, 2024 15:53
shahzadlone pushed a commit to shahzadlone/defradb that referenced this pull request Jan 22, 2024
## Relevant issue(s)

Resolves sourcenetwork#2179 

## Description

Counters need to be incrementable independently from different nodes.
Initially, if two nodes incremented by the same amount from the same
synced state, then the update CID would be the same and thus taken as a
the same operation when syncing. So starting from 10 if both node A and
B increment by 5 simultaneously, because they would generate the same
CID for the update, the end result would be 15. We want it to be 20.

This PR adds entropy to the PN Counter delta so that a situation like
described above would result in 20.

Note that the entropy is only added on update so that a document can be
instantiated on multiple nodes with exactly the same CID.
shahzadlone pushed a commit to shahzadlone/defradb that referenced this pull request Feb 23, 2024
## Relevant issue(s)

Resolves sourcenetwork#2179 

## Description

Counters need to be incrementable independently from different nodes.
Initially, if two nodes incremented by the same amount from the same
synced state, then the update CID would be the same and thus taken as a
the same operation when syncing. So starting from 10 if both node A and
B increment by 5 simultaneously, because they would generate the same
CID for the update, the end result would be 15. We want it to be 20.

This PR adds entropy to the PN Counter delta so that a situation like
described above would result in 20.

Note that the entropy is only added on update so that a document can be
instantiated on multiple nodes with exactly the same CID.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/crdt Related to the (Merkle) CRDT system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Concurrent PNCounter is unpredictable over P2P
4 participants