github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/head.go (about) 1 package blockchain 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/feed" 11 statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" 12 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 13 "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" 14 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 15 ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1" 16 "github.com/prysmaticlabs/prysm/proto/interfaces" 17 "github.com/prysmaticlabs/prysm/shared/bytesutil" 18 "github.com/prysmaticlabs/prysm/shared/featureconfig" 19 "github.com/prysmaticlabs/prysm/shared/params" 20 "github.com/prysmaticlabs/prysm/shared/slotutil" 21 "github.com/sirupsen/logrus" 22 "go.opencensus.io/trace" 23 ) 24 25 // This defines the current chain service's view of head. 26 type head struct { 27 slot types.Slot // current head slot. 28 root [32]byte // current head root. 29 block interfaces.SignedBeaconBlock // current head block. 30 state iface.BeaconState // current head state. 31 } 32 33 // Determined the head from the fork choice service and saves its new data 34 // (head root, head block, and head state) to the local service cache. 35 func (s *Service) updateHead(ctx context.Context, balances []uint64) error { 36 ctx, span := trace.StartSpan(ctx, "blockChain.updateHead") 37 defer span.End() 38 39 // To get the proper head update, a node first checks its best justified 40 // can become justified. This is designed to prevent bounce attack and 41 // ensure head gets its best justified info. 42 if s.bestJustifiedCheckpt.Epoch > s.justifiedCheckpt.Epoch { 43 s.justifiedCheckpt = s.bestJustifiedCheckpt 44 if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil { 45 return err 46 } 47 } 48 49 // Get head from the fork choice service. 50 f := s.finalizedCheckpt 51 j := s.justifiedCheckpt 52 // To get head before the first justified epoch, the fork choice will start with genesis root 53 // instead of zero hashes. 54 headStartRoot := bytesutil.ToBytes32(j.Root) 55 if headStartRoot == params.BeaconConfig().ZeroHash { 56 headStartRoot = s.genesisRoot 57 } 58 59 // In order to process head, fork choice store requires justified info. 60 // If the fork choice store is missing justified block info, a node should 61 // re-initiate fork choice store using the latest justified info. 62 // This recovers a fatal condition and should not happen in run time. 63 if !s.cfg.ForkChoiceStore.HasNode(headStartRoot) { 64 jb, err := s.cfg.BeaconDB.Block(ctx, headStartRoot) 65 if err != nil { 66 return err 67 } 68 s.cfg.ForkChoiceStore = protoarray.New(j.Epoch, f.Epoch, bytesutil.ToBytes32(f.Root)) 69 if err := s.insertBlockToForkChoiceStore(ctx, jb.Block(), headStartRoot, f, j); err != nil { 70 return err 71 } 72 } 73 74 headRoot, err := s.cfg.ForkChoiceStore.Head(ctx, j.Epoch, headStartRoot, balances, f.Epoch) 75 if err != nil { 76 return err 77 } 78 79 // Save head to the local service cache. 80 return s.saveHead(ctx, headRoot) 81 } 82 83 // This saves head info to the local service cache, it also saves the 84 // new head root to the DB. 85 func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error { 86 ctx, span := trace.StartSpan(ctx, "blockChain.saveHead") 87 defer span.End() 88 89 // Do nothing if head hasn't changed. 90 r, err := s.HeadRoot(ctx) 91 if err != nil { 92 return err 93 } 94 if headRoot == bytesutil.ToBytes32(r) { 95 return nil 96 } 97 98 // If the head state is not available, just return nil. 99 // There's nothing to cache 100 if !s.cfg.BeaconDB.HasStateSummary(ctx, headRoot) { 101 return nil 102 } 103 104 // Get the new head block from DB. 105 newHeadBlock, err := s.cfg.BeaconDB.Block(ctx, headRoot) 106 if err != nil { 107 return err 108 } 109 if newHeadBlock == nil || newHeadBlock.IsNil() || newHeadBlock.Block().IsNil() { 110 return errors.New("cannot save nil head block") 111 } 112 113 // Get the new head state from cached state or DB. 114 newHeadState, err := s.cfg.StateGen.StateByRoot(ctx, headRoot) 115 if err != nil { 116 return errors.Wrap(err, "could not retrieve head state in DB") 117 } 118 if newHeadState == nil || newHeadState.IsNil() { 119 return errors.New("cannot save nil head state") 120 } 121 122 // A chain re-org occurred, so we fire an event notifying the rest of the services. 123 headSlot := s.HeadSlot() 124 newHeadSlot := newHeadBlock.Block().Slot() 125 oldHeadRoot := s.headRoot() 126 oldStateRoot := s.headBlock().Block().StateRoot() 127 newStateRoot := newHeadBlock.Block().StateRoot() 128 if bytesutil.ToBytes32(newHeadBlock.Block().ParentRoot()) != bytesutil.ToBytes32(r) { 129 log.WithFields(logrus.Fields{ 130 "newSlot": fmt.Sprintf("%d", newHeadSlot), 131 "oldSlot": fmt.Sprintf("%d", headSlot), 132 }).Debug("Chain reorg occurred") 133 absoluteSlotDifference := slotutil.AbsoluteValueSlotDifference(newHeadSlot, headSlot) 134 s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ 135 Type: statefeed.Reorg, 136 Data: ðpbv1.EventChainReorg{ 137 Slot: newHeadSlot, 138 Depth: absoluteSlotDifference, 139 OldHeadBlock: oldHeadRoot[:], 140 NewHeadBlock: headRoot[:], 141 OldHeadState: oldStateRoot, 142 NewHeadState: newStateRoot, 143 Epoch: helpers.SlotToEpoch(newHeadSlot), 144 }, 145 }) 146 147 if err := s.saveOrphanedAtts(ctx, bytesutil.ToBytes32(r)); err != nil { 148 return err 149 } 150 151 reorgCount.Inc() 152 } 153 154 // Cache the new head info. 155 s.setHead(headRoot, newHeadBlock, newHeadState) 156 157 // Save the new head root to DB. 158 if err := s.cfg.BeaconDB.SaveHeadBlockRoot(ctx, headRoot); err != nil { 159 return errors.Wrap(err, "could not save head root in DB") 160 } 161 162 // Forward an event capturing a new chain head over a common event feed 163 // done in a goroutine to avoid blocking the critical runtime main routine. 164 go func() { 165 if err := s.notifyNewHeadEvent(newHeadSlot, newHeadState, newStateRoot, headRoot[:]); err != nil { 166 log.WithError(err).Error("Could not notify event feed of new chain head") 167 } 168 }() 169 170 return nil 171 } 172 173 // This gets called to update canonical root mapping. It does not save head block 174 // root in DB. With the inception of initial-sync-cache-state flag, it uses finalized 175 // check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis. 176 func (s *Service) saveHeadNoDB(ctx context.Context, b interfaces.SignedBeaconBlock, r [32]byte, hs iface.BeaconState) error { 177 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 178 return err 179 } 180 cachedHeadRoot, err := s.HeadRoot(ctx) 181 if err != nil { 182 return errors.Wrap(err, "could not get head root from cache") 183 } 184 if bytes.Equal(r[:], cachedHeadRoot) { 185 return nil 186 } 187 188 s.setHeadInitialSync(r, b.Copy(), hs) 189 return nil 190 } 191 192 // This sets head view object which is used to track the head slot, root, block and state. 193 func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) { 194 s.headLock.Lock() 195 defer s.headLock.Unlock() 196 197 // This does a full copy of the block and state. 198 s.head = &head{ 199 slot: block.Block().Slot(), 200 root: root, 201 block: block.Copy(), 202 state: state.Copy(), 203 } 204 } 205 206 // This sets head view object which is used to track the head slot, root, block and state. The method 207 // assumes that state being passed into the method will not be modified by any other alternate 208 // caller which holds the state's reference. 209 func (s *Service) setHeadInitialSync(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) { 210 s.headLock.Lock() 211 defer s.headLock.Unlock() 212 213 // This does a full copy of the block only. 214 s.head = &head{ 215 slot: block.Block().Slot(), 216 root: root, 217 block: block.Copy(), 218 state: state, 219 } 220 } 221 222 // This returns the head slot. 223 // This is a lock free version. 224 func (s *Service) headSlot() types.Slot { 225 return s.head.slot 226 } 227 228 // This returns the head root. 229 // It does a full copy on head root for immutability. 230 // This is a lock free version. 231 func (s *Service) headRoot() [32]byte { 232 if s.head == nil { 233 return params.BeaconConfig().ZeroHash 234 } 235 236 return s.head.root 237 } 238 239 // This returns the head block. 240 // It does a full copy on head block for immutability. 241 // This is a lock free version. 242 func (s *Service) headBlock() interfaces.SignedBeaconBlock { 243 return s.head.block.Copy() 244 } 245 246 // This returns the head state. 247 // It does a full copy on head state for immutability. 248 // This is a lock free version. 249 func (s *Service) headState(ctx context.Context) iface.BeaconState { 250 ctx, span := trace.StartSpan(ctx, "blockChain.headState") 251 defer span.End() 252 253 return s.head.state.Copy() 254 } 255 256 // This returns the genesis validator root of the head state. 257 // This is a lock free version. 258 func (s *Service) headGenesisValidatorRoot() [32]byte { 259 return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot()) 260 } 261 262 // Returns true if head state exists. 263 // This is the lock free version. 264 func (s *Service) hasHeadState() bool { 265 return s.head != nil && s.head.state != nil 266 } 267 268 // This caches justified state balances to be used for fork choice. 269 func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot [32]byte) error { 270 if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil { 271 return err 272 } 273 274 s.clearInitSyncBlocks() 275 276 var justifiedState iface.BeaconState 277 var err error 278 if justifiedRoot == s.genesisRoot { 279 justifiedState, err = s.cfg.BeaconDB.GenesisState(ctx) 280 if err != nil { 281 return err 282 } 283 } else { 284 justifiedState, err = s.cfg.StateGen.StateByRoot(ctx, justifiedRoot) 285 if err != nil { 286 return err 287 } 288 } 289 if justifiedState == nil || justifiedState.IsNil() { 290 return errors.New("justified state can't be nil") 291 } 292 293 epoch := helpers.CurrentEpoch(justifiedState) 294 295 justifiedBalances := make([]uint64, justifiedState.NumValidators()) 296 if err := justifiedState.ReadFromEveryValidator(func(idx int, val iface.ReadOnlyValidator) error { 297 if helpers.IsActiveValidatorUsingTrie(val, epoch) { 298 justifiedBalances[idx] = val.EffectiveBalance() 299 } else { 300 justifiedBalances[idx] = 0 301 } 302 return nil 303 }); err != nil { 304 return err 305 } 306 307 s.justifiedBalancesLock.Lock() 308 defer s.justifiedBalancesLock.Unlock() 309 s.justifiedBalances = justifiedBalances 310 return nil 311 } 312 313 func (s *Service) getJustifiedBalances() []uint64 { 314 s.justifiedBalancesLock.RLock() 315 defer s.justifiedBalancesLock.RUnlock() 316 return s.justifiedBalances 317 } 318 319 // Notifies a common event feed of a new chain head event. Called right after a new 320 // chain head is determined, set, and saved to disk. 321 func (s *Service) notifyNewHeadEvent( 322 newHeadSlot types.Slot, 323 newHeadState iface.BeaconState, 324 newHeadStateRoot, 325 newHeadRoot []byte, 326 ) error { 327 previousDutyDependentRoot := s.genesisRoot[:] 328 currentDutyDependentRoot := s.genesisRoot[:] 329 330 var previousDutyEpoch types.Epoch 331 currentDutyEpoch := helpers.SlotToEpoch(newHeadSlot) 332 if currentDutyEpoch > 0 { 333 previousDutyEpoch = currentDutyEpoch.Sub(1) 334 } 335 currentDutySlot, err := helpers.StartSlot(currentDutyEpoch) 336 if err != nil { 337 return errors.Wrap(err, "could not get duty slot") 338 } 339 previousDutySlot, err := helpers.StartSlot(previousDutyEpoch) 340 if err != nil { 341 return errors.Wrap(err, "could not get duty slot") 342 } 343 if currentDutySlot > 0 { 344 currentDutyDependentRoot, err = helpers.BlockRootAtSlot(newHeadState, currentDutySlot-1) 345 if err != nil { 346 return errors.Wrap(err, "could not get duty dependent root") 347 } 348 } 349 if previousDutySlot > 0 { 350 previousDutyDependentRoot, err = helpers.BlockRootAtSlot(newHeadState, previousDutySlot-1) 351 if err != nil { 352 return errors.Wrap(err, "could not get duty dependent root") 353 } 354 } 355 s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ 356 Type: statefeed.NewHead, 357 Data: ðpbv1.EventHead{ 358 Slot: newHeadSlot, 359 Block: newHeadRoot, 360 State: newHeadStateRoot, 361 EpochTransition: helpers.IsEpochEnd(newHeadSlot), 362 PreviousDutyDependentRoot: previousDutyDependentRoot, 363 CurrentDutyDependentRoot: currentDutyDependentRoot, 364 }, 365 }) 366 return nil 367 } 368 369 // This saves the attestations inside the beacon block with respect to root `orphanedRoot` back into the 370 // attestation pool. It also filters out the attestations that is one epoch older as a 371 // defense so invalid attestations don't flow into the attestation pool. 372 func (s *Service) saveOrphanedAtts(ctx context.Context, orphanedRoot [32]byte) error { 373 if !featureconfig.Get().CorrectlyInsertOrphanedAtts { 374 return nil 375 } 376 377 orphanedBlk, err := s.cfg.BeaconDB.Block(ctx, orphanedRoot) 378 if err != nil { 379 return err 380 } 381 382 if orphanedBlk == nil || orphanedBlk.IsNil() { 383 return errors.New("orphaned block can't be nil") 384 } 385 386 for _, a := range orphanedBlk.Block().Body().Attestations() { 387 // Is the attestation one epoch older. 388 if a.Data.Slot+params.BeaconConfig().SlotsPerEpoch < s.CurrentSlot() { 389 continue 390 } 391 if helpers.IsAggregated(a) { 392 if err := s.cfg.AttPool.SaveAggregatedAttestation(a); err != nil { 393 return err 394 } 395 } else { 396 if err := s.cfg.AttPool.SaveUnaggregatedAttestation(a); err != nil { 397 return err 398 } 399 } 400 saveOrphanedAttCount.Inc() 401 } 402 403 return nil 404 }