github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/execution/state/bootstrap/bootstrap.go (about) 1 package bootstrap 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/cockroachdb/pebble" 9 "github.com/dgraph-io/badger/v2" 10 "github.com/rs/zerolog" 11 12 "github.com/onflow/flow-go/engine/execution/state" 13 "github.com/onflow/flow-go/engine/execution/storehouse" 14 "github.com/onflow/flow-go/fvm" 15 "github.com/onflow/flow-go/fvm/storage/snapshot" 16 "github.com/onflow/flow-go/ledger" 17 "github.com/onflow/flow-go/model/flow" 18 "github.com/onflow/flow-go/storage" 19 "github.com/onflow/flow-go/storage/badger/operation" 20 pStorage "github.com/onflow/flow-go/storage/pebble" 21 ) 22 23 // an increased limit for bootstrapping 24 const ledgerIntractionLimitNeededForBootstrapping = 1_000_000_000 25 26 type Bootstrapper struct { 27 logger zerolog.Logger 28 } 29 30 func NewBootstrapper(logger zerolog.Logger) *Bootstrapper { 31 return &Bootstrapper{ 32 logger: logger, 33 } 34 } 35 36 // BootstrapLedger adds the above root account to the ledger and initializes execution node-only data 37 func (b *Bootstrapper) BootstrapLedger( 38 ledger ledger.Ledger, 39 servicePublicKey flow.AccountPublicKey, 40 chain flow.Chain, 41 opts ...fvm.BootstrapProcedureOption, 42 ) (flow.StateCommitment, error) { 43 startCommit := flow.StateCommitment(ledger.InitialState()) 44 storageSnapshot := state.NewLedgerStorageSnapshot( 45 ledger, 46 startCommit) 47 48 vm := fvm.NewVirtualMachine() 49 50 ctx := fvm.NewContext( 51 fvm.WithLogger(b.logger), 52 fvm.WithMaxStateInteractionSize(ledgerIntractionLimitNeededForBootstrapping), 53 fvm.WithChain(chain), 54 ) 55 56 bootstrap := fvm.Bootstrap( 57 servicePublicKey, 58 opts..., 59 ) 60 61 executionSnapshot, _, err := vm.Run(ctx, bootstrap, storageSnapshot) 62 if err != nil { 63 return flow.DummyStateCommitment, err 64 } 65 66 newStateCommitment, _, _, err := state.CommitDelta( 67 ledger, 68 executionSnapshot, 69 storehouse.NewExecutingBlockSnapshot(storageSnapshot, startCommit), 70 ) 71 if err != nil { 72 return flow.DummyStateCommitment, err 73 } 74 75 return newStateCommitment, nil 76 } 77 78 // IsBootstrapped returns whether the execution database has been bootstrapped, if yes, returns the 79 // root statecommitment 80 func (b *Bootstrapper) IsBootstrapped(db *badger.DB) (flow.StateCommitment, bool, error) { 81 var commit flow.StateCommitment 82 83 err := db.View(func(txn *badger.Txn) error { 84 err := operation.LookupStateCommitment(flow.ZeroID, &commit)(txn) 85 if err != nil { 86 return fmt.Errorf("could not lookup state commitment: %w", err) 87 } 88 89 return nil 90 }) 91 92 if errors.Is(err, storage.ErrNotFound) { 93 return flow.DummyStateCommitment, false, nil 94 } 95 96 if err != nil { 97 return flow.DummyStateCommitment, false, err 98 } 99 100 return commit, true, nil 101 } 102 103 func (b *Bootstrapper) BootstrapExecutionDatabase( 104 db *badger.DB, 105 rootSeal *flow.Seal, 106 ) error { 107 108 commit := rootSeal.FinalState 109 err := operation.RetryOnConflict(db.Update, func(txn *badger.Txn) error { 110 111 err := operation.InsertExecutedBlock(rootSeal.BlockID)(txn) 112 if err != nil { 113 return fmt.Errorf("could not index initial genesis execution block: %w", err) 114 } 115 116 err = operation.SkipDuplicates(operation.IndexExecutionResult(rootSeal.BlockID, rootSeal.ResultID))(txn) 117 if err != nil { 118 return fmt.Errorf("could not index result for root result: %w", err) 119 } 120 121 err = operation.IndexStateCommitment(flow.ZeroID, commit)(txn) 122 if err != nil { 123 return fmt.Errorf("could not index void state commitment: %w", err) 124 } 125 126 err = operation.IndexStateCommitment(rootSeal.BlockID, commit)(txn) 127 if err != nil { 128 return fmt.Errorf("could not index genesis state commitment: %w", err) 129 } 130 131 snapshots := make([]*snapshot.ExecutionSnapshot, 0) 132 err = operation.InsertExecutionStateInteractions(rootSeal.BlockID, snapshots)(txn) 133 if err != nil { 134 return fmt.Errorf("could not bootstrap execution state interactions: %w", err) 135 } 136 137 return nil 138 }) 139 140 if err != nil { 141 return err 142 } 143 144 return nil 145 } 146 147 func ImportRegistersFromCheckpoint(logger zerolog.Logger, checkpointFile string, checkpointHeight uint64, checkpointRootHash ledger.RootHash, pdb *pebble.DB, workerCount int) error { 148 logger.Info().Msgf("importing registers from checkpoint file %s at height %d with root hash: %v", checkpointFile, checkpointHeight, checkpointRootHash) 149 150 bootstrap, err := pStorage.NewRegisterBootstrap(pdb, checkpointFile, checkpointHeight, checkpointRootHash, logger) 151 if err != nil { 152 return fmt.Errorf("could not create registers bootstrapper: %w", err) 153 } 154 155 // TODO: find a way to hook a context up to this to allow a graceful shutdown 156 err = bootstrap.IndexCheckpointFile(context.Background(), workerCount) 157 if err != nil { 158 return fmt.Errorf("could not load checkpoint file: %w", err) 159 } 160 161 logger.Info().Msgf("finish importing registers from checkpoint file %s at height %d", checkpointFile, checkpointHeight) 162 return nil 163 }