github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/kv/blocks.go (about) 1 package kv 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 8 "github.com/pkg/errors" 9 types "github.com/prysmaticlabs/eth2-types" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 11 "github.com/prysmaticlabs/prysm/beacon-chain/db/filters" 12 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 13 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 14 "github.com/prysmaticlabs/prysm/proto/interfaces" 15 "github.com/prysmaticlabs/prysm/shared/bytesutil" 16 "github.com/prysmaticlabs/prysm/shared/params" 17 "github.com/prysmaticlabs/prysm/shared/sliceutil" 18 bolt "go.etcd.io/bbolt" 19 "go.opencensus.io/trace" 20 ) 21 22 // used to represent errors for inconsistent slot ranges. 23 var errInvalidSlotRange = errors.New("invalid end slot and start slot provided") 24 25 // Block retrieval by root. 26 func (s *Store) Block(ctx context.Context, blockRoot [32]byte) (interfaces.SignedBeaconBlock, error) { 27 ctx, span := trace.StartSpan(ctx, "BeaconDB.Block") 28 defer span.End() 29 // Return block from cache if it exists. 30 if v, ok := s.blockCache.Get(string(blockRoot[:])); v != nil && ok { 31 return v.(interfaces.SignedBeaconBlock), nil 32 } 33 var block *ethpb.SignedBeaconBlock 34 err := s.db.View(func(tx *bolt.Tx) error { 35 bkt := tx.Bucket(blocksBucket) 36 enc := bkt.Get(blockRoot[:]) 37 if enc == nil { 38 return nil 39 } 40 block = ðpb.SignedBeaconBlock{} 41 return decode(ctx, enc, block) 42 }) 43 return wrapper.WrappedPhase0SignedBeaconBlock(block), err 44 } 45 46 // HeadBlock returns the latest canonical block in the Ethereum Beacon Chain. 47 func (s *Store) HeadBlock(ctx context.Context) (interfaces.SignedBeaconBlock, error) { 48 ctx, span := trace.StartSpan(ctx, "BeaconDB.HeadBlock") 49 defer span.End() 50 var headBlock *ethpb.SignedBeaconBlock 51 err := s.db.View(func(tx *bolt.Tx) error { 52 bkt := tx.Bucket(blocksBucket) 53 headRoot := bkt.Get(headBlockRootKey) 54 if headRoot == nil { 55 return nil 56 } 57 enc := bkt.Get(headRoot) 58 if enc == nil { 59 return nil 60 } 61 headBlock = ðpb.SignedBeaconBlock{} 62 return decode(ctx, enc, headBlock) 63 }) 64 return wrapper.WrappedPhase0SignedBeaconBlock(headBlock), err 65 } 66 67 // Blocks retrieves a list of beacon blocks and its respective roots by filter criteria. 68 func (s *Store) Blocks(ctx context.Context, f *filters.QueryFilter) ([]interfaces.SignedBeaconBlock, [][32]byte, error) { 69 ctx, span := trace.StartSpan(ctx, "BeaconDB.Blocks") 70 defer span.End() 71 blocks := make([]interfaces.SignedBeaconBlock, 0) 72 blockRoots := make([][32]byte, 0) 73 74 err := s.db.View(func(tx *bolt.Tx) error { 75 bkt := tx.Bucket(blocksBucket) 76 77 keys, err := blockRootsByFilter(ctx, tx, f) 78 if err != nil { 79 return err 80 } 81 82 for i := 0; i < len(keys); i++ { 83 encoded := bkt.Get(keys[i]) 84 block := ðpb.SignedBeaconBlock{} 85 if err := decode(ctx, encoded, block); err != nil { 86 return err 87 } 88 blocks = append(blocks, wrapper.WrappedPhase0SignedBeaconBlock(block)) 89 blockRoots = append(blockRoots, bytesutil.ToBytes32(keys[i])) 90 } 91 return nil 92 }) 93 return blocks, blockRoots, err 94 } 95 96 // BlockRoots retrieves a list of beacon block roots by filter criteria. If the caller 97 // requires both the blocks and the block roots for a certain filter they should instead 98 // use the Blocks function rather than use BlockRoots. During periods of non finality 99 // there are potential race conditions which leads to differing roots when calling the db 100 // multiple times for the same filter. 101 func (s *Store) BlockRoots(ctx context.Context, f *filters.QueryFilter) ([][32]byte, error) { 102 ctx, span := trace.StartSpan(ctx, "BeaconDB.BlockRoots") 103 defer span.End() 104 blockRoots := make([][32]byte, 0) 105 err := s.db.View(func(tx *bolt.Tx) error { 106 keys, err := blockRootsByFilter(ctx, tx, f) 107 if err != nil { 108 return err 109 } 110 111 for i := 0; i < len(keys); i++ { 112 blockRoots = append(blockRoots, bytesutil.ToBytes32(keys[i])) 113 } 114 return nil 115 }) 116 if err != nil { 117 return nil, errors.Wrap(err, "could not retrieve block roots") 118 } 119 return blockRoots, nil 120 } 121 122 // HasBlock checks if a block by root exists in the db. 123 func (s *Store) HasBlock(ctx context.Context, blockRoot [32]byte) bool { 124 ctx, span := trace.StartSpan(ctx, "BeaconDB.HasBlock") 125 defer span.End() 126 if v, ok := s.blockCache.Get(string(blockRoot[:])); v != nil && ok { 127 return true 128 } 129 exists := false 130 if err := s.db.View(func(tx *bolt.Tx) error { 131 bkt := tx.Bucket(blocksBucket) 132 exists = bkt.Get(blockRoot[:]) != nil 133 return nil 134 }); err != nil { // This view never returns an error, but we'll handle anyway for sanity. 135 panic(err) 136 } 137 return exists 138 } 139 140 // BlocksBySlot retrieves a list of beacon blocks and its respective roots by slot. 141 func (s *Store) BlocksBySlot(ctx context.Context, slot types.Slot) (bool, []interfaces.SignedBeaconBlock, error) { 142 ctx, span := trace.StartSpan(ctx, "BeaconDB.BlocksBySlot") 143 defer span.End() 144 blocks := make([]interfaces.SignedBeaconBlock, 0) 145 146 err := s.db.View(func(tx *bolt.Tx) error { 147 bkt := tx.Bucket(blocksBucket) 148 149 keys, err := blockRootsBySlot(ctx, tx, slot) 150 if err != nil { 151 return err 152 } 153 154 for i := 0; i < len(keys); i++ { 155 encoded := bkt.Get(keys[i]) 156 block := ðpb.SignedBeaconBlock{} 157 if err := decode(ctx, encoded, block); err != nil { 158 return err 159 } 160 blocks = append(blocks, wrapper.WrappedPhase0SignedBeaconBlock(block)) 161 } 162 return nil 163 }) 164 return len(blocks) > 0, blocks, err 165 } 166 167 // BlockRootsBySlot retrieves a list of beacon block roots by slot 168 func (s *Store) BlockRootsBySlot(ctx context.Context, slot types.Slot) (bool, [][32]byte, error) { 169 ctx, span := trace.StartSpan(ctx, "BeaconDB.BlockRootsBySlot") 170 defer span.End() 171 blockRoots := make([][32]byte, 0) 172 err := s.db.View(func(tx *bolt.Tx) error { 173 keys, err := blockRootsBySlot(ctx, tx, slot) 174 if err != nil { 175 return err 176 } 177 178 for i := 0; i < len(keys); i++ { 179 blockRoots = append(blockRoots, bytesutil.ToBytes32(keys[i])) 180 } 181 return nil 182 }) 183 if err != nil { 184 return false, nil, errors.Wrap(err, "could not retrieve block roots by slot") 185 } 186 return len(blockRoots) > 0, blockRoots, nil 187 } 188 189 // deleteBlock by block root. 190 func (s *Store) deleteBlock(ctx context.Context, blockRoot [32]byte) error { 191 ctx, span := trace.StartSpan(ctx, "BeaconDB.deleteBlock") 192 defer span.End() 193 return s.db.Update(func(tx *bolt.Tx) error { 194 bkt := tx.Bucket(blocksBucket) 195 enc := bkt.Get(blockRoot[:]) 196 if enc == nil { 197 return nil 198 } 199 block := ðpb.SignedBeaconBlock{} 200 if err := decode(ctx, enc, block); err != nil { 201 return err 202 } 203 indicesByBucket := createBlockIndicesFromBlock(ctx, wrapper.WrappedPhase0BeaconBlock(block.Block)) 204 if err := deleteValueForIndices(ctx, indicesByBucket, blockRoot[:], tx); err != nil { 205 return errors.Wrap(err, "could not delete root for DB indices") 206 } 207 s.blockCache.Del(string(blockRoot[:])) 208 return bkt.Delete(blockRoot[:]) 209 }) 210 } 211 212 // deleteBlocks by block roots. 213 func (s *Store) deleteBlocks(ctx context.Context, blockRoots [][32]byte) error { 214 ctx, span := trace.StartSpan(ctx, "BeaconDB.deleteBlocks") 215 defer span.End() 216 217 return s.db.Update(func(tx *bolt.Tx) error { 218 bkt := tx.Bucket(blocksBucket) 219 for _, blockRoot := range blockRoots { 220 enc := bkt.Get(blockRoot[:]) 221 if enc == nil { 222 return nil 223 } 224 block := ðpb.SignedBeaconBlock{} 225 if err := decode(ctx, enc, block); err != nil { 226 return err 227 } 228 indicesByBucket := createBlockIndicesFromBlock(ctx, wrapper.WrappedPhase0BeaconBlock(block.Block)) 229 if err := deleteValueForIndices(ctx, indicesByBucket, blockRoot[:], tx); err != nil { 230 return errors.Wrap(err, "could not delete root for DB indices") 231 } 232 s.blockCache.Del(string(blockRoot[:])) 233 if err := bkt.Delete(blockRoot[:]); err != nil { 234 return err 235 } 236 } 237 return nil 238 }) 239 } 240 241 // SaveBlock to the db. 242 func (s *Store) SaveBlock(ctx context.Context, signed interfaces.SignedBeaconBlock) error { 243 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlock") 244 defer span.End() 245 blockRoot, err := signed.Block().HashTreeRoot() 246 if err != nil { 247 return err 248 } 249 if v, ok := s.blockCache.Get(string(blockRoot[:])); v != nil && ok { 250 return nil 251 } 252 253 return s.SaveBlocks(ctx, []interfaces.SignedBeaconBlock{signed}) 254 } 255 256 // SaveBlocks via bulk updates to the db. 257 func (s *Store) SaveBlocks(ctx context.Context, blocks []interfaces.SignedBeaconBlock) error { 258 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlocks") 259 defer span.End() 260 261 return s.db.Update(func(tx *bolt.Tx) error { 262 bkt := tx.Bucket(blocksBucket) 263 for _, block := range blocks { 264 blockRoot, err := block.Block().HashTreeRoot() 265 if err != nil { 266 return err 267 } 268 269 if existingBlock := bkt.Get(blockRoot[:]); existingBlock != nil { 270 continue 271 } 272 enc, err := encode(ctx, block.Proto()) 273 if err != nil { 274 return err 275 } 276 indicesByBucket := createBlockIndicesFromBlock(ctx, block.Block()) 277 if err := updateValueForIndices(ctx, indicesByBucket, blockRoot[:], tx); err != nil { 278 return errors.Wrap(err, "could not update DB indices") 279 } 280 s.blockCache.Set(string(blockRoot[:]), block, int64(len(enc))) 281 282 if err := bkt.Put(blockRoot[:], enc); err != nil { 283 return err 284 } 285 } 286 return nil 287 }) 288 } 289 290 // SaveHeadBlockRoot to the db. 291 func (s *Store) SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error { 292 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveHeadBlockRoot") 293 defer span.End() 294 return s.db.Update(func(tx *bolt.Tx) error { 295 hasStateSummaryInDB := s.HasStateSummary(ctx, blockRoot) 296 hasStateInDB := tx.Bucket(stateBucket).Get(blockRoot[:]) != nil 297 if !(hasStateInDB || hasStateSummaryInDB) { 298 return errors.New("no state or state summary found with head block root") 299 } 300 301 bucket := tx.Bucket(blocksBucket) 302 return bucket.Put(headBlockRootKey, blockRoot[:]) 303 }) 304 } 305 306 // GenesisBlock retrieves the genesis block of the beacon chain. 307 func (s *Store) GenesisBlock(ctx context.Context) (interfaces.SignedBeaconBlock, error) { 308 ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisBlock") 309 defer span.End() 310 var block *ethpb.SignedBeaconBlock 311 err := s.db.View(func(tx *bolt.Tx) error { 312 bkt := tx.Bucket(blocksBucket) 313 root := bkt.Get(genesisBlockRootKey) 314 enc := bkt.Get(root) 315 if enc == nil { 316 return nil 317 } 318 block = ðpb.SignedBeaconBlock{} 319 return decode(ctx, enc, block) 320 }) 321 return wrapper.WrappedPhase0SignedBeaconBlock(block), err 322 } 323 324 // SaveGenesisBlockRoot to the db. 325 func (s *Store) SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error { 326 ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveGenesisBlockRoot") 327 defer span.End() 328 return s.db.Update(func(tx *bolt.Tx) error { 329 bucket := tx.Bucket(blocksBucket) 330 return bucket.Put(genesisBlockRootKey, blockRoot[:]) 331 }) 332 } 333 334 // HighestSlotBlocksBelow returns the block with the highest slot below the input slot from the db. 335 func (s *Store) HighestSlotBlocksBelow(ctx context.Context, slot types.Slot) ([]interfaces.SignedBeaconBlock, error) { 336 ctx, span := trace.StartSpan(ctx, "BeaconDB.HighestSlotBlocksBelow") 337 defer span.End() 338 339 var best []byte 340 if err := s.db.View(func(tx *bolt.Tx) error { 341 bkt := tx.Bucket(blockSlotIndicesBucket) 342 // Iterate through the index, which is in byte sorted order. 343 c := bkt.Cursor() 344 for s, root := c.First(); s != nil; s, root = c.Next() { 345 if ctx.Err() != nil { 346 return ctx.Err() 347 } 348 key := bytesutil.BytesToSlotBigEndian(s) 349 if root == nil { 350 continue 351 } 352 if key >= slot { 353 break 354 } 355 best = root 356 } 357 return nil 358 }); err != nil { 359 return nil, err 360 } 361 362 var blk interfaces.SignedBeaconBlock 363 var err error 364 if best != nil { 365 blk, err = s.Block(ctx, bytesutil.ToBytes32(best)) 366 if err != nil { 367 return nil, err 368 } 369 } 370 if blk == nil || blk.IsNil() { 371 blk, err = s.GenesisBlock(ctx) 372 if err != nil { 373 return nil, err 374 } 375 } 376 377 return []interfaces.SignedBeaconBlock{blk}, nil 378 } 379 380 // blockRootsByFilter retrieves the block roots given the filter criteria. 381 func blockRootsByFilter(ctx context.Context, tx *bolt.Tx, f *filters.QueryFilter) ([][]byte, error) { 382 ctx, span := trace.StartSpan(ctx, "BeaconDB.blockRootsByFilter") 383 defer span.End() 384 385 // If no filter criteria are specified, return an error. 386 if f == nil { 387 return nil, errors.New("must specify a filter criteria for retrieving blocks") 388 } 389 390 // Creates a list of indices from the passed in filter values, such as: 391 // []byte("0x2093923") in the parent root indices bucket to be used for looking up 392 // block roots that were stored under each of those indices for O(1) lookup. 393 indicesByBucket, err := createBlockIndicesFromFilters(ctx, f) 394 if err != nil { 395 return nil, errors.Wrap(err, "could not determine lookup indices") 396 } 397 398 // We retrieve block roots that match a filter criteria of slot ranges, if specified. 399 filtersMap := f.Filters() 400 rootsBySlotRange, err := blockRootsBySlotRange( 401 ctx, 402 tx.Bucket(blockSlotIndicesBucket), 403 filtersMap[filters.StartSlot], 404 filtersMap[filters.EndSlot], 405 filtersMap[filters.StartEpoch], 406 filtersMap[filters.EndEpoch], 407 filtersMap[filters.SlotStep], 408 ) 409 if err != nil { 410 return nil, err 411 } 412 413 // Once we have a list of block roots that correspond to each 414 // lookup index, we find the intersection across all of them and use 415 // that list of roots to lookup the block. These block will 416 // meet the filter criteria. 417 indices := lookupValuesForIndices(ctx, indicesByBucket, tx) 418 keys := rootsBySlotRange 419 if len(indices) > 0 { 420 // If we have found indices that meet the filter criteria, and there are also 421 // block roots that meet the slot range filter criteria, we find the intersection 422 // between these two sets of roots. 423 if len(rootsBySlotRange) > 0 { 424 joined := append([][][]byte{keys}, indices...) 425 keys = sliceutil.IntersectionByteSlices(joined...) 426 } else { 427 // If we have found indices that meet the filter criteria, but there are no block roots 428 // that meet the slot range filter criteria, we find the intersection 429 // of the regular filter indices. 430 keys = sliceutil.IntersectionByteSlices(indices...) 431 } 432 } 433 434 return keys, nil 435 } 436 437 // blockRootsBySlotRange looks into a boltDB bucket and performs a binary search 438 // range scan using sorted left-padded byte keys using a start slot and an end slot. 439 // However, if step is one, the implemented logic won’t skip half of the slots in the range. 440 func blockRootsBySlotRange( 441 ctx context.Context, 442 bkt *bolt.Bucket, 443 startSlotEncoded, endSlotEncoded, startEpochEncoded, endEpochEncoded, slotStepEncoded interface{}, 444 ) ([][]byte, error) { 445 ctx, span := trace.StartSpan(ctx, "BeaconDB.blockRootsBySlotRange") 446 defer span.End() 447 448 // Return nothing when all slot parameters are missing 449 if startSlotEncoded == nil && endSlotEncoded == nil && startEpochEncoded == nil && endEpochEncoded == nil { 450 return [][]byte{}, nil 451 } 452 453 var startSlot, endSlot types.Slot 454 var step uint64 455 var ok bool 456 if startSlot, ok = startSlotEncoded.(types.Slot); !ok { 457 startSlot = 0 458 } 459 if endSlot, ok = endSlotEncoded.(types.Slot); !ok { 460 endSlot = 0 461 } 462 if step, ok = slotStepEncoded.(uint64); !ok || step == 0 { 463 step = 1 464 } 465 startEpoch, startEpochOk := startEpochEncoded.(types.Epoch) 466 endEpoch, endEpochOk := endEpochEncoded.(types.Epoch) 467 var err error 468 if startEpochOk && endEpochOk { 469 startSlot, err = helpers.StartSlot(startEpoch) 470 if err != nil { 471 return nil, err 472 } 473 endSlot, err = helpers.StartSlot(endEpoch) 474 if err != nil { 475 return nil, err 476 } 477 endSlot = endSlot + params.BeaconConfig().SlotsPerEpoch - 1 478 } 479 min := bytesutil.SlotToBytesBigEndian(startSlot) 480 max := bytesutil.SlotToBytesBigEndian(endSlot) 481 482 conditional := func(key, max []byte) bool { 483 return key != nil && bytes.Compare(key, max) <= 0 484 } 485 if endSlot < startSlot { 486 return nil, errInvalidSlotRange 487 } 488 rootsRange := endSlot.SubSlot(startSlot).Div(step) 489 roots := make([][]byte, 0, rootsRange) 490 c := bkt.Cursor() 491 for k, v := c.Seek(min); conditional(k, max); k, v = c.Next() { 492 if step > 1 { 493 slot := bytesutil.BytesToSlotBigEndian(k) 494 if slot.SubSlot(startSlot).Mod(step) != 0 { 495 continue 496 } 497 } 498 numOfRoots := len(v) / 32 499 splitRoots := make([][]byte, 0, numOfRoots) 500 for i := 0; i < len(v); i += 32 { 501 splitRoots = append(splitRoots, v[i:i+32]) 502 } 503 roots = append(roots, splitRoots...) 504 } 505 return roots, nil 506 } 507 508 // blockRootsBySlot retrieves the block roots by slot 509 func blockRootsBySlot(ctx context.Context, tx *bolt.Tx, slot types.Slot) ([][]byte, error) { 510 ctx, span := trace.StartSpan(ctx, "BeaconDB.blockRootsBySlot") 511 defer span.End() 512 513 roots := make([][]byte, 0) 514 bkt := tx.Bucket(blockSlotIndicesBucket) 515 key := bytesutil.SlotToBytesBigEndian(slot) 516 c := bkt.Cursor() 517 k, v := c.Seek(key) 518 if k != nil && bytes.Equal(k, key) { 519 for i := 0; i < len(v); i += 32 { 520 roots = append(roots, v[i:i+32]) 521 } 522 } 523 return roots, nil 524 } 525 526 // createBlockIndicesFromBlock takes in a beacon block and returns 527 // a map of bolt DB index buckets corresponding to each particular key for indices for 528 // data, such as (shard indices bucket -> shard 5). 529 func createBlockIndicesFromBlock(ctx context.Context, block interfaces.BeaconBlock) map[string][]byte { 530 ctx, span := trace.StartSpan(ctx, "BeaconDB.createBlockIndicesFromBlock") 531 defer span.End() 532 indicesByBucket := make(map[string][]byte) 533 // Every index has a unique bucket for fast, binary-search 534 // range scans for filtering across keys. 535 buckets := [][]byte{ 536 blockSlotIndicesBucket, 537 } 538 indices := [][]byte{ 539 bytesutil.SlotToBytesBigEndian(block.Slot()), 540 } 541 if block.ParentRoot() != nil && len(block.ParentRoot()) > 0 { 542 buckets = append(buckets, blockParentRootIndicesBucket) 543 indices = append(indices, block.ParentRoot()) 544 } 545 for i := 0; i < len(buckets); i++ { 546 indicesByBucket[string(buckets[i])] = indices[i] 547 } 548 return indicesByBucket 549 } 550 551 // createBlockFiltersFromIndices takes in filter criteria and returns 552 // a map with a single key-value pair: "block-parent-root-indices” -> parentRoot (array of bytes). 553 // 554 // For blocks, these are list of signing roots of block 555 // objects. If a certain filter criterion does not apply to 556 // blocks, an appropriate error is returned. 557 func createBlockIndicesFromFilters(ctx context.Context, f *filters.QueryFilter) (map[string][]byte, error) { 558 ctx, span := trace.StartSpan(ctx, "BeaconDB.createBlockIndicesFromFilters") 559 defer span.End() 560 indicesByBucket := make(map[string][]byte) 561 for k, v := range f.Filters() { 562 switch k { 563 case filters.ParentRoot: 564 parentRoot, ok := v.([]byte) 565 if !ok { 566 return nil, errors.New("parent root is not []byte") 567 } 568 indicesByBucket[string(blockParentRootIndicesBucket)] = parentRoot 569 // The following cases are passthroughs for blocks, as they are not used 570 // for filtering indices. 571 case filters.StartSlot: 572 case filters.EndSlot: 573 case filters.StartEpoch: 574 case filters.EndEpoch: 575 case filters.SlotStep: 576 default: 577 return nil, fmt.Errorf("filter criterion %v not supported for blocks", k) 578 } 579 } 580 return indicesByBucket, nil 581 }