Skip to content

Commit 0a55604

Browse files
Merge pull request #7857 from onflow/UliananAndrukhiv/7837-consolidate-instance-params
Consolidate InstanceParams into one storage object
2 parents 10102f3 + ddb2e6c commit 0a55604

File tree

17 files changed

+413
-334
lines changed

17 files changed

+413
-334
lines changed

model/flow/protocol_state.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,3 +709,13 @@ func (d PSKeyValueStoreData) Equal(d2 *PSKeyValueStoreData) bool {
709709
return d.Version == d2.Version &&
710710
slices.Equal(d.Data, d2.Data)
711711
}
712+
713+
// VersionedInstanceParams is a binary instance params blob with a version attached, specifying the format
714+
// of the marshaled data. In a nutshell, it serves as a binary of an InstanceParams.
715+
// The VersionedInstanceParams is a generic format that can be later decoded to
716+
// potentially different strongly typed structures based on version. When reading from the store,
717+
// callers must know how to deal with the binary representation.
718+
type VersionedInstanceParams struct {
719+
Version uint64
720+
Data []byte
721+
}

module/builder/consensus/builder_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/onflow/flow-go/module/metrics"
2020
"github.com/onflow/flow-go/module/trace"
2121
realproto "github.com/onflow/flow-go/state/protocol"
22+
"github.com/onflow/flow-go/state/protocol/datastore"
2223
protocol "github.com/onflow/flow-go/state/protocol/mock"
2324
"github.com/onflow/flow-go/storage"
2425
storagemock "github.com/onflow/flow-go/storage/mock"
@@ -253,12 +254,20 @@ func (bs *BuilderSuite) SetupTest() {
253254
lockManager := storage.NewTestingLockManager()
254255
lctx := lockManager.NewContext()
255256
require.NoError(bs.T(), lctx.AcquireLock(storage.LockFinalizeBlock))
257+
require.NoError(bs.T(), lctx.AcquireLock(storage.LockBootstrapping))
256258
defer lctx.Release()
257259

258260
// insert finalized height and root height
259261
db := bs.db
260262
require.NoError(bs.T(), db.WithReaderBatchWriter(func(rw storage.ReaderBatchWriter) error {
261-
require.NoError(bs.T(), operation.InsertRootHeight(rw.Writer(), 13))
263+
enc, err := datastore.NewVersionedInstanceParams(
264+
datastore.DefaultInstanceParamsVersion,
265+
unittest.IdentifierFixture(),
266+
unittest.IdentifierFixture(),
267+
unittest.IdentifierFixture(),
268+
)
269+
require.NoError(bs.T(), err)
270+
require.NoError(bs.T(), operation.InsertInstanceParams(lctx, rw, *enc))
262271
require.NoError(bs.T(), operation.UpsertFinalizedHeight(lctx, rw.Writer(), final.Height))
263272
require.NoError(bs.T(), operation.IndexFinalizedBlockByHeight(lctx, rw, final.Height, bs.finalID))
264273
require.NoError(bs.T(), operation.UpsertSealedHeight(lctx, rw.Writer(), first.Height))

state/protocol/badger/params.go

Lines changed: 0 additions & 129 deletions
This file was deleted.

state/protocol/badger/state.go

Lines changed: 58 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ func Bootstrap(
120120
if err != nil {
121121
return nil, err
122122
}
123+
err = lctx.AcquireLock(storage.LockBootstrapping)
124+
if err != nil {
125+
return nil, err
126+
}
123127

124128
config := defaultBootstrapConfig()
125129
for _, opt := range options {
@@ -155,10 +159,6 @@ func Bootstrap(
155159
// (The lowest block in sealing segment is the last sealed block, but we don't use that here.)
156160
lastFinalized := segment.Finalized() // highest block in sealing segment; finalized by protocol convention
157161

158-
// The spork root block is always provided by a sealing segment separately. This is because the spork root block
159-
// may or may not be part of [SealingSegment.Blocks] depending on how much history the sealing segment covers.
160-
sporkRootBlock := segment.SporkRootBlock
161-
162162
// bootstrap the sealing segment
163163
// creating sealed root block with the rootResult
164164
// creating finalized root block with lastFinalized
@@ -168,12 +168,6 @@ func Bootstrap(
168168
}
169169

170170
err = db.WithReaderBatchWriter(func(rw storage.ReaderBatchWriter) error {
171-
// initialize spork params
172-
err = bootstrapSporkInfo(lctx, rw, blocks, sporkRootBlock)
173-
if err != nil {
174-
return fmt.Errorf("could not bootstrap spork info: %w", err)
175-
}
176-
177171
// bootstrap dynamic protocol state
178172
err = bootstrapProtocolState(lctx, rw, segment, root.Params(), epochProtocolStateSnapshots, protocolKVStoreSnapshots, setups, commits, !config.SkipNetworkAddressValidation)
179173
if err != nil {
@@ -287,6 +281,10 @@ func bootstrapProtocolState(
287281
// 4. For the highest seal (`rootSeal`), we index the sealed result ID in the database.
288282
// This is necessary for the execution node to confirm that it is starting to execute from the
289283
// correct state.
284+
// 5. persist the spork root block. This block is always provided separately in the sealing
285+
// segment, as it may or may not be included in SealingSegment.Blocks depending on how much
286+
// history is covered. The spork root block is persisted as a root proposal without proposer
287+
// signature (by convention).
290288
func bootstrapSealingSegment(
291289
lctx lockctx.Proof,
292290
db storage.DB,
@@ -475,6 +473,36 @@ func bootstrapSealingSegment(
475473
return err
476474
}
477475

476+
// STEP 5: PERSIST spork root block
477+
// The spork root block is always provided by a sealing segment separately. This is because the spork root block
478+
// may or may not be part of [SealingSegment.Blocks] depending on how much history the sealing segment covers.
479+
sporkRootBlock := segment.SporkRootBlock
480+
481+
// create the spork root proposal
482+
proposal, err := flow.NewRootProposal(
483+
flow.UntrustedProposal{
484+
Block: *sporkRootBlock,
485+
ProposerSigData: nil, // by protocol convention, the spork root block (or genesis block) don't have a proposer signature
486+
},
487+
)
488+
if err != nil {
489+
return fmt.Errorf("could not create root proposal for spork root block: %w", err)
490+
}
491+
492+
err = db.WithReaderBatchWriter(func(rw storage.ReaderBatchWriter) error {
493+
err = blocks.BatchStore(lctx, rw, proposal)
494+
if err != nil {
495+
// the spork root block may or may not have already been persisted, depending
496+
// on whether the root snapshot sealing segment contained it.
497+
if errors.Is(err, storage.ErrAlreadyExists) {
498+
return nil
499+
}
500+
return fmt.Errorf("could not store spork root block: %w", err)
501+
}
502+
503+
return nil
504+
})
505+
478506
return nil
479507
}
480508

@@ -485,6 +513,7 @@ func bootstrapSealingSegment(
485513
// - Sealed Root Block Height (block height sealed as of the Root Block)
486514
// - Latest Finalized Height (initialized to height of Root Block)
487515
// - Latest Sealed Block Height (initialized to block height sealed as of the Root Block)
516+
// - Spork root block ID (spork root block in sealing segment)
488517
// - initial entry in map:
489518
// Finalized Block ID -> ID of latest seal in fork with this block as head
490519
func bootstrapStatePointers(lctx lockctx.Proof, rw storage.ReaderBatchWriter, root protocol.Snapshot) error {
@@ -498,6 +527,21 @@ func bootstrapStatePointers(lctx lockctx.Proof, rw storage.ReaderBatchWriter, ro
498527
lastFinalized := segment.Finalized() // the lastFinalized block in sealing segment is the latest known finalized block
499528
lastSealed := segment.Sealed() // the lastSealed block in sealing segment is the latest known sealed block
500529

530+
enc, err := datastore.NewVersionedInstanceParams(
531+
datastore.DefaultInstanceParamsVersion,
532+
lastFinalized.ID(),
533+
lastSealed.ID(),
534+
root.Params().SporkID(),
535+
)
536+
if err != nil {
537+
return fmt.Errorf("could not create versioned instance params: %w", err)
538+
}
539+
540+
err = operation.InsertInstanceParams(lctx, rw, *enc)
541+
if err != nil {
542+
return fmt.Errorf("could not store instance params: %w", err)
543+
}
544+
501545
// find the finalized seal that seals the lastSealed block, meaning seal.BlockID == lastSealed.ID()
502546
seal, err := segment.FinalizedSeal()
503547
if err != nil {
@@ -558,15 +602,6 @@ func bootstrapStatePointers(lctx lockctx.Proof, rw storage.ReaderBatchWriter, ro
558602
}
559603

560604
// insert height pointers
561-
err = operation.InsertRootHeight(w, lastFinalized.Height)
562-
if err != nil {
563-
return fmt.Errorf("could not insert finalized root height: %w", err)
564-
}
565-
// the sealed root height is the lastSealed block in sealing segment
566-
err = operation.InsertSealedRootHeight(w, lastSealed.Height)
567-
if err != nil {
568-
return fmt.Errorf("could not insert sealed root height: %w", err)
569-
}
570605
err = operation.UpsertFinalizedHeight(lctx, w, lastFinalized.Height)
571606
if err != nil {
572607
return fmt.Errorf("could not insert finalized height: %w", err)
@@ -683,44 +718,6 @@ func bootstrapEpochForProtocolStateEntry(
683718
return nil
684719
}
685720

686-
// bootstrapSporkInfo bootstraps the protocol state with information about the
687-
// spork which is used to disambiguate Flow networks.
688-
func bootstrapSporkInfo(
689-
lctx lockctx.Proof,
690-
rw storage.ReaderBatchWriter,
691-
blocks storage.Blocks,
692-
sporkRootBlock *flow.Block,
693-
) error {
694-
// persist the ID of the spork root block
695-
sporkRootBlockID := sporkRootBlock.ID()
696-
err := operation.IndexSporkRootBlock(rw.Writer(), sporkRootBlockID)
697-
if err != nil {
698-
return fmt.Errorf("could not insert spork ID: %w", err)
699-
}
700-
701-
// store the spork root block
702-
proposal, err := flow.NewRootProposal(
703-
flow.UntrustedProposal{
704-
Block: *sporkRootBlock,
705-
ProposerSigData: nil, // by protocol convention, the spork root block (or genesis block) don't have a proposer signature
706-
},
707-
)
708-
if err != nil {
709-
return fmt.Errorf("could not create root proposal for spork root block: %w", err)
710-
}
711-
712-
err = blocks.BatchStore(lctx, rw, proposal)
713-
if err != nil {
714-
// the spork root block may or may not have already been persisted, depending
715-
// on whether the root snapshot sealing segment contained it.
716-
if errors.Is(err, storage.ErrAlreadyExists) {
717-
return nil
718-
}
719-
return fmt.Errorf("could not store spork root block: %w", err)
720-
}
721-
return nil
722-
}
723-
724721
// indexEpochHeights populates the epoch height index from the root snapshot.
725722
// We index the FirstHeight for every epoch where the transition occurs within the sealing segment of the root snapshot,
726723
// or for the first epoch of a spork if the snapshot is a spork root snapshot (1 block sealing segment).
@@ -781,10 +778,12 @@ func OpenState(
781778
if !isBootstrapped {
782779
return nil, fmt.Errorf("expected database to contain bootstrapped state")
783780
}
784-
sporkRootBlock, err := ReadSporkRootBlock(db, blocks)
781+
instanceParams, err := datastore.ReadInstanceParams(db.Reader(), headers, seals, blocks)
785782
if err != nil {
786-
return nil, fmt.Errorf("could not read spork root block: %w", err)
783+
return nil, fmt.Errorf("could not read instance params: %w", err)
787784
}
785+
sporkRootBlock := instanceParams.SporkRootBlock()
786+
788787
globalParams := inmem.NewParams(
789788
inmem.EncodableParams{
790789
ChainID: sporkRootBlock.ChainID,
@@ -793,10 +792,6 @@ func OpenState(
793792
SporkRootBlockView: sporkRootBlock.View,
794793
},
795794
)
796-
instanceParams, err := ReadInstanceParams(db.Reader(), headers, seals)
797-
if err != nil {
798-
return nil, fmt.Errorf("could not read instance params: %w", err)
799-
}
800795
params := &datastore.Params{
801796
GlobalParams: globalParams,
802797
InstanceParams: instanceParams,

0 commit comments

Comments
 (0)