public async Task GenesisHead() { // Arrange var testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true); var state = TestState.PrepareTestState(testServiceProvider); var miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; var timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; var stateListLengths = testServiceProvider.GetService <IOptions <StateListLengths> >().Value; var maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; var options = new System.Text.Json.JsonSerializerOptions { WriteIndented = true }; options.AddCortexContainerConverters(); var debugState = System.Text.Json.JsonSerializer.Serialize(state, options); // Initialization var forkChoice = testServiceProvider.GetService <ForkChoice>(); var store = forkChoice.GetGenesisStore(state); // Act var headRoot = await forkChoice.GetHeadAsync(store); // Assert var stateRoot = state.HashTreeRoot(miscellaneousParameters, timeParameters, stateListLengths, maxOperationsPerBlock); var genesisBlock = new BeaconBlock(stateRoot); var expectedRoot = genesisBlock.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); headRoot.ShouldBe(expectedRoot); }
public async Task ChainNoAttestations() { // 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 ForkChoice forkChoice = testServiceProvider.GetService <ForkChoice>(); IStore store = forkChoice.GetGenesisStore(state); // On receiving a block of `GENESIS_SLOT + 1` slot BeaconBlock block1 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, state, signed: true); TestState.StateTransitionAndSignBlock(testServiceProvider, state, block1); AddBlockToStore(testServiceProvider, store, block1); // On receiving a block of next epoch BeaconBlock block2 = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, state, signed: true); TestState.StateTransitionAndSignBlock(testServiceProvider, state, block2); AddBlockToStore(testServiceProvider, store, block2); // Act Hash32 headRoot = await forkChoice.GetHeadAsync(store); // Assert Hash32 expectedRoot = block2.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); headRoot.ShouldBe(expectedRoot); }
public Hash32 SigningRoot(BeaconBlock beaconBlock) { MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; return(beaconBlock.SigningRoot(maxOperationsPerBlock.MaximumProposerSlashings, maxOperationsPerBlock.MaximumAttesterSlashings, maxOperationsPerBlock.MaximumAttestations, maxOperationsPerBlock.MaximumDeposits, maxOperationsPerBlock.MaximumVoluntaryExits, miscellaneousParameters.MaximumValidatorsPerCommittee)); }
public Hash32 SigningRoot(BeaconBlock beaconBlock) { // TODO: Signing root version of Nethermind SSZ; or are removed in later version of spec, so maybe just wait until then MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; return beaconBlock.SigningRoot(maxOperationsPerBlock.MaximumProposerSlashings, maxOperationsPerBlock.MaximumAttesterSlashings, maxOperationsPerBlock.MaximumAttestations, maxOperationsPerBlock.MaximumDeposits, maxOperationsPerBlock.MaximumVoluntaryExits, miscellaneousParameters.MaximumValidatorsPerCommittee); }
public static void SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex proposerIndex) { var miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; var timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; var maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; var signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; var beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); var 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}"); } var blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot); if (proposerIndex == ValidatorIndex.None) { if (block.Slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { var stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (stateEpoch + new Epoch(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 var stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, block.Slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } } var privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); var privateKey = privateKeys[(int)(ulong)proposerIndex]; var randaoDomain = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch); var randaoRevealHash = blockEpoch.HashTreeRoot(); var randaoReveal = TestSecurity.BlsSign(randaoRevealHash, privateKey, randaoDomain); block.Body.SetRandaoReveal(randaoReveal); var signatureDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch); var signingRoot = block.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); var 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); MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; MaxOperationsPerBlock maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; // Initialization 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); AddBlockToStore(testServiceProvider, store, longBlock); if (i == 2) { longRoot = longBlock.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); } } // 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); AddBlockToStore(testServiceProvider, store, shortBlock); Attestation shortAttestation = TestAttestation.GetValidAttestation(testServiceProvider, shortState, shortBlock.Slot, CommitteeIndex.None, signed: true); AddAttestationToStore(testServiceProvider, store, shortAttestation); // Act Hash32 headRoot = await forkChoice.GetHeadAsync(store); // Assert Hash32 expectedRoot = shortBlock.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); headRoot.ShouldBe(expectedRoot); headRoot.ShouldNotBe(longRoot); }
public void ProcessBlockHeader(BeaconState state, BeaconBlock block) { _logger.LogInformation(Event.ProcessBlock, "Process block header for block {BeaconBlock}", block); // Verify that the slots match if (block.Slot != state.Slot) { throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Block slot must match state slot {state.Slot}."); } // Verify that the parent matches var latestBlockSigningRoot = state.LatestBlockHeader.SigningRoot(); if (block.ParentRoot != latestBlockSigningRoot) { throw new ArgumentOutOfRangeException("block.ParentRoot", block.ParentRoot, $"Block parent root must match latest block header root {latestBlockSigningRoot}."); } // Save current block as the new latest block var bodyRoot = block.Body.HashTreeRoot(_miscellaneousParameterOptions.CurrentValue, _maxOperationsPerBlockOptions.CurrentValue); var newBlockHeader = new BeaconBlockHeader(block.Slot, block.ParentRoot, Hash32.Zero, // `state_root` is zeroed and overwritten in the next `process_slot` call bodyRoot, new BlsSignature() //`signature` is zeroed ); state.SetLatestBlockHeader(newBlockHeader); // Verify proposer is not slashed var beaconProposerIndex = _beaconStateAccessor.GetBeaconProposerIndex(state); var proposer = state.Validators[(int)(ulong)beaconProposerIndex]; if (proposer.IsSlashed) { throw new Exception("Beacon proposer must not be slashed."); } // Verify proposer signature var signingRoot = block.SigningRoot(_miscellaneousParameterOptions.CurrentValue, _maxOperationsPerBlockOptions.CurrentValue); var domain = _beaconStateAccessor.GetDomain(state, _signatureDomainOptions.CurrentValue.BeaconProposer, Epoch.None); var validSignature = _cryptographyService.BlsVerify(proposer.PublicKey, signingRoot, block.Signature, domain); if (!validSignature) { throw new Exception($"Block signature must match proposer public key {proposer.PublicKey}"); } }
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 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); AddBlockToStore(testServiceProvider, store, block1); Hash32 block1Root = block1.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); // 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); AddBlockToStore(testServiceProvider, store, block2); Hash32 block2Root = block2.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); // 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 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); }
private void RunOnBlock(IServiceProvider testServiceProvider, IStore store, BeaconBlock block, bool expectValid) { var miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; var maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; var forkChoice = testServiceProvider.GetService <ForkChoice>(); if (!expectValid) { Should.Throw <Exception>(() => { forkChoice.OnBlock(store, block); }); return; } forkChoice.OnBlock(store, block); var signingRoot = block.SigningRoot(miscellaneousParameters, maxOperationsPerBlock); var storeBlock = store.Blocks[signingRoot]; storeBlock.ShouldBe(block); }
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); } }