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

[Dynamic Protocol State] Protocol state used in FollowerState and ParticipantState #4613

Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
31b21f1
Partially integrated state mutator and state updater in FollowerState
durkmurder Aug 3, 2023
e4448c2
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 3, 2023
120caed
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 3, 2023
824ca0e
Updated FollowerState to use protocol state for processing service ev…
durkmurder Aug 4, 2023
8e6749b
Integrated protocol state into State and FollowerState.
durkmurder Aug 7, 2023
c6c45cf
Moved protocol state DB into State
durkmurder Aug 7, 2023
83a1975
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 7, 2023
f89b883
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 7, 2023
2f30d19
Updated Snapshot API to return protocol state. Updated mocks. Updated…
durkmurder Aug 7, 2023
85bb99e
Injected initial protocol state when bootstrapping. Updated how globa…
durkmurder Aug 8, 2023
56a41e1
Fixed cluster tests
durkmurder Aug 8, 2023
14b7d60
Allowed duplicated protocol states
durkmurder Aug 8, 2023
574ec0c
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 8, 2023
947d9bf
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 8, 2023
54e06ab
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 9, 2023
f0d2784
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 9, 2023
5169455
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 9, 2023
4931eb4
Updated protocol state to transition to next epoch as part of block p…
durkmurder Aug 9, 2023
538cb35
Updated initialization of storage components
durkmurder Aug 10, 2023
0ec6c9d
Updated other tests to compile
durkmurder Aug 10, 2023
24b91be
Fixed test setups
durkmurder Aug 10, 2023
7448a84
Added consistensy checks for rich epoch entry constructor. Updated tests
durkmurder Aug 10, 2023
e8ddf6e
Updated converting logic. Fixed tests.
durkmurder Aug 10, 2023
452c7cc
Linted
durkmurder Aug 10, 2023
4bab29f
Removed TODO
durkmurder Aug 10, 2023
1575990
Cleanup. Small refactoring. Godoc updates
durkmurder Aug 10, 2023
1943c0e
Merge branch 'yurii/6802-protocol-state-mutator' of https://github.co…
durkmurder Aug 11, 2023
331133b
Updated usages of Entry
durkmurder Aug 11, 2023
ea78cda
Updated tests
durkmurder Aug 11, 2023
9404402
Merge branch 'yurii/6802-protocol-state-mutator' into yurii/5514-exte…
jordanschalm Aug 24, 2023
f7efa37
Merge branch 'yurii/6802-protocol-state-mutator' into yurii/5514-exte…
jordanschalm Sep 7, 2023
79b2ebb
removed duplicated line in documentation
Sep 8, 2023
4a92bb7
Merge branch 'feature/dynamic-protocol-state' of https://github.com/o…
durkmurder Sep 11, 2023
5b3e65f
Applied suggestions regarding naming
durkmurder Sep 11, 2023
fb23b0d
Updated implementation of protocol state storage. Updated how changes…
durkmurder Sep 11, 2023
0295799
Reordered checks for handleEpochServiceEvents
durkmurder Sep 11, 2023
7027a7b
Removed snapshot strippening. Updated tests
durkmurder Sep 12, 2023
ffed810
Apply suggestions from code review
durkmurder Sep 12, 2023
66edbfa
Updated badger transaction utils
durkmurder Sep 12, 2023
f44720c
Updated how state params are implemented
durkmurder Sep 13, 2023
0e69fa5
Log cleanup for tests
durkmurder Sep 13, 2023
479da3d
Fixed last commit
durkmurder Sep 13, 2023
b4f3fa5
Fixed last commit
durkmurder Sep 13, 2023
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
6 changes: 4 additions & 2 deletions cmd/bootstrap/run/cluster_qc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import (

// GenerateClusterRootQC creates votes and generates a QC based on participant data
func GenerateClusterRootQC(signers []bootstrap.NodeInfo, allCommitteeMembers flow.IdentityList, clusterBlock *cluster.Block) (*flow.QuorumCertificate, error) {
if !allCommitteeMembers.Sorted(order.Canonical) {
return nil, fmt.Errorf("can't create root cluster QC: committee members are not sorted in canonical order")
}
clusterRootBlock := model.GenesisBlockFromFlow(clusterBlock.Header)

// STEP 1: create votes for cluster root block
Expand All @@ -29,8 +32,7 @@ func GenerateClusterRootQC(signers []bootstrap.NodeInfo, allCommitteeMembers flo
}

// STEP 2: create VoteProcessor
ordered := allCommitteeMembers.Sort(order.Canonical)
committee, err := committees.NewStaticCommittee(ordered, flow.Identifier{}, nil, nil)
committee, err := committees.NewStaticCommittee(allCommitteeMembers, flow.Identifier{}, nil, nil)
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/bootstrap/run/cluster_qc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
model "github.com/onflow/flow-go/model/bootstrap"
"github.com/onflow/flow-go/model/cluster"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/model/flow/order"
"github.com/onflow/flow-go/utils/unittest"
)

Expand All @@ -32,7 +33,8 @@ func TestGenerateClusterRootQC(t *testing.T) {
payload := cluster.EmptyPayload(flow.ZeroID)
clusterBlock.SetPayload(payload)

_, err := GenerateClusterRootQC(participants, model.ToIdentityList(participants), &clusterBlock)
orderedParticipants := model.ToIdentityList(participants).Sort(order.Canonical)
_, err := GenerateClusterRootQC(participants, orderedParticipants, &clusterBlock)
require.NoError(t, err)
}

Expand Down
6 changes: 4 additions & 2 deletions cmd/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ func (fnb *FlowNodeBuilder) initStorage() error {
epochCommits := bstorage.NewEpochCommits(fnb.Metrics.Cache, fnb.DB)
statuses := bstorage.NewEpochStatuses(fnb.Metrics.Cache, fnb.DB)
commits := bstorage.NewCommits(fnb.Metrics.Cache, fnb.DB)
protocolState := bstorage.NewProtocolState(fnb.Metrics.Cache, setups, epochCommits, fnb.DB, bstorage.DefaultCacheSize)
versionBeacons := bstorage.NewVersionBeacons(fnb.DB)

fnb.Storage = Storage{
Expand All @@ -996,6 +997,7 @@ func (fnb *FlowNodeBuilder) initStorage() error {
Setups: setups,
EpochCommits: epochCommits,
VersionBeacons: versionBeacons,
ProtocolState: protocolState,
Statuses: statuses,
Commits: commits,
}
Expand Down Expand Up @@ -1060,7 +1062,7 @@ func (fnb *FlowNodeBuilder) initState() error {
fnb.Storage.QuorumCertificates,
fnb.Storage.Setups,
fnb.Storage.EpochCommits,
fnb.Storage.Statuses,
fnb.Storage.ProtocolState,
fnb.Storage.VersionBeacons,
)
if err != nil {
Expand Down Expand Up @@ -1112,7 +1114,7 @@ func (fnb *FlowNodeBuilder) initState() error {
fnb.Storage.QuorumCertificates,
fnb.Storage.Setups,
fnb.Storage.EpochCommits,
fnb.Storage.Statuses,
fnb.Storage.ProtocolState,
fnb.Storage.VersionBeacons,
fnb.RootSnapshot,
options...,
Expand Down
2 changes: 1 addition & 1 deletion cmd/util/cmd/common/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func InitProtocolState(db *badger.DB, storages *storage.All) (protocol.State, er
storages.QuorumCertificates,
storages.Setups,
storages.EpochCommits,
storages.Statuses,
storages.ProtocolState,
storages.VersionBeacons,
)

Expand Down
22 changes: 22 additions & 0 deletions consensus/integration/epoch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/onflow/flow-go/model/flow/filter"
"github.com/onflow/flow-go/model/flow/mapfunc"
"github.com/onflow/flow-go/model/flow/order"
"github.com/onflow/flow-go/state/protocol"
"github.com/onflow/flow-go/state/protocol/inmem"
"github.com/onflow/flow-go/utils/unittest"
)
Expand Down Expand Up @@ -255,5 +256,26 @@ func withNextEpoch(
Map(mapfunc.WithWeight(0))...,
).Sort(order.Canonical)

// update protocol state
protocolState := encodableSnapshot.ProtocolState
// update protocol state identities since we are in committed phase
protocolState.Identities = flow.DynamicIdentityEntryListFromIdentities(encodableSnapshot.Identities)
// setup ID has changed, need to update it
convertedEpochSetup, _ := protocol.ToEpochSetup(inmem.NewEpoch(*currEpoch))
protocolState.CurrentEpochEventIDs.SetupID = convertedEpochSetup.ID()
// create next epoch protocol state
convertedEpochSetup, _ = protocol.ToEpochSetup(inmem.NewEpoch(*encodableSnapshot.Epochs.Next))
convertedEpochCommit, _ := protocol.ToEpochCommit(inmem.NewEpoch(*encodableSnapshot.Epochs.Next))
protocolState.NextEpochProtocolState = &flow.ProtocolStateEntry{
CurrentEpochEventIDs: flow.EventIDs{
SetupID: convertedEpochSetup.ID(),
CommitID: convertedEpochCommit.ID(),
},
PreviousEpochEventIDs: protocolState.CurrentEpochEventIDs,
Identities: flow.DynamicIdentityEntryListFromIdentities(encodableSnapshot.Identities),
InvalidStateTransitionAttempted: false,
NextEpochProtocolState: nil,
}

return inmem.SnapshotFromEncodable(encodableSnapshot)
}
4 changes: 2 additions & 2 deletions consensus/integration/nodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func createNode(
qcsDB := storage.NewQuorumCertificates(metricsCollector, db, storage.DefaultCacheSize)
setupsDB := storage.NewEpochSetups(metricsCollector, db)
commitsDB := storage.NewEpochCommits(metricsCollector, db)
statusesDB := storage.NewEpochStatuses(metricsCollector, db)
protocolStateDB := storage.NewProtocolState(metricsCollector, setupsDB, commitsDB, db, storage.DefaultCacheSize)
versionBeaconDB := storage.NewVersionBeacons(db)
protocolStateEvents := events.NewDistributor()

Expand All @@ -396,7 +396,7 @@ func createNode(
qcsDB,
setupsDB,
commitsDB,
statusesDB,
protocolStateDB,
versionBeaconDB,
rootSnapshot,
)
Expand Down
8 changes: 4 additions & 4 deletions engine/collection/test/cluster_switchover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/model/flow/factory"
"github.com/onflow/flow-go/model/flow/filter"
"github.com/onflow/flow-go/model/flow/order"
"github.com/onflow/flow-go/module"
"github.com/onflow/flow-go/module/util"
"github.com/onflow/flow-go/network/channels"
Expand Down Expand Up @@ -66,19 +67,18 @@ func NewClusterSwitchoverTestCase(t *testing.T, conf ClusterSwitchoverTestConf)
rootClusterQCs := make([]flow.ClusterQCVoteData, len(rootClusterBlocks))
for i, cluster := range clusters {
signers := make([]model.NodeInfo, 0)
signerIDs := make([]flow.Identifier, 0)
for _, identity := range nodeInfos {
if _, inCluster := cluster.ByNodeID(identity.NodeID); inCluster {
signers = append(signers, identity)
signerIDs = append(signerIDs, identity.NodeID)
}
}
qc, err := run.GenerateClusterRootQC(signers, model.ToIdentityList(signers), rootClusterBlocks[i])
signerIdentities := model.ToIdentityList(signers).Sort(order.Canonical)
qc, err := run.GenerateClusterRootQC(signers, signerIdentities, rootClusterBlocks[i])
require.NoError(t, err)
rootClusterQCs[i] = flow.ClusterQCVoteDataFromQC(&flow.QuorumCertificateWithSignerIDs{
View: qc.View,
BlockID: qc.BlockID,
SignerIDs: signerIDs,
SignerIDs: signerIdentities.NodeIDs(),
SigData: qc.SigData,
})
}
Expand Down
2 changes: 1 addition & 1 deletion engine/common/follower/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestFollowerHappyPath(t *testing.T) {
all.QuorumCertificates,
all.Setups,
all.EpochCommits,
all.Statuses,
all.ProtocolState,
all.VersionBeacons,
rootSnapshot,
)
Expand Down
2 changes: 1 addition & 1 deletion engine/testutil/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ func CompleteStateFixture(
s.QuorumCertificates,
s.Setups,
s.EpochCommits,
s.Statuses,
s.ProtocolState,
s.VersionBeacons,
rootSnapshot,
)
Expand Down
4 changes: 2 additions & 2 deletions integration/testnet/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func (c *Container) OpenState() (*state.State, error) {
qcs := storage.NewQuorumCertificates(metrics, db, storage.DefaultCacheSize)
setups := storage.NewEpochSetups(metrics, db)
commits := storage.NewEpochCommits(metrics, db)
statuses := storage.NewEpochStatuses(metrics, db)
protocolState := storage.NewProtocolState(metrics, setups, commits, db, storage.DefaultCacheSize)
versionBeacons := storage.NewVersionBeacons(db)

return state.OpenState(
Expand All @@ -403,7 +403,7 @@ func (c *Container) OpenState() (*state.State, error) {
qcs,
setups,
commits,
statuses,
protocolState,
versionBeacons,
)
}
Expand Down
37 changes: 30 additions & 7 deletions model/flow/protocol_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,32 +82,56 @@ func NewRichProtocolStateEntry(
NextEpochProtocolState: nil,
}

// ensure data is consistent
if protocolState.PreviousEpochEventIDs.SetupID != ZeroID {
if protocolState.PreviousEpochEventIDs.SetupID != previousEpochSetup.ID() {
return nil, fmt.Errorf("supplied previous epoch setup (%x) does not match protocol state (%x)",
previousEpochSetup.ID(),
protocolState.PreviousEpochEventIDs.SetupID)
}
if protocolState.PreviousEpochEventIDs.CommitID != previousEpochCommit.ID() {
return nil, fmt.Errorf("supplied previous epoch commit (%x) does not match protocol state (%x)",
previousEpochCommit.ID(),
protocolState.PreviousEpochEventIDs.CommitID)
}
}
if protocolState.CurrentEpochEventIDs.SetupID != currentEpochSetup.ID() {
return nil, fmt.Errorf("supplied current epoch setup (%x) does not match protocol state (%x)",
currentEpochSetup.ID(),
protocolState.CurrentEpochEventIDs.SetupID)
}
if protocolState.CurrentEpochEventIDs.CommitID != currentEpochCommit.ID() {
return nil, fmt.Errorf("supplied current epoch commit (%x) does not match protocol state (%x)",
currentEpochCommit.ID(),
protocolState.CurrentEpochEventIDs.CommitID)
}

var err error
nextEpochProtocolState := protocolState.NextEpochProtocolState
// if next epoch has been already committed, fill in data for it as well.
if protocolState.NextEpochProtocolState != nil {
if nextEpochProtocolState != nil {
// sanity check consistency of input data
if protocolState.NextEpochProtocolState.CurrentEpochEventIDs.SetupID != nextEpochSetup.ID() {
if nextEpochProtocolState.CurrentEpochEventIDs.SetupID != nextEpochSetup.ID() {
return nil, fmt.Errorf("inconsistent EpochSetup for constucting RichProtocolStateEntry, next protocol state states ID %v while input event has ID %v",
protocolState.NextEpochProtocolState.CurrentEpochEventIDs.SetupID, nextEpochSetup.ID())
}
if protocolState.NextEpochProtocolState.CurrentEpochEventIDs.CommitID != nextEpochCommit.ID() {
if nextEpochProtocolState.CurrentEpochEventIDs.CommitID != nextEpochCommit.ID() {
return nil, fmt.Errorf("inconsistent EpochCommit for constucting RichProtocolStateEntry, next protocol state states ID %v while input event has ID %v",
protocolState.NextEpochProtocolState.CurrentEpochEventIDs.CommitID, nextEpochCommit.ID())
}

// sanity check consistency of input data
if protocolState.NextEpochProtocolState.CurrentEpochEventIDs.SetupID != nextEpochSetup.ID() {
if nextEpochProtocolState.CurrentEpochEventIDs.SetupID != nextEpochSetup.ID() {
return nil, fmt.Errorf("inconsistent EpochSetup for constucting RichProtocolStateEntry, next protocol state states ID %v while input event has ID %v",
protocolState.NextEpochProtocolState.CurrentEpochEventIDs.SetupID, nextEpochSetup.ID())
}
if protocolState.NextEpochProtocolState.CurrentEpochEventIDs.CommitID != nextEpochCommit.ID() {
if nextEpochProtocolState.CurrentEpochEventIDs.CommitID != nextEpochCommit.ID() {
return nil, fmt.Errorf("inconsistent EpochCommit for constucting RichProtocolStateEntry, next protocol state states ID %v while input event has ID %v",
protocolState.NextEpochProtocolState.CurrentEpochEventIDs.CommitID, nextEpochCommit.ID())
}

// if next epoch is available, it means that we have observed epoch setup event and we are not anymore in staking phase,
// so we need to build the identity table using current and next epoch setup events.
// so we need to build the identity table using current and next epoch setup events.
result.Identities, err = buildIdentityTable(
protocolState.Identities,
currentEpochSetup.Participants,
Expand All @@ -117,7 +141,6 @@ func NewRichProtocolStateEntry(
return nil, fmt.Errorf("could not build identity table for setup/commit phase: %w", err)
}

nextEpochProtocolState := protocolState.NextEpochProtocolState
nextEpochIdentityTable, err := buildIdentityTable(
nextEpochProtocolState.Identities,
nextEpochSetup.Participants,
Expand Down
2 changes: 1 addition & 1 deletion module/builder/collection/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (suite *BuilderSuite) SetupTest() {
all.QuorumCertificates,
all.Setups,
all.EpochCommits,
all.Statuses,
all.ProtocolState,
all.VersionBeacons,
rootSnapshot,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -787,11 +787,12 @@ 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) 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) ProtocolState() (protocol.DynamicProtocolState, error) { return nil, nil }
func (m *mockSnapshot) VersionBeacon() (*flow.SealedVersionBeacon, error) { return nil, nil }
2 changes: 1 addition & 1 deletion state/cluster/badger/mutator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (suite *MutatorSuite) SetupTest() {
all.QuorumCertificates,
all.Setups,
all.EpochCommits,
all.Statuses,
all.ProtocolState,
all.VersionBeacons,
rootSnapshot,
)
Expand Down
2 changes: 1 addition & 1 deletion state/cluster/badger/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (suite *SnapshotSuite) SetupTest() {
all.QuorumCertificates,
all.Setups,
all.EpochCommits,
all.Statuses,
all.ProtocolState,
all.VersionBeacons,
root,
)
Expand Down
Loading