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

[EFM] Recoverable Random Beacon State Machine follow up updates #6815

Open
wants to merge 11 commits into
base: feature/efm-recovery
Choose a base branch
from

Conversation

durkmurder
Copy link
Member

@durkmurder durkmurder commented Dec 13, 2024

Context

This PR addresses some open comments from PR #6771.
Specifically:

By far the biggest change is how we insert/upsert keys, now caller needs to provide evidence in form of EpochCommit so state machine can sanity check if it's inserting a valid private key.

@codecov-commenter
Copy link

codecov-commenter commented Dec 13, 2024

Codecov Report

Attention: Patch coverage is 45.94595% with 60 lines in your changes missing coverage. Please review.

Project coverage is 41.72%. Comparing base (cbb9053) to head (b953a43).

Files with missing lines Patch % Lines
storage/badger/dkg_state.go 58.22% 23 Missing and 10 partials ⚠️
storage/mock/dkg_state.go 0.00% 12 Missing ⚠️
cmd/consensus/main.go 0.00% 6 Missing ⚠️
engine/consensus/dkg/reactor_engine.go 44.44% 4 Missing and 1 partial ⚠️
storage/mock/epoch_recovery_my_beacon_key.go 0.00% 4 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                  @@
##           feature/efm-recovery    #6815   +/-   ##
=====================================================
  Coverage                 41.71%   41.72%           
=====================================================
  Files                      2033     2033           
  Lines                    181062   181153   +91     
=====================================================
+ Hits                      75529    75578   +49     
- Misses                    99311    99346   +35     
- Partials                   6222     6229    +7     
Flag Coverage Δ
unittests 41.72% <45.94%> (+<0.01%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@durkmurder durkmurder marked this pull request as ready for review December 17, 2024 14:29

// start up the engine
unittest.AssertClosesBefore(suite.T(), suite.engine.Ready(), time.Second)
unittest.AssertClosesBefore(suite.T(), suite.engine.Ready(), 100*time.Second)
Copy link
Member

Choose a reason for hiding this comment

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

Is it really not starting up within a second? 100s seems like a lot.. Maybe 5s or 10s?

// verify that the key is part of the EpochCommit
if err = ensureKeyIncludedInEpoch(epochCounter, key, commit); err != nil {
return storage.NewInvalidDKGStateTransitionErrorf(currentState, flow.RandomBeaconKeyCommitted,
"previously storred key has not been found in epoch commit event: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"previously storred key has not been found in epoch commit event: %w", err)
"previously stored key has not been found in epoch commit event: %w", err)

// CommitMyBeaconPrivateKey commits the previously inserted random beacon private key for an epoch.
// Effectively, this method transitions the state machine into the [flow.RandomBeaconKeyCommitted] state if the current state is [flow.DKGStateCompleted].
// Caller needs to supply the [flow.EpochCommit] which is an evidence that the key has been indeed included for the given epoch.
// No errors are expected during normal operations.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// No errors are expected during normal operations.
// If the current state is already [flow.RandomBeaconKeyCommitted], this function is a no-op regardless of input.
// No errors are expected during normal operations.

Describing the behaviour on line 238.

Copy link
Member

Choose a reason for hiding this comment

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

regarding Jordan's suggestion:

If the current state is already [flow.RandomBeaconKeyCommitted], this function is a no-op regardless of input.

This is probably the most minimal implementation, but I am not sure it would be the most robust. I think there are two non-happy path scenarios I think we should consider for the CommitMyBeaconPrivateKey:

  1. A random beacon key was previously committed (i.e. we are in the flow.RandomBeaconKeyCommitted state). If there is a call to CommitMyBeaconPrivateKey with an flow.EpochCommit that is inconsistent with the committed key, we have a clear failure condition.
  2. A random beacon key was previously committed (i.e. we are in the flow.RandomBeaconKeyCommitted state). The state machine receives a call to CommitMyBeaconPrivateKey with an flow.EpochCommit that is consistent with the committed key. Here, we could either return an exception and say that repeated calls are in principle not allowed. Alternatively, we can treat this call as confirming information that the state machine already has and ignore this call (as information is idempotent). The latter is my preference.

What makes me nervous is taking the response strategy for 2. and also applying it to 1., because we would be proceeding in a clear failure case. I think it would be comparatively easy to be more strict in this case.

@@ -344,9 +515,16 @@ func TestDKGState_RandomBeaconKeyCommittedState(t *testing.T) {
store, err := NewRecoverableRandomBeaconStateMachine(metrics, db)
require.NoError(t, err)

var evidence *flow.EpochCommit
var pkey crypto.PrivateKey
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
var pkey crypto.PrivateKey
var privKey crypto.PrivateKey

Nitpick: avoiding just the "p" prefix (because public also starts with "p" 😄)

Comment on lines +522 to +527
pkey = unittest.StakingPrivKeyFixture()
evidence = unittest.EpochCommitFixture(func(commit *flow.EpochCommit) {
commit.Counter = epochCounter
commit.DKGParticipantKeys[0] = pkey.PublicKey()
})
err = store.UpsertMyBeaconPrivateKey(epochCounter, pkey, evidence)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
pkey = unittest.StakingPrivKeyFixture()
evidence = unittest.EpochCommitFixture(func(commit *flow.EpochCommit) {
commit.Counter = epochCounter
commit.DKGParticipantKeys[0] = pkey.PublicKey()
})
err = store.UpsertMyBeaconPrivateKey(epochCounter, pkey, evidence)
privKey = unittest.StakingPrivKeyFixture()
evidence = unittest.EpochCommitFixture(func(commit *flow.EpochCommit) {
commit.Counter = epochCounter
commit.DKGParticipantKeys[0] = privKey.PublicKey()
})
err = store.UpsertMyBeaconPrivateKey(epochCounter, privKey, evidence)

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.

4 participants