public void OnBlock(IStore store, BeaconBlock block) { // Make a copy of the state to avoid mutability issues if (!store.TryGetBlockState(block.ParentRoot, out var parentState)) { throw new ArgumentOutOfRangeException(nameof(block), block.ParentRoot, "Block parent root not found in the block states history."); } var preState = BeaconState.Clone(parentState); // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past. var blockTime = preState.GenesisTime + (ulong)block.Slot * _timeParameterOptions.CurrentValue.SecondsPerSlot; if (blockTime > store.Time) { throw new ArgumentOutOfRangeException(nameof(block), blockTime, $"Block slot time cannot be in the future, compared to store time {store.Time}."); } // Add new block to the store var signingRoot = block.SigningRoot(_miscellaneousParameterOptions.CurrentValue, _maxOperationsPerBlockOptions.CurrentValue); store.AddBlock(signingRoot, block); // Check block is a descendant of the finalized block if (!store.TryGetBlock(store.FinalizedCheckpoint.Root, out var finalizedCheckpointBlock)) { throw new Exception($"Block not found for finalized checkpoint root {store.FinalizedCheckpoint.Root}."); } var ancestor = GetAncestor(store, signingRoot, finalizedCheckpointBlock.Slot); if (ancestor != store.FinalizedCheckpoint.Root) { throw new Exception($"Block with signing root {signingRoot} is not a descendant of the finalized block {store.FinalizedCheckpoint.Root} at slot {finalizedCheckpointBlock.Slot}."); } // Check that block is later than the finalized epoch slot var finalizedEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch); if (block.Slot <= finalizedEpochStartSlot) { throw new ArgumentOutOfRangeException(nameof(block), block.Slot, $"Block slot must be later than the finalized epoch start slot {finalizedEpochStartSlot}."); } // Check the block is valid and compute the post-state var state = _beaconStateTransition.StateTransition(preState, block, validateStateRoot: true); // Add new state for this block to the store store.AddBlockState(signingRoot, state); _logger.LogInformation(Event.CreateGenesisStore, "Store added block {BeaconBlock} generating state {BeaconState}, with signing root {SigningRoot}", block, state, signingRoot); // Update justified checkpoint if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch) { store.SetBestJustifiedCheckpoint(state.CurrentJustifiedCheckpoint); var shouldUpdateJustifiedCheckpoint = ShouldUpdateJustifiedCheckpoint(store, state.CurrentJustifiedCheckpoint); if (shouldUpdateJustifiedCheckpoint) { store.SetJustifiedCheckpoint(state.CurrentJustifiedCheckpoint); _logger.LogDebug("Updated justified checkpoint {JustifiedCheckpoint}", state.CurrentJustifiedCheckpoint); } else { _logger.LogDebug("Updated best justified checkpoint {JustifiedCheckpoint}", state.CurrentJustifiedCheckpoint); } } // Update finalized checkpoint if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch) { store.SetFinalizedCheckpoint(state.FinalizedCheckpoint); _logger.LogDebug("Updated finalized checkpoint {FinalizedCheckpoint}", state.FinalizedCheckpoint); } }