github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/kv/state.go (about) 1 package kv 2 3 import ( 4 "bytes" 5 "context" 6 7 "github.com/pkg/errors" 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 10 "github.com/prysmaticlabs/prysm/beacon-chain/state/genesis" 11 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 12 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 13 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 14 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 15 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 16 "github.com/prysmaticlabs/prysm/shared/bytesutil" 17 "github.com/prysmaticlabs/prysm/shared/params" 18 "github.com/prysmaticlabs/prysm/shared/traceutil" 19 bolt "go.etcd.io/bbolt" 20 "go.opencensus.io/trace" 21 ) 22 23 // State returns the saved state using block's signing root, 24 // this particular block was used to generate the state. 25 func (s *Store) State(ctx context.Context, blockRoot [32]byte) (iface.BeaconState, error) { 26 ctx, span := trace.StartSpan(ctx, "BeaconDB.State") 27 defer span.End() 28 var st *pb.BeaconState 29 enc, err := s.stateBytes(ctx, blockRoot) 30 if err != nil { 31 return nil, err 32 } 33 34 if len(enc) == 0 { 35 return nil, nil 36 } 37 38 st, err = createState(ctx, enc) 39 if err != nil { 40 return nil, err 41 } 42 return v1.InitializeFromProtoUnsafe(st) 43 } 44 45 // GenesisState returns the genesis state in beacon chain. 46 func (s *Store) GenesisState(ctx context.Context) (iface.BeaconState, error) { 47 ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState") 48 defer span.End() 49 50 cached, err := genesis.State(params.BeaconConfig().ConfigName) 51 if err != nil { 52 traceutil.AnnotateError(span, err) 53 return nil, err 54 } 55 span.AddAttributes(trace.BoolAttribute("cache_hit", cached != nil)) 56 if cached != nil { 57 return cached, nil 58 } 59 60 var st *pb.BeaconState 61 err = s.db.View(func(tx *bolt.Tx) error { 62 // Retrieve genesis block's signing root from blocks bucket, 63 // to look up what the genesis state is. 64 bucket := tx.Bucket(blocksBucket) 65 genesisBlockRoot := bucket.Get(genesisBlockRootKey) 66 67 bucket = tx.Bucket(stateBucket) 68 enc := bucket.Get(genesisBlockRoot) 69 if enc == nil { 70 return nil 71 } 72 73 var err error 74 st, err = createState(ctx, enc) 75 return err 76 }) 77 if err != nil { 78 return nil, err 79 } 80 if st == nil { 81 return nil, nil 82 } 83 return v1.InitializeFromProtoUnsafe(st) 84 } 85 86 // SaveState stores a state to the db using block's signing root which was used to generate the state. 87 func (s *Store) SaveState(ctx context.Context, st iface.ReadOnlyBeaconState, blockRoot [32]byte) error { 88 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveState") 89 defer span.End() 90 91 return s.SaveStates(ctx, []iface.ReadOnlyBeaconState{st}, [][32]byte{blockRoot}) 92 } 93 94 // SaveStates stores multiple states to the db using the provided corresponding roots. 95 func (s *Store) SaveStates(ctx context.Context, states []iface.ReadOnlyBeaconState, blockRoots [][32]byte) error { 96 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveStates") 97 defer span.End() 98 if states == nil { 99 return errors.New("nil state") 100 } 101 multipleEncs := make([][]byte, len(states)) 102 for i, st := range states { 103 pbState, err := v1.ProtobufBeaconState(st.InnerStateUnsafe()) 104 if err != nil { 105 return err 106 } 107 multipleEncs[i], err = encode(ctx, pbState) 108 if err != nil { 109 return err 110 } 111 } 112 113 return s.db.Update(func(tx *bolt.Tx) error { 114 bucket := tx.Bucket(stateBucket) 115 for i, rt := range blockRoots { 116 indicesByBucket := createStateIndicesFromStateSlot(ctx, states[i].Slot()) 117 if err := updateValueForIndices(ctx, indicesByBucket, rt[:], tx); err != nil { 118 return errors.Wrap(err, "could not update DB indices") 119 } 120 if err := bucket.Put(rt[:], multipleEncs[i]); err != nil { 121 return err 122 } 123 } 124 return nil 125 }) 126 } 127 128 // HasState checks if a state by root exists in the db. 129 func (s *Store) HasState(ctx context.Context, blockRoot [32]byte) bool { 130 ctx, span := trace.StartSpan(ctx, "BeaconDB.HasState") 131 defer span.End() 132 hasState := false 133 err := s.db.View(func(tx *bolt.Tx) error { 134 bkt := tx.Bucket(stateBucket) 135 stBytes := bkt.Get(blockRoot[:]) 136 if len(stBytes) > 0 { 137 hasState = true 138 } 139 return nil 140 }) 141 if err != nil { 142 panic(err) 143 } 144 return hasState 145 } 146 147 // DeleteState by block root. 148 func (s *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error { 149 ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteState") 150 defer span.End() 151 152 return s.db.Update(func(tx *bolt.Tx) error { 153 bkt := tx.Bucket(blocksBucket) 154 genesisBlockRoot := bkt.Get(genesisBlockRootKey) 155 156 bkt = tx.Bucket(checkpointBucket) 157 enc := bkt.Get(finalizedCheckpointKey) 158 checkpoint := ðpb.Checkpoint{} 159 if enc == nil { 160 checkpoint = ðpb.Checkpoint{Root: genesisBlockRoot} 161 } else if err := decode(ctx, enc, checkpoint); err != nil { 162 return err 163 } 164 165 blockBkt := tx.Bucket(blocksBucket) 166 headBlkRoot := blockBkt.Get(headBlockRootKey) 167 bkt = tx.Bucket(stateBucket) 168 // Safe guard against deleting genesis, finalized, head state. 169 if bytes.Equal(blockRoot[:], checkpoint.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], headBlkRoot) { 170 return errors.New("cannot delete genesis, finalized, or head state") 171 } 172 173 slot, err := slotByBlockRoot(ctx, tx, blockRoot[:]) 174 if err != nil { 175 return err 176 } 177 indicesByBucket := createStateIndicesFromStateSlot(ctx, slot) 178 if err := deleteValueForIndices(ctx, indicesByBucket, blockRoot[:], tx); err != nil { 179 return errors.Wrap(err, "could not delete root for DB indices") 180 } 181 182 return bkt.Delete(blockRoot[:]) 183 }) 184 } 185 186 // DeleteStates by block roots. 187 func (s *Store) DeleteStates(ctx context.Context, blockRoots [][32]byte) error { 188 ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteStates") 189 defer span.End() 190 191 for _, r := range blockRoots { 192 if err := s.DeleteState(ctx, r); err != nil { 193 return err 194 } 195 } 196 197 return nil 198 } 199 200 // creates state from marshaled proto state bytes. 201 func createState(ctx context.Context, enc []byte) (*pb.BeaconState, error) { 202 protoState := &pb.BeaconState{} 203 if err := decode(ctx, enc, protoState); err != nil { 204 return nil, errors.Wrap(err, "failed to unmarshal encoding") 205 } 206 return protoState, nil 207 } 208 209 // HasState checks if a state by root exists in the db. 210 func (s *Store) stateBytes(ctx context.Context, blockRoot [32]byte) ([]byte, error) { 211 ctx, span := trace.StartSpan(ctx, "BeaconDB.stateBytes") 212 defer span.End() 213 var dst []byte 214 err := s.db.View(func(tx *bolt.Tx) error { 215 bkt := tx.Bucket(stateBucket) 216 stBytes := bkt.Get(blockRoot[:]) 217 if len(stBytes) == 0 { 218 return nil 219 } 220 // Due to https://github.com/boltdb/bolt/issues/204, we need to 221 // allocate a byte slice separately in the transaction or there 222 // is the possibility of a panic when accessing that particular 223 // area of memory. 224 dst = make([]byte, len(stBytes)) 225 copy(dst, stBytes) 226 return nil 227 }) 228 return dst, err 229 } 230 231 // slotByBlockRoot retrieves the corresponding slot of the input block root. 232 func slotByBlockRoot(ctx context.Context, tx *bolt.Tx, blockRoot []byte) (types.Slot, error) { 233 ctx, span := trace.StartSpan(ctx, "BeaconDB.slotByBlockRoot") 234 defer span.End() 235 236 bkt := tx.Bucket(stateSummaryBucket) 237 enc := bkt.Get(blockRoot) 238 239 if enc == nil { 240 // Fall back to check the block. 241 bkt := tx.Bucket(blocksBucket) 242 enc := bkt.Get(blockRoot) 243 244 if enc == nil { 245 // Fallback and check the state. 246 bkt = tx.Bucket(stateBucket) 247 enc = bkt.Get(blockRoot) 248 if enc == nil { 249 return 0, errors.New("state enc can't be nil") 250 } 251 s, err := createState(ctx, enc) 252 if err != nil { 253 return 0, err 254 } 255 if s == nil { 256 return 0, errors.New("state can't be nil") 257 } 258 return s.Slot, nil 259 } 260 b := ðpb.SignedBeaconBlock{} 261 err := decode(ctx, enc, b) 262 if err != nil { 263 return 0, err 264 } 265 if err := helpers.VerifyNilBeaconBlock(wrapper.WrappedPhase0SignedBeaconBlock(b)); err != nil { 266 return 0, err 267 } 268 return b.Block.Slot, nil 269 } 270 stateSummary := &pb.StateSummary{} 271 if err := decode(ctx, enc, stateSummary); err != nil { 272 return 0, err 273 } 274 return stateSummary.Slot, nil 275 } 276 277 // HighestSlotStatesBelow returns the states with the highest slot below the input slot 278 // from the db. Ideally there should just be one state per slot, but given validator 279 // can double propose, a single slot could have multiple block roots and 280 // results states. This returns a list of states. 281 func (s *Store) HighestSlotStatesBelow(ctx context.Context, slot types.Slot) ([]iface.ReadOnlyBeaconState, error) { 282 ctx, span := trace.StartSpan(ctx, "BeaconDB.HighestSlotStatesBelow") 283 defer span.End() 284 285 var best []byte 286 if err := s.db.View(func(tx *bolt.Tx) error { 287 bkt := tx.Bucket(stateSlotIndicesBucket) 288 c := bkt.Cursor() 289 for s, root := c.First(); s != nil; s, root = c.Next() { 290 if ctx.Err() != nil { 291 return ctx.Err() 292 } 293 key := bytesutil.BytesToSlotBigEndian(s) 294 if root == nil { 295 continue 296 } 297 if key >= slot { 298 break 299 } 300 best = root 301 } 302 return nil 303 }); err != nil { 304 return nil, err 305 } 306 307 var st iface.ReadOnlyBeaconState 308 var err error 309 if best != nil { 310 st, err = s.State(ctx, bytesutil.ToBytes32(best)) 311 if err != nil { 312 return nil, err 313 } 314 } 315 if st == nil || st.IsNil() { 316 st, err = s.GenesisState(ctx) 317 if err != nil { 318 return nil, err 319 } 320 } 321 322 return []iface.ReadOnlyBeaconState{st}, nil 323 } 324 325 // createStateIndicesFromStateSlot takes in a state slot and returns 326 // a map of bolt DB index buckets corresponding to each particular key for indices for 327 // data, such as (shard indices bucket -> shard 5). 328 func createStateIndicesFromStateSlot(ctx context.Context, slot types.Slot) map[string][]byte { 329 ctx, span := trace.StartSpan(ctx, "BeaconDB.createStateIndicesFromState") 330 defer span.End() 331 indicesByBucket := make(map[string][]byte) 332 // Every index has a unique bucket for fast, binary-search 333 // range scans for filtering across keys. 334 buckets := [][]byte{ 335 stateSlotIndicesBucket, 336 } 337 338 indices := [][]byte{ 339 bytesutil.SlotToBytesBigEndian(slot), 340 } 341 for i := 0; i < len(buckets); i++ { 342 indicesByBucket[string(buckets[i])] = indices[i] 343 } 344 return indicesByBucket 345 } 346 347 // CleanUpDirtyStates removes states in DB that falls to under archived point interval rules. 348 // Only following states would be kept: 349 // 1.) state_slot % archived_interval == 0. (e.g. archived_interval=2048, states with slot 2048, 4096... etc) 350 // 2.) archived_interval - archived_interval/3 < state_slot % archived_interval 351 // (e.g. archived_interval=2048, states with slots after 1365). 352 // This is to tolerate skip slots. Not every state lays on the boundary. 353 // 3.) state with current finalized root 354 // 4.) unfinalized States 355 func (s *Store) CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint types.Slot) error { 356 ctx, span := trace.StartSpan(ctx, "BeaconDB. CleanUpDirtyStates") 357 defer span.End() 358 359 f, err := s.FinalizedCheckpoint(ctx) 360 if err != nil { 361 return err 362 } 363 finalizedSlot, err := helpers.StartSlot(f.Epoch) 364 if err != nil { 365 return err 366 } 367 deletedRoots := make([][32]byte, 0) 368 369 err = s.db.View(func(tx *bolt.Tx) error { 370 bkt := tx.Bucket(stateSlotIndicesBucket) 371 return bkt.ForEach(func(k, v []byte) error { 372 if ctx.Err() != nil { 373 return ctx.Err() 374 } 375 376 finalizedChkpt := bytesutil.ToBytes32(f.Root) == bytesutil.ToBytes32(v) 377 slot := bytesutil.BytesToSlotBigEndian(k) 378 mod := slot % slotsPerArchivedPoint 379 nonFinalized := slot > finalizedSlot 380 381 // The following conditions cover 1, 2, 3 and 4 above. 382 if mod != 0 && mod <= slotsPerArchivedPoint-slotsPerArchivedPoint/3 && !finalizedChkpt && !nonFinalized { 383 deletedRoots = append(deletedRoots, bytesutil.ToBytes32(v)) 384 } 385 return nil 386 }) 387 }) 388 if err != nil { 389 return err 390 } 391 392 // Length of to be deleted roots is 0. Nothing to do. 393 if len(deletedRoots) == 0 { 394 return nil 395 } 396 397 log.WithField("count", len(deletedRoots)).Info("Cleaning up dirty states") 398 if err := s.DeleteStates(ctx, deletedRoots); err != nil { 399 return err 400 } 401 402 return err 403 }