public void FullAttestations() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(); BeaconState state = TestState.PrepareTestState(testServiceProvider); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); var attestations = PrepareStateWithFullAttestations(testServiceProvider, state); BeaconState preState = BeaconState.Clone(state); // Act RunProcessRewardsAndPenalties(testServiceProvider, state); // Assert var pendingAttestations = attestations.Select(x => new PendingAttestation(x.AggregationBits, x.Data, Slot.None, ValidatorIndex.None)); var attestingIndices = beaconStateTransition.GetUnslashedAttestingIndices(state, pendingAttestations).ToList(); attestingIndices.Count.ShouldBeGreaterThan(0); for (int index = 0; index < preState.Validators.Count; index++) { ValidatorIndex validatorIndex = new ValidatorIndex((ulong)index); if (attestingIndices.Contains(validatorIndex)) { state.Balances[index].ShouldBeGreaterThan(preState.Balances[index], $"Attesting balance {index}"); } else { state.Balances[index].ShouldBeLessThan(preState.Balances[index], $"Non-attesting balance {index}"); } } }
public static void SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex proposerIndex) { MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; MaxOperationsPerBlock maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); if (state.Slot > block.Slot) { throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}"); } Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot); if (proposerIndex == ValidatorIndex.None) { if (block.Slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (stateEpoch + 1 > blockEpoch) { Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given." + " Signing block is slow due to transition for proposer index calculation."); } // use stub state to get proposer index of future slot BeaconState stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, block.Slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } } byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); byte[] privateKey = privateKeys[(int)(ulong)proposerIndex]; Domain randaoDomain = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch); Hash32 randaoRevealHash = blockEpoch.HashTreeRoot(); BlsSignature randaoReveal = TestSecurity.BlsSign(randaoRevealHash, privateKey, randaoDomain); block.Body.SetRandaoReveal(randaoReveal); Domain signatureDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch); Hash32 signingRoot = cryptographyService.SigningRoot(block); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey, signatureDomain); block.SetSignature(signature); }
public async Task ShorterChainButHeavierWeight() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true); BeaconState state = TestState.PrepareTestState(testServiceProvider); // Initialization ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); IForkChoice forkChoice = testServiceProvider.GetService <IForkChoice>(); IStore store = testServiceProvider.GetService <IStore>(); await forkChoice.InitializeForkChoiceStoreAsync(store, state); BeaconState genesisState = BeaconState.Clone(state); // build longer tree Root longRoot = Root.Zero; BeaconState longState = BeaconState.Clone(genesisState); for (int i = 0; i < 3; i++) { BeaconBlock longBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, longState, BlsSignature.Zero); SignedBeaconBlock signedLongBlock = TestState.StateTransitionAndSignBlock(testServiceProvider, longState, longBlock); await AddBlockToStore(testServiceProvider, store, signedLongBlock); if (i == 2) { longRoot = cryptographyService.HashTreeRoot(longBlock); } } // build short tree BeaconState shortState = BeaconState.Clone(genesisState); BeaconBlock shortBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, shortState, BlsSignature.Zero); shortBlock.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray())); TestBlock.SignBlock(testServiceProvider, shortState, shortBlock, ValidatorIndex.None); SignedBeaconBlock signedShortBlock = TestState.StateTransitionAndSignBlock(testServiceProvider, shortState, shortBlock); await AddBlockToStore(testServiceProvider, store, signedShortBlock); Attestation shortAttestation = TestAttestation.GetValidAttestation(testServiceProvider, shortState, shortBlock.Slot, CommitteeIndex.None, signed: true); await AddAttestationToStore(testServiceProvider, store, shortAttestation); // Act Root headRoot = await forkChoice.GetHeadAsync(store); // Assert Root expectedRoot = cryptographyService.HashTreeRoot(shortBlock); headRoot.ShouldBe(expectedRoot); headRoot.ShouldNotBe(longRoot); }
public static SignedBeaconBlock SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex?optionalProposerIndex) { TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); if (state.Slot > block.Slot) { throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}"); } Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot); ValidatorIndex proposerIndex; if (optionalProposerIndex.HasValue) { proposerIndex = optionalProposerIndex.Value; } else { if (block.Slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (stateEpoch + 1 > blockEpoch) { Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given." + " Signing block is slow due to transition for proposer index calculation."); } // use stub state to get proposer index of future slot BeaconState stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, block.Slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } } byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); byte[] privateKey = privateKeys[(int)(ulong)proposerIndex]; Root blockHashTreeRoot = cryptographyService.HashTreeRoot(block); Domain proposerDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch); Root signingRoot = beaconChainUtility.ComputeSigningRoot(blockHashTreeRoot, proposerDomain); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey); return(new SignedBeaconBlock(block, signature)); }
public async Task ShorterChainButHeavierWeight() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true); BeaconState state = TestState.PrepareTestState(testServiceProvider); MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; MaxOperationsPerBlock maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; // Initialization ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); ForkChoice forkChoice = testServiceProvider.GetService <ForkChoice>(); IStore store = forkChoice.GetGenesisStore(state); BeaconState genesisState = BeaconState.Clone(state); // build longer tree Hash32 longRoot = default; BeaconState longState = BeaconState.Clone(genesisState); for (int i = 0; i < 3; i++) { BeaconBlock longBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, longState, signed: true); TestState.StateTransitionAndSignBlock(testServiceProvider, longState, longBlock); await AddBlockToStore(testServiceProvider, store, longBlock); if (i == 2) { longRoot = cryptographyService.SigningRoot(longBlock); } } // build short tree BeaconState shortState = BeaconState.Clone(genesisState); BeaconBlock shortBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, shortState, signed: true); shortBlock.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray())); TestBlock.SignBlock(testServiceProvider, shortState, shortBlock, ValidatorIndex.None); TestState.StateTransitionAndSignBlock(testServiceProvider, shortState, shortBlock); await AddBlockToStore(testServiceProvider, store, shortBlock); Attestation shortAttestation = TestAttestation.GetValidAttestation(testServiceProvider, shortState, shortBlock.Slot, CommitteeIndex.None, signed: true); await AddAttestationToStore(testServiceProvider, store, shortAttestation); // Act Hash32 headRoot = await forkChoice.GetHeadAsync(store); // Assert Hash32 expectedRoot = cryptographyService.SigningRoot(shortBlock); headRoot.ShouldBe(expectedRoot); headRoot.ShouldNotBe(longRoot); }
public void GenesisEpochFullAttestationsNoRewards() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(); BeaconState state = TestState.PrepareTestState(testServiceProvider); InitialValues initialValues = testServiceProvider.GetService <IOptions <InitialValues> >().Value; TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var attestations = new List <Attestation>(); for (Slot slot = Slot.Zero; slot < timeParameters.SlotsPerEpoch - new Slot(1); slot += new Slot(1)) { // create an attestation for each slot if (slot < timeParameters.SlotsPerEpoch) { Attestation attestation = TestAttestation.GetValidAttestation(testServiceProvider, state, slot, CommitteeIndex.None, signed: true); attestations.Add(attestation); } // fill each created slot in state after inclusion delay if (slot >= timeParameters.MinimumAttestationInclusionDelay) { Slot index = slot - timeParameters.MinimumAttestationInclusionDelay; Attestation includeAttestation = attestations[(int)(ulong)index]; TestAttestation.AddAttestationsToState(testServiceProvider, state, new[] { includeAttestation }, state.Slot); } TestState.NextSlot(testServiceProvider, state); } // ensure has not cross the epoch boundary Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); stateEpoch.ShouldBe(initialValues.GenesisEpoch); BeaconState preState = BeaconState.Clone(state); // Act RunProcessRewardsAndPenalties(testServiceProvider, state); // Assert for (int index = 0; index < preState.Validators.Count; index++) { state.Balances[index].ShouldBe(preState.Balances[index], $"Balance {index}"); } }
public async Task SplitTieBreakerNoAttestations() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true); BeaconState state = TestState.PrepareTestState(testServiceProvider); MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; MaxOperationsPerBlock maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; // Initialization ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); ForkChoice forkChoice = testServiceProvider.GetService <ForkChoice>(); IStore store = forkChoice.GetGenesisStore(state); BeaconState genesisState = BeaconState.Clone(state); // block at slot 1 BeaconState block1State = BeaconState.Clone(genesisState); BeaconBlock block1 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block1State, signed: true); TestState.StateTransitionAndSignBlock(testServiceProvider, block1State, block1); await AddBlockToStore(testServiceProvider, store, block1); Hash32 block1Root = cryptographyService.SigningRoot(block1); // build short tree BeaconState block2State = BeaconState.Clone(genesisState); BeaconBlock block2 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block2State, signed: true); block2.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray())); TestBlock.SignBlock(testServiceProvider, block2State, block2, ValidatorIndex.None); TestState.StateTransitionAndSignBlock(testServiceProvider, block2State, block2); await AddBlockToStore(testServiceProvider, store, block2); Hash32 block2Root = cryptographyService.SigningRoot(block2); // Act Hash32 headRoot = await forkChoice.GetHeadAsync(store); // Assert Console.WriteLine("block1 {0}", block1Root); Console.WriteLine("block2 {0}", block2Root); Hash32 highestRoot = block1Root.CompareTo(block2Root) > 0 ? block1Root : block2Root; Console.WriteLine("highest {0}", highestRoot); headRoot.ShouldBe(highestRoot); }
public async Task SplitTieBreakerNoAttestations() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true); BeaconState state = TestState.PrepareTestState(testServiceProvider); // Initialization ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); IForkChoice forkChoice = testServiceProvider.GetService <IForkChoice>(); IStore store = testServiceProvider.GetService <IStore>(); await forkChoice.InitializeForkChoiceStoreAsync(store, state); BeaconState genesisState = BeaconState.Clone(state); // block at slot 1 BeaconState block1State = BeaconState.Clone(genesisState); BeaconBlock block1 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block1State, BlsSignature.Zero); SignedBeaconBlock signedBlock1 = TestState.StateTransitionAndSignBlock(testServiceProvider, block1State, block1); await AddBlockToStore(testServiceProvider, store, signedBlock1); Root block1Root = cryptographyService.HashTreeRoot(block1); // build short tree BeaconState block2State = BeaconState.Clone(genesisState); BeaconBlock block2 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block2State, BlsSignature.Zero); block2.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray())); TestBlock.SignBlock(testServiceProvider, block2State, block2, ValidatorIndex.None); SignedBeaconBlock signedBlock2 = TestState.StateTransitionAndSignBlock(testServiceProvider, block2State, block2); await AddBlockToStore(testServiceProvider, store, signedBlock2); Root block2Root = cryptographyService.HashTreeRoot(block2); // Act Root headRoot = await forkChoice.GetHeadAsync(store); // Assert Console.WriteLine("block1 {0}", block1Root); Console.WriteLine("block2 {0}", block2Root); Root highestRoot = block1Root.CompareTo(block2Root) > 0 ? block1Root : block2Root; Console.WriteLine("highest {0}", highestRoot); headRoot.ShouldBe(highestRoot); }
public async Task InitializeForkChoiceStoreAsync(IStore store, BeaconState anchorState) { // Implements the logic for get_genesis_store / get_forkchoice_store Root stateRoot = !anchorState.LatestBlockHeader.StateRoot.Equals(Root.Zero) ? anchorState.LatestBlockHeader.StateRoot : _cryptographyService.HashTreeRoot(anchorState); BeaconBlock anchorBlock = new BeaconBlock(anchorState.Slot, anchorState.LatestBlockHeader.ParentRoot, stateRoot, BeaconBlockBody.Zero); SignedBeaconBlock signedAnchorBlock = new SignedBeaconBlock(anchorBlock, BlsSignature.Zero); Root anchorRoot = _cryptographyService.HashTreeRoot(anchorBlock); Epoch anchorEpoch = _beaconStateAccessor.GetCurrentEpoch(anchorState); Checkpoint justifiedCheckpoint = new Checkpoint(anchorEpoch, anchorRoot); Checkpoint finalizedCheckpoint = new Checkpoint(anchorEpoch, anchorRoot); if (_logger.IsInfo()) { Log.CreateGenesisStore(_logger, anchorState.Fork, anchorRoot, anchorState.GenesisTime, anchorState, anchorBlock, justifiedCheckpoint, null); } Dictionary <Root, SignedBeaconBlock> signedBlocks = new Dictionary <Root, SignedBeaconBlock> { [anchorRoot] = signedAnchorBlock }; Dictionary <Root, BeaconState> blockStates = new Dictionary <Root, BeaconState> { [anchorRoot] = BeaconState.Clone(anchorState) }; Dictionary <Checkpoint, BeaconState> checkpointStates = new Dictionary <Checkpoint, BeaconState> { [justifiedCheckpoint] = BeaconState.Clone(anchorState) }; await store.InitializeForkChoiceStoreAsync( anchorState.GenesisTime, anchorState.GenesisTime, justifiedCheckpoint, finalizedCheckpoint, justifiedCheckpoint, signedBlocks, blockStates, checkpointStates); }
public IStore GetGenesisStore(BeaconState genesisState) { MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; Hash32 stateRoot = _cryptographyService.HashTreeRoot(genesisState); BeaconBlock genesisBlock = new BeaconBlock(stateRoot); Hash32 root = _cryptographyService.SigningRoot(genesisBlock); Checkpoint justifiedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root); Checkpoint finalizedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root); if (_logger.IsInfo()) { Log.CreateGenesisStore(_logger, genesisBlock, genesisState, justifiedCheckpoint, root, null); } Dictionary <Hash32, BeaconBlock> blocks = new Dictionary <Hash32, BeaconBlock> { [root] = genesisBlock }; Dictionary <Hash32, BeaconState> blockStates = new Dictionary <Hash32, BeaconState> { [root] = BeaconState.Clone(genesisState) }; Dictionary <Checkpoint, BeaconState> checkpointStates = new Dictionary <Checkpoint, BeaconState> { [justifiedCheckpoint] = BeaconState.Clone(genesisState) }; IStore store = _storeProvider.CreateStore( genesisState.GenesisTime, genesisState.GenesisTime, justifiedCheckpoint, finalizedCheckpoint, justifiedCheckpoint, blocks, blockStates, checkpointStates, new Dictionary <ValidatorIndex, LatestMessage>() ); return(store); }
public IStore GetGenesisStore(BeaconState genesisState) { var miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; var maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; var stateRoot = genesisState.HashTreeRoot(miscellaneousParameters, _timeParameterOptions.CurrentValue, _stateListLengthOptions.CurrentValue, maxOperationsPerBlock); var genesisBlock = new BeaconBlock(stateRoot); var root = genesisBlock.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); var justifiedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root); var finalizedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root); _logger.LogInformation(Event.CreateGenesisStore, "Creating genesis store with block {BeaconBlock} for state {BeaconState}, with checkpoint {JustifiedCheckpoint}, with signing root {SigningRoot}", genesisBlock, genesisState, justifiedCheckpoint, root); var blocks = new Dictionary <Hash32, BeaconBlock> { [root] = genesisBlock }; var blockStates = new Dictionary <Hash32, BeaconState> { [root] = BeaconState.Clone(genesisState) }; var checkpointStates = new Dictionary <Checkpoint, BeaconState> { [justifiedCheckpoint] = BeaconState.Clone(genesisState) }; var store = _storeProvider.CreateStore( genesisState.GenesisTime, genesisState.GenesisTime, justifiedCheckpoint, finalizedCheckpoint, justifiedCheckpoint, blocks, blockStates, checkpointStates, new Dictionary <ValidatorIndex, LatestMessage>() ); return(store); }
public void GenesisEpochNoAttestationsNoPenalties() { // Arrange IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(); BeaconState state = TestState.PrepareTestState(testServiceProvider); InitialValues initialValues = testServiceProvider.GetService <IOptions <InitialValues> >().Value; BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconState preState = BeaconState.Clone(state); Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); stateEpoch.ShouldBe(initialValues.GenesisEpoch); // Act RunProcessRewardsAndPenalties(testServiceProvider, state); // Assert for (int index = 0; index < preState.Validators.Count; index++) { state.Balances[index].ShouldBe(preState.Balances[index], $"Balance {index}"); } }
public async Task OnBlockAsync(IStore store, BeaconBlock block) { MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; Hash32 signingRoot = _cryptographyService.SigningRoot(block); if (_logger.IsInfo()) { Log.OnBlock(_logger, signingRoot, block, null); } // Make a copy of the state to avoid mutability issues BeaconState parentState = await store.GetBlockStateAsync(block.ParentRoot).ConfigureAwait(false); BeaconState preState = BeaconState.Clone(parentState); // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past. ulong 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 await store.SetBlockAsync(signingRoot, block).ConfigureAwait(false); // Check block is a descendant of the finalized block BeaconBlock finalizedCheckpointBlock = await store.GetBlockAsync(store.FinalizedCheckpoint.Root).ConfigureAwait(false); Hash32 ancestor = await GetAncestorAsync(store, signingRoot, finalizedCheckpointBlock !.Slot).ConfigureAwait(false); 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 Slot 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 BeaconState state = _beaconStateTransition.StateTransition(preState, block, validateStateRoot: true); // Add new state for this block to the store await store.SetBlockStateAsync(signingRoot, state).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.AddedBlockToStore(_logger, block, state, signingRoot, null); } // Update justified checkpoint if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch) { await store.SetBestJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); bool shouldUpdateJustifiedCheckpoint = await ShouldUpdateJustifiedCheckpointAsync(store, state.CurrentJustifiedCheckpoint).ConfigureAwait(false); if (shouldUpdateJustifiedCheckpoint) { await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } else { if (_logger.IsDebug()) { LogDebug.UpdateBestJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } } // Update finalized checkpoint if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch) { await store.SetFinalizedCheckpointAsync(state.FinalizedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateFinalizedCheckpoint(_logger, state.FinalizedCheckpoint, null); } } }
/// <summary> /// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire. /// An ``attestation`` that is asserted as invalid may be valid at a later time, /// consider scheduling it for later processing in such case. /// </summary> public async Task OnAttestationAsync(IStore store, Attestation attestation) { if (_logger.IsInfo()) { Log.OnAttestation(_logger, attestation, null); } TimeParameters timeParameters = _timeParameterOptions.CurrentValue; Checkpoint target = attestation.Data.Target; // Attestations must be from the current or previous epoch Slot currentSlot = GetCurrentSlot(store); Epoch currentEpoch = _beaconChainUtility.ComputeEpochAtSlot(currentSlot); // Use GENESIS_EPOCH for previous when genesis to avoid underflow Epoch previousEpoch = currentEpoch > _chainConstants.GenesisEpoch ? currentEpoch - new Epoch(1) : _chainConstants.GenesisEpoch; if (target.Epoch != currentEpoch && target.Epoch != previousEpoch) { throw new ArgumentOutOfRangeException("attestation.Target.Epoch", target.Epoch, $"Attestation target epoch must be either the current epoch {currentEpoch} or previous epoch {previousEpoch}."); } Epoch dataSlotEpoch = _beaconChainUtility.ComputeEpochAtSlot(attestation.Data.Slot); if (attestation.Data.Target.Epoch != dataSlotEpoch) { throw new ArgumentOutOfRangeException("attestation.Data.Target.Epoch", attestation.Data.Target.Epoch, $"Attestation data target epoch must match the attestation data slot {attestation.Data.Slot} (epoch {dataSlotEpoch})."); } // Attestations target be for a known block. If target block is unknown, delay consideration until the block is found BeaconBlock targetBlock = (await store.GetSignedBlockAsync(target.Root).ConfigureAwait(false)).Message; // Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives BeaconState targetStoredState = await store.GetBlockStateAsync(target.Root).ConfigureAwait(false); BeaconState baseState = BeaconState.Clone(targetStoredState); Slot targetEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(target.Epoch); if (currentSlot < targetEpochStartSlot) { throw new Exception( $"Ättestation target epoch start slot {targetEpochStartSlot} should not be larger than the store current slot {currentSlot})."); } // Attestations must be for a known block. If block is unknown, delay consideration until the block is found BeaconBlock attestationBlock = (await store.GetSignedBlockAsync(attestation.Data.BeaconBlockRoot).ConfigureAwait(false)).Message; // Attestations must not be for blocks in the future. If not, the attestation should not be considered if (attestationBlock.Slot > attestation.Data.Slot) { throw new Exception( $"Attestation data root slot {attestationBlock.Slot} should not be larger than the attestation data slot {attestation.Data.Slot})."); } // Store target checkpoint state if not yet seen BeaconState?targetState = await store.GetCheckpointStateAsync(target, false).ConfigureAwait(false); if (targetState == null) { _beaconStateTransition.ProcessSlots(baseState, targetEpochStartSlot); await store.SetCheckpointStateAsync(target, baseState).ConfigureAwait(false); targetState = baseState; } // Attestations can only affect the fork choice of subsequent slots. // Delay consideration in the fork choice until their slot is in the past. Slot newCurrentSlot = GetCurrentSlot(store); if (newCurrentSlot < attestation.Data.Slot + 1) { throw new Exception( $"Attestation data slot {attestation.Data.Slot} should not be larger than the store current slot {newCurrentSlot})."); } // Get state at the `target` to validate attestation and calculate the committees IndexedAttestation indexedAttestation = _beaconStateAccessor.GetIndexedAttestation(targetState, attestation); Domain domain = _beaconStateAccessor.GetDomain(targetState, _signatureDomainOptions.CurrentValue.BeaconAttester, indexedAttestation.Data.Target.Epoch); bool isValid = _beaconChainUtility.IsValidIndexedAttestation(targetState, indexedAttestation, domain); if (!isValid) { throw new Exception($"Indexed attestation {indexedAttestation} is not valid."); } // Update latest messages IEnumerable <ValidatorIndex> attestingIndices = _beaconStateAccessor.GetAttestingIndices(targetState, attestation.Data, attestation.AggregationBits); foreach (ValidatorIndex index in attestingIndices) { LatestMessage?latestMessage = await store.GetLatestMessageAsync(index, false).ConfigureAwait(false); if (latestMessage == null || target.Epoch > latestMessage !.Epoch) { latestMessage = new LatestMessage(target.Epoch, attestation.Data.BeaconBlockRoot); await store.SetLatestMessageAsync(index, latestMessage).ConfigureAwait(false); } } }
public static BeaconBlock BuildEmptyBlock(IServiceProvider testServiceProvider, BeaconState state, Slot slot, BlsSignature randaoReveal) { //if (slot) is none TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); Eth1Data eth1Data = new Eth1Data(Root.Zero, state.Eth1DepositIndex, Bytes32.Zero); Root stateRoot = !state.LatestBlockHeader.StateRoot.Equals(Root.Zero) ? state.LatestBlockHeader.StateRoot : cryptographyService.HashTreeRoot(state); BeaconBlockHeader previousBlockHeader = new BeaconBlockHeader(state.LatestBlockHeader.Slot, state.LatestBlockHeader.ParentRoot, stateRoot, state.LatestBlockHeader.BodyRoot); Root previousBlockHashTreeRoot = cryptographyService.HashTreeRoot(previousBlockHeader); if (randaoReveal.Equals(BlsSignature.Zero)) { Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(slot); ValidatorIndex proposerIndex; if (slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (blockEpoch > stateEpoch + 1) { Console.WriteLine("WARNING: Block slot (epoch {0}) far away from state (epoch {1}), and no proposer index manually given." + " Signing block is slow due to transition for proposer index calculation.", blockEpoch, stateEpoch); } // use stub state to get proposer index of future slot BeaconState stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); byte[] privateKey = privateKeys[(int)(ulong)proposerIndex]; Domain randaoDomain = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch); Root epochHashTreeRoot = cryptographyService.HashTreeRoot(blockEpoch); Root randaoSigningRoot = beaconChainUtility.ComputeSigningRoot(epochHashTreeRoot, randaoDomain); randaoReveal = TestSecurity.BlsSign(randaoSigningRoot, privateKey); } BeaconBlock emptyBlock = new BeaconBlock(slot, previousBlockHashTreeRoot, Root.Zero, new BeaconBlockBody( randaoReveal, eth1Data, new Bytes32(), Array.Empty <ProposerSlashing>(), Array.Empty <AttesterSlashing>(), Array.Empty <Attestation>(), Array.Empty <Deposit>(), Array.Empty <SignedVoluntaryExit>() )); return(emptyBlock); }
/// <summary> /// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire. /// An ``attestation`` that is asserted as invalid may be valid at a later time, /// consider scheduling it for later processing in such case. /// </summary> public void OnAttestation(IStore store, Attestation attestation) { var initialValues = _initialValueOptions.CurrentValue; var timeParameters = _timeParameterOptions.CurrentValue; var target = attestation.Data.Target; // Attestations must be from the current or previous epoch var currentSlot = GetCurrentSlot(store); var currentEpoch = _beaconChainUtility.ComputeEpochAtSlot(currentSlot); // Use GENESIS_EPOCH for previous when genesis to avoid underflow var previousEpoch = currentEpoch > initialValues.GenesisEpoch ? currentEpoch - new Epoch(1) : initialValues.GenesisEpoch; if (target.Epoch != currentEpoch && target.Epoch != previousEpoch) { throw new ArgumentOutOfRangeException("attestation.Target.Epoch", target.Epoch, $"Attestation target epoch must be either the current epoch {currentEpoch} or previous epoch {previousEpoch}."); } // Cannot calculate the current shuffling if have not seen the target if (!store.TryGetBlock(target.Root, out var targetBlock)) { throw new ArgumentOutOfRangeException("attestation.Target.Root", target.Root, "Attestation target root not found in the block history."); } // Attestations target be for a known block. If target block is unknown, delay consideration until the block is found if (!store.TryGetBlockState(target.Root, out var targetStoredState)) { throw new ArgumentOutOfRangeException("attestation.Target.Root", target.Root, "Attestation target root not found in the block stores history."); } // Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives var baseState = BeaconState.Clone(targetStoredState); var targetEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(target.Epoch); var targetEpochStartSlotTime = baseState.GenesisTime + (ulong)targetEpochStartSlot * timeParameters.SecondsPerSlot; if (store.Time < targetEpochStartSlotTime) { throw new Exception($"Ättestation target state time {targetEpochStartSlotTime} should not be larger than the store time {store.Time})."); } // Attestations must be for a known block. If block is unknown, delay consideration until the block is found if (!store.TryGetBlock(attestation.Data.BeaconBlockRoot, out var attestationBlock)) { throw new ArgumentOutOfRangeException("attestation.Data.BeaconBlockRoot", attestation.Data.BeaconBlockRoot, "Attestation data root not found in the block history."); } // Attestations must not be for blocks in the future. If not, the attestation should not be considered if (attestationBlock.Slot > attestation.Data.Slot) { throw new Exception($"Ättestation data root slot {attestationBlock.Slot} should not be larger than the attestation data slot {attestation.Data.Slot})."); } // Store target checkpoint state if not yet seen if (!store.TryGetCheckpointState(target, out var targetState)) { _beaconStateTransition.ProcessSlots(baseState, targetEpochStartSlot); store.SetCheckpointState(target, baseState); targetState = baseState; } // Attestations can only affect the fork choice of subsequent slots. // Delay consideration in the fork choice until their slot is in the past. //var attestationDataSlotTime = ((ulong)attestation.Data.Slot + 1) * timeParameters.SecondsPerSlot; var attestationDataSlotTime = targetState.GenesisTime + ((ulong)attestation.Data.Slot + 1) * timeParameters.SecondsPerSlot; if (store.Time < attestationDataSlotTime) { throw new Exception($"Ättestation data time {attestationDataSlotTime} should not be larger than the store time {store.Time})."); } // Get state at the `target` to validate attestation and calculate the committees var indexedAttestation = _beaconStateAccessor.GetIndexedAttestation(targetState, attestation); var domain = _beaconStateAccessor.GetDomain(targetState, _signatureDomainOptions.CurrentValue.BeaconAttester, indexedAttestation.Data.Target.Epoch); var isValid = _beaconChainUtility.IsValidIndexedAttestation(targetState, indexedAttestation, domain); if (!isValid) { throw new Exception($"Indexed attestation {indexedAttestation} is not valid."); } // Update latest messages var attestingIndices = _beaconStateAccessor.GetAttestingIndices(targetState, attestation.Data, attestation.AggregationBits); foreach (var index in attestingIndices) { if (!store.TryGetLatestMessage(index, out var latestMessage) || target.Epoch > latestMessage.Epoch) { var newLatestMessage = new LatestMessage(target.Epoch, attestation.Data.BeaconBlockRoot); store.SetLatestMessage(index, newLatestMessage); } } }
public async Task <ValidatorDuty> GetValidatorDutyAsync(BlsPublicKey validatorPublicKey, Epoch epoch) { Root head = await _forkChoice.GetHeadAsync(_store).ConfigureAwait(false); BeaconState headState = await _store.GetBlockStateAsync(head).ConfigureAwait(false); Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState); Epoch nextEpoch = currentEpoch + Epoch.One; if (epoch == Epoch.None) { epoch = currentEpoch; } else if (epoch > nextEpoch) { throw new ArgumentOutOfRangeException(nameof(epoch), epoch, $"Duties cannot look ahead more than the next epoch {nextEpoch}."); } TimeParameters timeParameters = _timeParameterOptions.CurrentValue; Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch); Slot endSlot = startSlot + new Slot(timeParameters.SlotsPerEpoch); Duty duty = new Duty() { AttestationSlot = Slot.None, AttestationCommitteeIndex = CommitteeIndex.None, BlockProposalSlot = Slot.None }; if (epoch == nextEpoch) { // Clone for next or current, so that it can be safely mutated (transitioned forward) BeaconState state = BeaconState.Clone(headState); _beaconStateTransition.ProcessSlots(state, startSlot); // Check base state ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey); duty = CheckStateDuty(state, validatorIndex, duty); // Check future states duty = CheckFutureSlots(state, endSlot, validatorIndex, duty); } else if (epoch == currentEpoch) { // Take block slot and roots before cloning (for historical checks) IReadOnlyList <Root> historicalBlockRoots = headState.BlockRoots; Slot fromSlot = headState.Slot; BeaconState state = BeaconState.Clone(headState); // Check base state ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey); duty = CheckStateDuty(state, validatorIndex, duty); // Check future states duty = CheckFutureSlots(state, endSlot, validatorIndex, duty); // Check historical states if (startSlot < fromSlot && (duty.AttestationSlot == Slot.None || duty.BlockProposalSlot == Slot.None)) { duty = await CheckHistoricalSlotsAsync(_store, historicalBlockRoots, fromSlot, startSlot, validatorIndex, duty).ConfigureAwait(false); } } else { Root endRoot = await _forkChoice.GetAncestorAsync(_store, head, endSlot - Slot.One); BeaconState state = await _store.GetBlockStateAsync(endRoot).ConfigureAwait(false); // Check base state ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey); duty = CheckStateDuty(state, validatorIndex, duty); // Check historical states IReadOnlyList <Root> historicalBlockRoots = state.BlockRoots; if (duty.AttestationSlot == Slot.None || duty.BlockProposalSlot == Slot.None) { Slot fromSlot = state.Slot; duty = await CheckHistoricalSlotsAsync(_store, historicalBlockRoots, fromSlot, startSlot, validatorIndex, duty).ConfigureAwait(false); } } // HACK: Shards were removed from Phase 0, but analogy is committee index, so use for initial testing. Shard attestationShard = new Shard((ulong)duty.AttestationCommitteeIndex); ValidatorDuty validatorDuty = new ValidatorDuty(validatorPublicKey, duty.AttestationSlot, attestationShard, duty.BlockProposalSlot); return(validatorDuty); }
public void OnBlock(IStore store, BeaconBlock block) { // Make a copy of the state to avoid mutability issues if (!store.TryGetBlockState(block.ParentRoot, out BeaconState? parentState) || parentState is null) { 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.SetBlock(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}."); } Hash32 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.SetBlockState(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); } }
public async Task OnBlockAsync(IStore store, SignedBeaconBlock signedBlock) { MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; BeaconBlock block = signedBlock.Message; Root blockRoot = _cryptographyService.HashTreeRoot(block); if (_logger.IsInfo()) { Log.OnBlock(_logger, blockRoot, block, signedBlock.Signature, null); } // Make a copy of the state to avoid mutability issues BeaconState parentState = await store.GetBlockStateAsync(block.ParentRoot).ConfigureAwait(false); BeaconState preState = BeaconState.Clone(parentState); // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past. ulong storeTime = store.Time; Slot storeCurrentSlot = GetCurrentSlot(store); if (storeCurrentSlot < block.Slot) { throw new ArgumentOutOfRangeException(nameof(block), block.Slot, $"Block slot time cannot be in the future, compared to store time {storeTime} (slot {storeCurrentSlot}, since genesis {store.GenesisTime}."); } // Add new block to the store await store.SetSignedBlockAsync(blockRoot, signedBlock).ConfigureAwait(false); // Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor) Slot finalizedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch); if (block.Slot <= finalizedSlot) { throw new ArgumentOutOfRangeException(nameof(block), block.Slot, $"Block slot must be later than the finalized epoch start slot {finalizedSlot}."); } // Check block is a descendant of the finalized block at the checkpoint finalized slot Root ancestorOfBlockAtFinalizedSlot = await GetAncestorAsync(store, blockRoot, finalizedSlot).ConfigureAwait(false); if (!ancestorOfBlockAtFinalizedSlot.Equals(store.FinalizedCheckpoint.Root)) { throw new Exception( $"Block with hash tree root {blockRoot} is not a descendant of the finalized block {store.FinalizedCheckpoint.Root} at slot {finalizedSlot}."); } // Check the block is valid and compute the post-state BeaconState state = _beaconStateTransition.StateTransition(preState, signedBlock, validateResult: true); // Add new state for this block to the store await store.SetBlockStateAsync(blockRoot, state).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.AddedBlockToStore(_logger, block, state, blockRoot, null); } // Update justified checkpoint if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch) { if (state.CurrentJustifiedCheckpoint.Epoch > store.BestJustifiedCheckpoint.Epoch) { await store.SetBestJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); } bool shouldUpdateJustifiedCheckpoint = await ShouldUpdateJustifiedCheckpointAsync(store, state.CurrentJustifiedCheckpoint) .ConfigureAwait(false); if (shouldUpdateJustifiedCheckpoint) { await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } else { if (_logger.IsDebug()) { LogDebug.UpdateBestJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } } // Update finalized checkpoint if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch) { await store.SetFinalizedCheckpointAsync(state.FinalizedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateFinalizedCheckpoint(_logger, state.FinalizedCheckpoint, null); } // Update justified if new justified is later than store justified // or if store justified is not in chain with finalized checkpoint if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch) { await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } else { Slot newFinalizedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch); Root ancestorOfJustifiedAtNewFinalizedSlot = await GetAncestorAsync(store, store.JustifiedCheckpoint.Root, newFinalizedSlot) .ConfigureAwait(false); if (!ancestorOfJustifiedAtNewFinalizedSlot.Equals(store.FinalizedCheckpoint.Root)) { await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false); if (_logger.IsDebug()) { LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null); } } } } }
public async Task <IList <ValidatorDuty> > GetValidatorDutiesAsync( IList <BlsPublicKey> validatorPublicKeys, Epoch?optionalEpoch) { Root head = await _forkChoice.GetHeadAsync(_store).ConfigureAwait(false); BeaconState headState = await _store.GetBlockStateAsync(head).ConfigureAwait(false); Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState); Epoch epoch = optionalEpoch ?? currentEpoch; Epoch nextEpoch = currentEpoch + Epoch.One; if (epoch > nextEpoch) { throw new ArgumentOutOfRangeException(nameof(epoch), epoch, $"Duties cannot look ahead more than the next epoch {nextEpoch}."); } Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch); Root epochStartRoot = await _store.GetAncestorAsync(head, startSlot); TimeParameters timeParameters = _timeParameterOptions.CurrentValue; (Root epochStartRoot, Epoch epoch)cacheKey = (epochStartRoot, epoch); ConcurrentDictionary <BlsPublicKey, ValidatorDuty> dutiesForEpoch = await _validatorAssignmentsCache.Cache.GetOrCreateAsync(cacheKey, entry => { entry.SlidingExpiration = TimeSpan.FromSeconds(2 * timeParameters.SecondsPerSlot); return(Task.FromResult(new ConcurrentDictionary <BlsPublicKey, ValidatorDuty>())); }).ConfigureAwait(false); IEnumerable <BlsPublicKey> missingValidators = validatorPublicKeys.Except(dutiesForEpoch.Keys); if (missingValidators.Any()) { if (_logger.IsDebug()) { LogDebug.GettingMissingValidatorDutiesForCache(_logger, missingValidators.Count(), epoch, epochStartRoot, null); } BeaconState storedState = await _store.GetBlockStateAsync(epochStartRoot); // Clone, so that it can be safely mutated (transitioned forward) BeaconState state = BeaconState.Clone(storedState); // Transition to start slot, of target epoch (may have been a skip slot, i.e. stored state root may have been older) _beaconStateTransition.ProcessSlots(state, startSlot); // Check validators are valid (if not duties are empty). IList <DutyDetails> dutyDetailsList = new List <DutyDetails>(); foreach (BlsPublicKey validatorPublicKey in missingValidators) { ValidatorIndex?validatorIndex = FindValidatorIndexByPublicKey(state, validatorPublicKey); if (validatorIndex.HasValue) { bool validatorActive = CheckIfValidatorActive(state, validatorIndex.Value); if (validatorActive) { dutyDetailsList.Add(new DutyDetails(validatorPublicKey, validatorIndex.Value)); } else { if (_logger.IsWarn()) { Log.ValidatorNotActiveAtEpoch(_logger, epoch, validatorIndex.Value, validatorPublicKey, null); } dutiesForEpoch[validatorPublicKey] = new ValidatorDuty(validatorPublicKey, Slot.None, CommitteeIndex.None, Slot.None); } } else { if (_logger.IsWarn()) { Log.ValidatorNotFoundAtEpoch(_logger, epoch, validatorPublicKey, null); } dutiesForEpoch[validatorPublicKey] = new ValidatorDuty(validatorPublicKey, Slot.None, CommitteeIndex.None, Slot.None); } } if (dutyDetailsList.Any()) { // Check starting state UpdateDutyDetailsForState(dutyDetailsList, state); // Check other slots in epoch, if needed Slot endSlotExclusive = startSlot + new Slot(timeParameters.SlotsPerEpoch); Slot slotToCheck = startSlot + Slot.One; while (slotToCheck < endSlotExclusive) { _beaconStateTransition.ProcessSlots(state, slotToCheck); UpdateDutyDetailsForState(dutyDetailsList, state); slotToCheck += Slot.One; } // Active validators should always have attestation slots; warn if they don't foreach (var dutyDetails in dutyDetailsList) { if (!dutyDetails.AttestationSlot.HasValue) { if (_logger.IsWarn()) { Log.ValidatorDoesNotHaveAttestationSlot(_logger, epoch, dutyDetails.ValidatorPublicKey, null); } } } // Add to cached dictionary foreach (var dutyDetails in dutyDetailsList) { ValidatorDuty validatorDuty = new ValidatorDuty(dutyDetails.ValidatorPublicKey, dutyDetails.AttestationSlot, dutyDetails.AttestationCommitteeIndex, dutyDetails.BlockProposalSlot); dutiesForEpoch[dutyDetails.ValidatorPublicKey] = validatorDuty; } } } return(dutiesForEpoch .Where(x => validatorPublicKeys.Contains(x.Key)) .Select(x => x.Value) .ToList()); }
public async Task <Attestation> NewAttestationAsync(BlsPublicKey validatorPublicKey, bool proofOfCustodyBit, Slot slot, CommitteeIndex index, CancellationToken cancellationToken) { Root head = await _store.GetHeadAsync().ConfigureAwait(false); BeaconBlock headBlock = (await _store.GetSignedBlockAsync(head).ConfigureAwait(false)).Message; BeaconState parentState = await _store.GetBlockStateAsync(head).ConfigureAwait(false); // Clone state (will mutate) and process outstanding slots BeaconState headState = BeaconState.Clone(parentState); _beaconStateTransition.ProcessSlots(headState, slot); // Set attestation_data.index = index where index is the index associated with the validator's committee. ValidatorIndex?validatorIndex = FindValidatorIndexByPublicKey(headState, validatorPublicKey); if (validatorIndex == null) { throw new Exception($"Can not find validator index for public key {validatorPublicKey}"); } // TODO: May need a more efficient way to try and find the committee and position within the committee. // Some of this may already be cached in Validator Assignments (generally stable for an epoch), // but not with the index within the committee. Easy enough to extend and use the same cache. IReadOnlyList <ValidatorIndex> committee = _beaconStateAccessor.GetBeaconCommittee(headState, headState.Slot, index); int committeeSize = committee.Count; int?committeeMemberIndexOfValidator = null; for (int committeeMemberIndex = 0; committeeMemberIndex < committee.Count; committeeMemberIndex++) { if (committee[committeeMemberIndex] == validatorIndex) { committeeMemberIndexOfValidator = committeeMemberIndex; break; } } if (committeeMemberIndexOfValidator == null) { throw new Exception($"Validator index {validatorIndex} is not a member of committee {index}"); } Root beaconBlockRoot = _cryptographyService.HashTreeRoot(headBlock); Checkpoint source = headState.CurrentJustifiedCheckpoint; Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState); Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(currentEpoch); Root epochBoundaryBlockRoot; if (startSlot == headState.Slot) { epochBoundaryBlockRoot = beaconBlockRoot; } else { epochBoundaryBlockRoot = _beaconStateAccessor.GetBlockRootAtSlot(headState, startSlot); } Checkpoint target = new Checkpoint(currentEpoch, epochBoundaryBlockRoot); AttestationData attestationData = new AttestationData(slot, index, beaconBlockRoot, source, target); var aggregationBits = new BitArray(committeeSize); aggregationBits.Set(committeeMemberIndexOfValidator.Value, true); var attestation = new Attestation(aggregationBits, attestationData, BlsSignature.Zero); return(attestation); }