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

InitialProtocolState refactor and epoch protocol sub-state rename #5968

Merged
merged 27 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f8fffbb
move InitialProtocolState into DynProtoState
jordanschalm May 22, 2024
e348c38
rm InitialProtocolState
jordanschalm May 22, 2024
7930a65
rename DynamicProtocolState to EpochProtocolState
jordanschalm May 22, 2024
788e885
remove commented ByEpoch method
jordanschalm May 22, 2024
7edd829
rename test suite, adapter
jordanschalm May 22, 2024
cb6001d
rename dynamic_protocol_state files
jordanschalm May 22, 2024
9b79f69
renaming adapter references, vars
jordanschalm May 22, 2024
33d4945
rename epoch protocol state typed vars
jordanschalm May 22, 2024
d8d2b9f
remove initial protocol state files
jordanschalm May 22, 2024
287fd54
rename (Rich)ProtocolStateEntry
jordanschalm May 22, 2024
b4bd80a
rename storage.ProtocolState
jordanschalm May 22, 2024
b0c5ba4
rename ProtocolState.ByBlockID
jordanschalm May 22, 2024
f23b53e
update mocks
jordanschalm May 22, 2024
763a663
fix mock names in tests
jordanschalm May 22, 2024
0dd09d6
add missing godoc
jordanschalm May 22, 2024
ceb3d66
Merge branch 'master' into jord/initial-proto-state-refactor
jordanschalm May 28, 2024
a36e111
Apply suggestions from code review
jordanschalm May 28, 2024
007927b
rename RichEpochProtocolStateEntry comments, constructor, etc.
jordanschalm May 28, 2024
ff0831c
EpochProtocolState interface updates
jordanschalm May 28, 2024
a360767
rename EpochProtocolStateFromServiceEvents
jordanschalm May 28, 2024
8cdfb26
rename RootEpochProtocolStateFixture
jordanschalm May 28, 2024
4600168
update epoch protocol state naming in storage layer
jordanschalm May 28, 2024
59bef12
EpochProtocolStateEntries godoc
jordanschalm May 28, 2024
242f699
rename EpochProtocolStateEntries in all.go
jordanschalm May 28, 2024
0af615c
update mocks
jordanschalm May 28, 2024
e3a9664
Update storage/badger/epoch_protocol_state.go
jordanschalm May 28, 2024
3cc4dde
Update state/protocol/inmem/epoch_protocol_state.go
jordanschalm May 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion consensus/integration/epoch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func withNextEpoch(
}
// Re-construct epoch protocol state with modified events (constructs ActiveIdentity fields)
epochProtocolState, err = flow.NewRichProtocolStateEntry(
epochProtocolState.ProtocolStateEntry,
epochProtocolState.EpochProtocolStateEntry,
epochProtocolState.PreviousEpochSetup, epochProtocolState.PreviousEpochCommit,
currEpochSetup, currEpochCommit,
nextEpochSetup, nextEpochCommit)
Expand Down
2 changes: 1 addition & 1 deletion engine/testutil/mock/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type GenericNode struct {
Results storage.ExecutionResults
Setups storage.EpochSetups
EpochCommits storage.EpochCommits
EpochProtocolState storage.ProtocolState
EpochProtocolState storage.EpochProtocolStateEntries
ProtocolKVStore storage.ProtocolKVStore
State protocol.ParticipantState
Index storage.Index
Expand Down
58 changes: 29 additions & 29 deletions model/flow/protocol_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type DynamicIdentityEntry struct {

type DynamicIdentityEntryList []*DynamicIdentityEntry

// ProtocolStateEntry represents a snapshot of the identity table (incl. the set of all notes authorized to
// EpochProtocolStateEntry represents a snapshot of the identity table (incl. the set of all notes authorized to
// be part of the network) at some point in time. It allows to reconstruct the state of identity table using
// epoch setup events and dynamic identities. It tracks attempts of invalid state transitions.
// It also holds information about the next epoch, if it has been already committed.
Expand All @@ -23,7 +23,7 @@ type DynamicIdentityEntryList []*DynamicIdentityEntry
// Note that the current implementation does not store the identity table directly. Instead, we store
// the original events that constituted the _initial_ identity table at the beginning of the epoch
// plus some modifiers. We intend to restructure this code soon.
type ProtocolStateEntry struct {
type EpochProtocolStateEntry struct {
PreviousEpoch *EpochStateContainer // minimal dynamic properties for previous epoch [optional, nil for first epoch after spork, genesis]
CurrentEpoch EpochStateContainer // minimal dynamic properties for current epoch
NextEpoch *EpochStateContainer // minimal dynamic properties for next epoch [optional, nil iff we are in staking phase]
Expand Down Expand Up @@ -93,9 +93,9 @@ func (c *EpochStateContainer) Copy() *EpochStateContainer {
}
}

// RichProtocolStateEntry is a ProtocolStateEntry which has additional fields that are cached
// RichEpochProtocolStateEntry is a EpochProtocolStateEntry which has additional fields that are cached
// from storage layer for convenience.
// Using this structure instead of ProtocolStateEntry allows us to avoid querying
// Using this structure instead of EpochProtocolStateEntry allows us to avoid querying
// the database for epoch setups and commits and full identity table.
// It holds several invariants, such as:
// - CurrentEpochSetup and CurrentEpochCommit are for the same epoch. Never nil.
Expand All @@ -111,8 +111,8 @@ func (c *EpochStateContainer) Copy() *EpochStateContainer {
// the Identity Table additionally contains nodes (with weight zero) from the previous or
// upcoming epoch, which are transitioning into / out of the network and are only allowed
// to listen but not to actively contribute.
type RichProtocolStateEntry struct {
*ProtocolStateEntry
type RichEpochProtocolStateEntry struct {
*EpochProtocolStateEntry

PreviousEpochSetup *EpochSetup
PreviousEpochCommit *EpochCommit
Expand All @@ -127,16 +127,16 @@ type RichProtocolStateEntry struct {
// NewRichProtocolStateEntry constructs a rich protocol state entry from a protocol state entry and additional data.
// No errors are expected during normal operation. All errors indicate inconsistent or invalid inputs.
func NewRichProtocolStateEntry(
jordanschalm marked this conversation as resolved.
Show resolved Hide resolved
protocolState *ProtocolStateEntry,
protocolState *EpochProtocolStateEntry,
previousEpochSetup *EpochSetup,
previousEpochCommit *EpochCommit,
currentEpochSetup *EpochSetup,
currentEpochCommit *EpochCommit,
nextEpochSetup *EpochSetup,
nextEpochCommit *EpochCommit,
) (*RichProtocolStateEntry, error) {
result := &RichProtocolStateEntry{
ProtocolStateEntry: protocolState,
) (*RichEpochProtocolStateEntry, error) {
result := &RichEpochProtocolStateEntry{
EpochProtocolStateEntry: protocolState,
PreviousEpochSetup: previousEpochSetup,
PreviousEpochCommit: previousEpochCommit,
CurrentEpochSetup: currentEpochSetup,
Expand All @@ -147,22 +147,22 @@ func NewRichProtocolStateEntry(
NextEpochIdentityTable: IdentityList{},
}

// If previous epoch is specified: ensure respective epoch service events are not nil and consistent with commitments in `ProtocolStateEntry.PreviousEpoch`
// If previous epoch is specified: ensure respective epoch service events are not nil and consistent with commitments in `EpochProtocolStateEntry.PreviousEpoch`
if protocolState.PreviousEpoch != nil {
if protocolState.PreviousEpoch.SetupID != previousEpochSetup.ID() { // calling ID() will panic is EpochSetup event is nil
return nil, fmt.Errorf("supplied previous epoch's setup event (%x) does not match commitment (%x) in ProtocolStateEntry", previousEpochSetup.ID(), protocolState.PreviousEpoch.SetupID)
return nil, fmt.Errorf("supplied previous epoch's setup event (%x) does not match commitment (%x) in EpochProtocolStateEntry", previousEpochSetup.ID(), protocolState.PreviousEpoch.SetupID)
}
if protocolState.PreviousEpoch.CommitID != previousEpochCommit.ID() { // calling ID() will panic is EpochCommit event is nil
return nil, fmt.Errorf("supplied previous epoch's commit event (%x) does not match commitment (%x) in ProtocolStateEntry", previousEpochCommit.ID(), protocolState.PreviousEpoch.CommitID)
return nil, fmt.Errorf("supplied previous epoch's commit event (%x) does not match commitment (%x) in EpochProtocolStateEntry", previousEpochCommit.ID(), protocolState.PreviousEpoch.CommitID)
}
}

// For current epoch: ensure respective epoch service events are not nil and consistent with commitments in `ProtocolStateEntry.CurrentEpoch`
// For current epoch: ensure respective epoch service events are not nil and consistent with commitments in `EpochProtocolStateEntry.CurrentEpoch`
if protocolState.CurrentEpoch.SetupID != currentEpochSetup.ID() { // calling ID() will panic is EpochSetup event is nil
return nil, fmt.Errorf("supplied current epoch's setup event (%x) does not match commitment (%x) in ProtocolStateEntry", currentEpochSetup.ID(), protocolState.CurrentEpoch.SetupID)
return nil, fmt.Errorf("supplied current epoch's setup event (%x) does not match commitment (%x) in EpochProtocolStateEntry", currentEpochSetup.ID(), protocolState.CurrentEpoch.SetupID)
}
if protocolState.CurrentEpoch.CommitID != currentEpochCommit.ID() { // calling ID() will panic is EpochCommit event is nil
return nil, fmt.Errorf("supplied current epoch's commit event (%x) does not match commitment (%x) in ProtocolStateEntry", currentEpochCommit.ID(), protocolState.CurrentEpoch.CommitID)
return nil, fmt.Errorf("supplied current epoch's commit event (%x) does not match commitment (%x) in EpochProtocolStateEntry", currentEpochCommit.ID(), protocolState.CurrentEpoch.CommitID)
}

// If we are in staking phase (i.e. protocolState.NextEpoch == nil):
Expand Down Expand Up @@ -192,13 +192,13 @@ func NewRichProtocolStateEntry(
return nil, fmt.Errorf("could not build identity table for staking phase: %w", err)
}
} else { // protocolState.NextEpoch ≠ nil, i.e. we are in epoch setup or epoch commit phase
// ensure respective epoch service events are not nil and consistent with commitments in `ProtocolStateEntry.NextEpoch`
// ensure respective epoch service events are not nil and consistent with commitments in `EpochProtocolStateEntry.NextEpoch`
if nextEpoch.SetupID != nextEpochSetup.ID() {
return nil, fmt.Errorf("supplied next epoch's setup event (%x) does not match commitment (%x) in ProtocolStateEntry", nextEpoch.SetupID, nextEpochSetup.ID())
return nil, fmt.Errorf("supplied next epoch's setup event (%x) does not match commitment (%x) in EpochProtocolStateEntry", nextEpoch.SetupID, nextEpochSetup.ID())
}
if nextEpoch.CommitID != ZeroID {
if nextEpoch.CommitID != nextEpochCommit.ID() {
return nil, fmt.Errorf("supplied next epoch's commit event (%x) does not match commitment (%x) in ProtocolStateEntry", nextEpoch.CommitID, nextEpochCommit.ID())
return nil, fmt.Errorf("supplied next epoch's commit event (%x) does not match commitment (%x) in EpochProtocolStateEntry", nextEpoch.CommitID, nextEpochCommit.ID())
}
}

Expand Down Expand Up @@ -228,7 +228,7 @@ func NewRichProtocolStateEntry(
}

// ID returns hash of entry by hashing all fields.
func (e *ProtocolStateEntry) ID() Identifier {
func (e *EpochProtocolStateEntry) ID() Identifier {
if e == nil {
return ZeroID
}
Expand All @@ -248,11 +248,11 @@ func (e *ProtocolStateEntry) ID() Identifier {

// Copy returns a full copy of the entry.
// Embedded Identities are deep-copied, _except_ for their keys, which are copied by reference.
func (e *ProtocolStateEntry) Copy() *ProtocolStateEntry {
func (e *EpochProtocolStateEntry) Copy() *EpochProtocolStateEntry {
if e == nil {
return nil
}
return &ProtocolStateEntry{
return &EpochProtocolStateEntry{
PreviousEpoch: e.PreviousEpoch.Copy(),
CurrentEpoch: *e.CurrentEpoch.Copy(),
NextEpoch: e.NextEpoch.Copy(),
Expand All @@ -263,12 +263,12 @@ func (e *ProtocolStateEntry) Copy() *ProtocolStateEntry {
// Copy returns a full copy of rich protocol state entry.
// - Embedded service events are copied by reference (not deep-copied).
// - CurrentEpochIdentityTable and NextEpochIdentityTable are deep-copied, _except_ for their keys, which are copied by reference.
func (e *RichProtocolStateEntry) Copy() *RichProtocolStateEntry {
func (e *RichEpochProtocolStateEntry) Copy() *RichEpochProtocolStateEntry {
if e == nil {
return nil
}
return &RichProtocolStateEntry{
ProtocolStateEntry: e.ProtocolStateEntry.Copy(),
return &RichEpochProtocolStateEntry{
EpochProtocolStateEntry: e.EpochProtocolStateEntry.Copy(),
PreviousEpochSetup: e.PreviousEpochSetup,
PreviousEpochCommit: e.PreviousEpochCommit,
CurrentEpochSetup: e.CurrentEpochSetup,
Expand All @@ -281,8 +281,8 @@ func (e *RichProtocolStateEntry) Copy() *RichProtocolStateEntry {
}

// EpochPhase returns the current epoch phase.
// The receiver ProtocolStateEntry must be properly constructed.
func (e *ProtocolStateEntry) EpochPhase() EpochPhase {
// The receiver EpochProtocolStateEntry must be properly constructed.
func (e *EpochProtocolStateEntry) EpochPhase() EpochPhase {
// The epoch phase is determined by how much information we have about the next epoch
if e.NextEpoch == nil {
return EpochPhaseStaking // if no information about the next epoch is known, we are in the Staking Phase
Expand All @@ -295,8 +295,8 @@ func (e *ProtocolStateEntry) EpochPhase() EpochPhase {
}

// EpochCounter returns the current epoch counter.
// The receiver RichProtocolStateEntry must be properly constructed.
func (e *RichProtocolStateEntry) EpochCounter() uint64 {
// The receiver RichEpochProtocolStateEntry must be properly constructed.
func (e *RichEpochProtocolStateEntry) EpochCounter() uint64 {
return e.CurrentEpochSetup.Counter
}

Expand Down
20 changes: 10 additions & 10 deletions model/flow/protocol_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
Ejected: false,
})
}
stateEntry := &flow.ProtocolStateEntry{
stateEntry := &flow.EpochProtocolStateEntry{
PreviousEpoch: nil,
CurrentEpoch: flow.EpochStateContainer{
SetupID: setup.ID(),
Expand Down Expand Up @@ -65,7 +65,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
t.Run("staking-phase", func(t *testing.T) {
stateEntry := unittest.EpochStateFixture()
richEntry, err := flow.NewRichProtocolStateEntry(
stateEntry.ProtocolStateEntry,
stateEntry.EpochProtocolStateEntry,
stateEntry.PreviousEpochSetup,
stateEntry.PreviousEpochCommit,
stateEntry.CurrentEpochSetup,
Expand Down Expand Up @@ -93,13 +93,13 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
// * previous epoch N-1 is known (specifically EpochSetup and EpochCommit events)
// * network is currently in the setup phase for the next epoch, i.e. EpochSetup event (starting setup phase) has already been observed
t.Run("setup-phase", func(t *testing.T) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichProtocolStateEntry) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichEpochProtocolStateEntry) {
entry.NextEpochCommit = nil
entry.NextEpoch.CommitID = flow.ZeroID
})

richEntry, err := flow.NewRichProtocolStateEntry(
stateEntry.ProtocolStateEntry,
stateEntry.EpochProtocolStateEntry,
stateEntry.PreviousEpochSetup,
stateEntry.PreviousEpochCommit,
stateEntry.CurrentEpochSetup,
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
})

t.Run("setup-after-spork", func(t *testing.T) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichProtocolStateEntry) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichEpochProtocolStateEntry) {
// no previous epoch since we are in the first epoch
entry.PreviousEpochSetup = nil
entry.PreviousEpochCommit = nil
Expand All @@ -148,7 +148,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
assert.Nil(t, stateEntry.PreviousEpochCommit)

richEntry, err := flow.NewRichProtocolStateEntry(
stateEntry.ProtocolStateEntry,
stateEntry.EpochProtocolStateEntry,
stateEntry.PreviousEpochSetup,
stateEntry.PreviousEpochCommit,
stateEntry.CurrentEpochSetup,
Expand Down Expand Up @@ -188,7 +188,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState())

richEntry, err := flow.NewRichProtocolStateEntry(
stateEntry.ProtocolStateEntry,
stateEntry.EpochProtocolStateEntry,
stateEntry.PreviousEpochSetup,
stateEntry.PreviousEpochCommit,
stateEntry.CurrentEpochSetup,
Expand Down Expand Up @@ -220,7 +220,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
})

t.Run("commit-after-spork", func(t *testing.T) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichProtocolStateEntry) {
stateEntry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState(), func(entry *flow.RichEpochProtocolStateEntry) {
// no previous epoch since we are in the first epoch
entry.PreviousEpochSetup = nil
entry.PreviousEpochCommit = nil
Expand All @@ -232,7 +232,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
assert.Nil(t, stateEntry.PreviousEpochCommit)

richEntry, err := flow.NewRichProtocolStateEntry(
stateEntry.ProtocolStateEntry,
stateEntry.EpochProtocolStateEntry,
stateEntry.PreviousEpochSetup,
stateEntry.PreviousEpochCommit,
stateEntry.CurrentEpochSetup,
Expand Down Expand Up @@ -267,7 +267,7 @@ func TestNewRichProtocolStateEntry(t *testing.T) {
// TestProtocolStateEntry_Copy tests if the copy method returns a deep copy of the entry.
// All changes to copy shouldn't affect the original entry -- except for key changes.
func TestProtocolStateEntry_Copy(t *testing.T) {
entry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState()).ProtocolStateEntry
entry := unittest.EpochStateFixture(unittest.WithNextEpochProtocolState()).EpochProtocolStateEntry
cpy := entry.Copy()
assert.Equal(t, entry, cpy)
assert.NotSame(t, entry.NextEpoch, cpy.NextEpoch)
Expand Down
4 changes: 2 additions & 2 deletions model/flow/sealing_segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ type SealingSegment struct {
// per unique ProtocolStateID field within the segment's blocks.
// Currently, although epoch data is conceptually a part of the protocol data entry associated
// with each block, it is stored separately as a matter of technical debt (only a hash commitment
// `RichProtocolStateEntry.ID()` is stored within the `KVStoreEntry`.
// `RichEpochProtocolStateEntry.ID()` is stored within the `KVStoreEntry`.
//
// Deprecated: avoid using this in new code; this is a temporary measure until epoch data is moved into protocol KV store
// TODO: move epoch data into the KVStore as part of a future upgrade
type ProtocolStateEntryWrapper struct {
KVStore PSKeyValueStoreData
EpochEntry *RichProtocolStateEntry
EpochEntry *RichEpochProtocolStateEntry
}

// Highest is the highest block in the sealing segment and the reference block from snapshot that was
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -796,13 +796,13 @@ func (m *mockSnapshot) Identity(nodeID flow.Identifier) (*flow.Identity, error)
func (m *mockSnapshot) SealedResult() (*flow.ExecutionResult, *flow.Seal, error) {
return nil, nil, nil
}
func (m *mockSnapshot) Commit() (flow.StateCommitment, error) { return flow.DummyStateCommitment, nil }
func (m *mockSnapshot) SealingSegment() (*flow.SealingSegment, error) { return nil, nil }
func (m *mockSnapshot) Descendants() ([]flow.Identifier, error) { return nil, nil }
func (m *mockSnapshot) RandomSource() ([]byte, error) { return nil, nil }
func (m *mockSnapshot) Phase() (flow.EpochPhase, error) { return flow.EpochPhaseUndefined, nil }
func (m *mockSnapshot) Epochs() protocol.EpochQuery { return nil }
func (m *mockSnapshot) Params() protocol.GlobalParams { return nil }
func (m *mockSnapshot) EpochProtocolState() (protocol.DynamicProtocolState, error) { return nil, nil }
func (m *mockSnapshot) ProtocolState() (protocol.KVStoreReader, error) { return nil, nil }
func (m *mockSnapshot) VersionBeacon() (*flow.SealedVersionBeacon, error) { return nil, nil }
func (m *mockSnapshot) Commit() (flow.StateCommitment, error) { return flow.DummyStateCommitment, nil }
func (m *mockSnapshot) SealingSegment() (*flow.SealingSegment, error) { return nil, nil }
func (m *mockSnapshot) Descendants() ([]flow.Identifier, error) { return nil, nil }
func (m *mockSnapshot) RandomSource() ([]byte, error) { return nil, nil }
func (m *mockSnapshot) Phase() (flow.EpochPhase, error) { return flow.EpochPhaseUndefined, nil }
func (m *mockSnapshot) Epochs() protocol.EpochQuery { return nil }
func (m *mockSnapshot) Params() protocol.GlobalParams { return nil }
func (m *mockSnapshot) EpochProtocolState() (protocol.EpochProtocolState, error) { return nil, nil }
func (m *mockSnapshot) ProtocolState() (protocol.KVStoreReader, error) { return nil, nil }
func (m *mockSnapshot) VersionBeacon() (*flow.SealedVersionBeacon, error) { return nil, nil }
Loading
Loading