Search in sources :

Example 26 with ChainBuilder

use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.

the class ForkChoiceTest method onBlock_shouldReorgWhenProposerWeightingMakesForkBestChain.

@Test
void onBlock_shouldReorgWhenProposerWeightingMakesForkBestChain() {
    forkChoice = new ForkChoice(spec, new InlineEventThread(), recentChainData, forkChoiceNotifier, transitionBlockValidator, true);
    final UInt64 currentSlot = recentChainData.getCurrentSlot().orElseThrow();
    final UInt64 lateBlockSlot = currentSlot.minus(1);
    final ChainBuilder chainB = chainBuilder.fork();
    final SignedBlockAndState chainBBlock1 = chainB.generateBlockAtSlot(lateBlockSlot, BlockOptions.create().setEth1Data(new Eth1Data(Bytes32.ZERO, UInt64.valueOf(6), Bytes32.ZERO)));
    final SignedBlockAndState chainABlock1 = chainBuilder.generateBlockAtSlot(lateBlockSlot);
    // All blocks received late for slot 1
    importBlock(chainABlock1);
    importBlock(chainBBlock1);
    // At this point fork choice is tied with no votes for either chain
    // The winner is the block with the greatest hash which is hard to control.
    // So just find which block won and check that we can switch forks based on proposer reward
    final SignedBlockAndState expectedChainHead;
    if (recentChainData.getChainHead().orElseThrow().getRoot().equals(chainABlock1.getRoot())) {
        // ChainA won, so try to switch to chain B
        expectedChainHead = chainB.generateBlockAtSlot(currentSlot);
    } else {
        // ChainB won so try to switch to chain A
        expectedChainHead = chainBuilder.generateBlockAtSlot(currentSlot);
    }
    importBlock(expectedChainHead);
    assertThat(recentChainData.getStore().getProposerBoostRoot()).contains(expectedChainHead.getRoot());
    assertThat(forkChoice.processHead()).isCompleted();
    // Check we switched chains, if proposer reward wasn't considered we'd stay on the other fork
    assertThat(recentChainData.getBestBlockRoot()).contains(expectedChainHead.getRoot());
}
Also used : ChainBuilder(tech.pegasys.teku.core.ChainBuilder) InlineEventThread(tech.pegasys.teku.infrastructure.async.eventthread.InlineEventThread) UInt64(tech.pegasys.teku.infrastructure.unsigned.UInt64) SignedBlockAndState(tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState) Eth1Data(tech.pegasys.teku.spec.datastructures.blocks.Eth1Data) Test(org.junit.jupiter.api.Test)

Example 27 with ChainBuilder

use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.

the class AbstractDatabaseTest method orphanedBlockStorageTest_multiple.

@Test
public void orphanedBlockStorageTest_multiple() {
    createStorage(storageMode, StoreConfig.createDefault(), true);
    final ChainBuilder primaryChain = ChainBuilder.create(spec, VALIDATOR_KEYS);
    primaryChain.generateGenesis(genesisTime, true);
    primaryChain.generateBlocksUpToSlot(3);
    final ChainBuilder forkChain = primaryChain.fork();
    // Primary chain's next block is at 5
    primaryChain.generateBlockAtSlot(5);
    final ChainBuilder secondFork = primaryChain.fork();
    // Primary chain's next block is at 7
    final SignedBlockAndState finalizedBlock = primaryChain.generateBlockAtSlot(7);
    final Checkpoint finalizedCheckpoint = getCheckpointForBlock(primaryChain.getBlockAtSlot(7));
    final UInt64 firstHotBlockSlot = finalizedCheckpoint.getEpochStartSlot(spec).plus(UInt64.ONE);
    primaryChain.generateBlockAtSlot(firstHotBlockSlot);
    // Fork chain's next block is at 6
    forkChain.generateBlockAtSlot(6);
    forkChain.generateBlockAtSlot(firstHotBlockSlot);
    secondFork.generateBlockAtSlot(6);
    secondFork.generateBlockAtSlot(firstHotBlockSlot);
    // Setup database
    initGenesis();
    final Set<SignedBlockAndState> allBlocksAndStates = Streams.concat(primaryChain.streamBlocksAndStates(), forkChain.streamBlocksAndStates(), secondFork.streamBlocksAndStates()).collect(Collectors.toSet());
    // Finalize at block 7, making the fork blocks unavailable
    add(allBlocksAndStates);
    justifyAndFinalizeEpoch(finalizedCheckpoint.getEpoch(), finalizedBlock);
    assertThat(database.getNonCanonicalBlocksAtSlot(UInt64.valueOf(6)).size()).isEqualTo(2);
}
Also used : ChainBuilder(tech.pegasys.teku.core.ChainBuilder) Checkpoint(tech.pegasys.teku.spec.datastructures.state.Checkpoint) SignedBlockAndState(tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState) UInt64(tech.pegasys.teku.infrastructure.unsigned.UInt64) Test(org.junit.jupiter.api.Test)

Example 28 with ChainBuilder

use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.

the class AbstractDatabaseTest method testShouldRecordFinalizedBlocksAndStates.

protected void testShouldRecordFinalizedBlocksAndStates(final StateStorageMode storageMode, final boolean batchUpdate, Consumer<StateStorageMode> initializeDatabase) {
    // Setup chains
    // Both chains share block up to slot 3
    final ChainBuilder primaryChain = ChainBuilder.create(spec, VALIDATOR_KEYS);
    primaryChain.generateGenesis(genesisTime, true);
    primaryChain.generateBlocksUpToSlot(3);
    final ChainBuilder forkChain = primaryChain.fork();
    // Fork chain's next block is at 6
    forkChain.generateBlockAtSlot(6);
    forkChain.generateBlocksUpToSlot(7);
    // Primary chain's next block is at 7
    final SignedBlockAndState finalizedBlock = primaryChain.generateBlockAtSlot(7);
    final Checkpoint finalizedCheckpoint = getCheckpointForBlock(finalizedBlock.getBlock());
    final UInt64 pruneToSlot = finalizedCheckpoint.getEpochStartSlot(spec);
    // Add some blocks in the next epoch
    final UInt64 hotSlot = pruneToSlot.plus(UInt64.ONE);
    primaryChain.generateBlockAtSlot(hotSlot);
    forkChain.generateBlockAtSlot(hotSlot);
    // Setup database
    initializeDatabase.accept(storageMode);
    initGenesis();
    final Set<SignedBlockAndState> allBlocksAndStates = Streams.concat(primaryChain.streamBlocksAndStates(), forkChain.streamBlocksAndStates()).collect(Collectors.toSet());
    if (batchUpdate) {
        final StoreTransaction transaction = recentChainData.startStoreTransaction();
        add(transaction, allBlocksAndStates);
        justifyAndFinalizeEpoch(finalizedCheckpoint.getEpoch(), finalizedBlock, transaction);
        assertThat(transaction.commit()).isCompleted();
    } else {
        add(allBlocksAndStates);
        justifyAndFinalizeEpoch(finalizedCheckpoint.getEpoch(), finalizedBlock);
    }
    // Upon finalization, we should prune data
    final Set<Bytes32> blocksToPrune = Streams.concat(primaryChain.streamBlocksAndStates(0, pruneToSlot.longValue()), forkChain.streamBlocksAndStates(0, pruneToSlot.longValue())).map(SignedBlockAndState::getRoot).collect(Collectors.toSet());
    blocksToPrune.remove(finalizedBlock.getRoot());
    final Set<Checkpoint> checkpointsToPrune = Set.of(genesisCheckpoint);
    // Check data was pruned from store
    assertRecentDataWasPruned(store, blocksToPrune, checkpointsToPrune);
    restartStorage();
    // Check hot data
    final List<SignedBlockAndState> expectedHotBlocksAndStates = List.of(finalizedBlock, primaryChain.getBlockAndStateAtSlot(hotSlot));
    assertHotBlocksAndStates(store, expectedHotBlocksAndStates);
    final SignedBlockAndState prunedForkBlock = forkChain.getBlockAndStateAtSlot(hotSlot);
    assertThat(store.containsBlock(prunedForkBlock.getRoot())).isFalse();
    // Check finalized data
    final List<SignedBeaconBlock> expectedFinalizedBlocks = primaryChain.streamBlocksAndStates(0, 7).map(SignedBlockAndState::getBlock).collect(toList());
    assertBlocksFinalized(expectedFinalizedBlocks);
    assertGetLatestFinalizedRootAtSlotReturnsFinalizedBlocks(expectedFinalizedBlocks);
    assertBlocksAvailableByRoot(expectedFinalizedBlocks);
    assertFinalizedBlocksAvailableViaStream(1, 3, primaryChain.getBlockAtSlot(1), primaryChain.getBlockAtSlot(2), primaryChain.getBlockAtSlot(3));
    switch(storageMode) {
        case ARCHIVE:
            // Finalized states should be available
            final Map<Bytes32, BeaconState> expectedStates = primaryChain.streamBlocksAndStates(0, 7).collect(toMap(SignedBlockAndState::getRoot, SignedBlockAndState::getState));
            assertFinalizedStatesAvailable(expectedStates);
            break;
        case PRUNE:
            // Check pruned states
            final List<UInt64> unavailableSlots = allBlocksAndStates.stream().map(SignedBlockAndState::getSlot).collect(toList());
            assertStatesUnavailable(unavailableSlots);
            break;
    }
}
Also used : StoreTransaction(tech.pegasys.teku.storage.store.UpdatableStore.StoreTransaction) SignedBeaconBlock(tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock) Bytes32(org.apache.tuweni.bytes.Bytes32) BeaconState(tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState) ChainBuilder(tech.pegasys.teku.core.ChainBuilder) Checkpoint(tech.pegasys.teku.spec.datastructures.state.Checkpoint) SignedBlockAndState(tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState) UInt64(tech.pegasys.teku.infrastructure.unsigned.UInt64)

Example 29 with ChainBuilder

use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.

the class RecentChainDataTest method updateHead_reorgEventWhenChainSwitchesToNewBlockAtLaterSlot.

@Test
public void updateHead_reorgEventWhenChainSwitchesToNewBlockAtLaterSlot() {
    initPreGenesis();
    final ChainBuilder chainBuilder = ChainBuilder.create(spec, BLSKeyGenerator.generateKeyPairs(16));
    final SignedBlockAndState genesis = chainBuilder.generateGenesis();
    recentChainData.initializeFromGenesis(genesis.getState(), UInt64.ZERO);
    assertThat(storageSystem.chainHeadChannel().getReorgEvents()).isEmpty();
    chainBuilder.generateBlockAtSlot(1);
    // Set target slot at which to create duplicate blocks
    // and generate block options to make each block unique
    final List<BlockOptions> blockOptions = chainBuilder.streamValidAttestationsForBlockAtSlot(ONE).map(attestation -> BlockOptions.create().addAttestation(attestation)).limit(2).collect(toList());
    final ChainBuilder forkBuilder = chainBuilder.fork();
    final SignedBlockAndState latestBlockAndState = chainBuilder.generateBlockAtSlot(UInt64.valueOf(2), blockOptions.get(0));
    forkBuilder.generateBlockAtSlot(UInt64.valueOf(2), blockOptions.get(1));
    // Fork extends a slot further
    final SignedBlockAndState latestForkBlockAndState = forkBuilder.generateBlockAtSlot(3);
    importBlocksAndStates(recentChainData, chainBuilder, forkBuilder);
    // Update to head block of original chain.
    recentChainData.updateHead(latestBlockAndState.getRoot(), latestBlockAndState.getSlot());
    assertThat(storageSystem.chainHeadChannel().getReorgEvents()).isEmpty();
    // Switch to fork.
    recentChainData.updateHead(latestForkBlockAndState.getRoot(), latestForkBlockAndState.getSlot());
    // Check reorg event
    assertThat(storageSystem.chainHeadChannel().getReorgEvents()).containsExactly(new ReorgEvent(latestForkBlockAndState.getRoot(), latestForkBlockAndState.getSlot(), latestForkBlockAndState.getStateRoot(), latestBlockAndState.getRoot(), latestBlockAndState.getStateRoot(), ONE));
}
Also used : ChainBuilder(tech.pegasys.teku.core.ChainBuilder) BlockOptions(tech.pegasys.teku.core.ChainBuilder.BlockOptions) SignedBlockAndState(tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState) ReorgEvent(tech.pegasys.teku.storage.api.TrackingChainHeadChannel.ReorgEvent) Test(org.junit.jupiter.api.Test)

Example 30 with ChainBuilder

use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.

the class AbstractDatabaseTest method shouldPruneHotBlocksInCurrentTransactionFromChainThatIsInvalided.

@Test
public void shouldPruneHotBlocksInCurrentTransactionFromChainThatIsInvalided() {
    final UInt64 commonAncestorSlot = UInt64.valueOf(5);
    chainBuilder.generateBlocksUpToSlot(commonAncestorSlot);
    final ChainBuilder forkA = chainBuilder;
    final ChainBuilder forkB = chainBuilder.fork();
    // Add base blocks
    addBlocks(chainBuilder.streamBlocksAndStates().collect(toList()));
    // Forks diverge - generate block options to make each block unique
    final UInt64 divergingSlot = commonAncestorSlot.plus(1);
    final List<BlockOptions> blockOptions = chainBuilder.streamValidAttestationsForBlockAtSlot(divergingSlot).map(attestation -> BlockOptions.create().addAttestation(attestation)).limit(2).collect(toList());
    // Create several different blocks at the same slot
    final SignedBlockAndState blockA = forkA.generateBlockAtSlot(divergingSlot, blockOptions.get(0));
    final SignedBlockAndState blockB = forkB.generateBlockAtSlot(divergingSlot, blockOptions.get(1));
    // Add diverging blocks sequentially
    add(List.of(blockA));
    add(List.of(blockB));
    // Then build on both chains, into the next epoch
    final SignedBlockAndState blockA2 = forkA.generateBlockAtSlot(spec.slotsPerEpoch(ZERO) * 2 + 2);
    final SignedBlockAndState blockB2 = forkB.generateBlockAtSlot(spec.slotsPerEpoch(ZERO) * 2 + 2);
    // Add blocks while finalizing blockA at the same time
    StoreTransaction tx = recentChainData.startStoreTransaction();
    tx.putBlockAndState(blockA2);
    tx.putBlockAndState(blockB2);
    justifyAndFinalizeEpoch(UInt64.ONE, blockA, tx);
    assertThat(tx.commit()).isCompleted();
    // Verify all fork B blocks were pruned
    assertThatSafeFuture(store.retrieveBlock(blockB.getRoot())).isCompletedWithEmptyOptional();
    assertThatSafeFuture(store.retrieveBlock(blockB2.getRoot())).isCompletedWithEmptyOptional();
    // And fork A should be available.
    assertThat(store.retrieveSignedBlock(blockA.getRoot())).isCompletedWithValue(Optional.of(blockA.getBlock()));
    assertThat(store.retrieveSignedBlock(blockA2.getRoot())).isCompletedWithValue(Optional.of(blockA2.getBlock()));
}
Also used : ChainBuilder(tech.pegasys.teku.core.ChainBuilder) BlockOptions(tech.pegasys.teku.core.ChainBuilder.BlockOptions) StoreTransaction(tech.pegasys.teku.storage.store.UpdatableStore.StoreTransaction) UInt64(tech.pegasys.teku.infrastructure.unsigned.UInt64) SignedBlockAndState(tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState) Test(org.junit.jupiter.api.Test)

Aggregations

ChainBuilder (tech.pegasys.teku.core.ChainBuilder)33 SignedBlockAndState (tech.pegasys.teku.spec.datastructures.blocks.SignedBlockAndState)30 Test (org.junit.jupiter.api.Test)27 UInt64 (tech.pegasys.teku.infrastructure.unsigned.UInt64)18 BlockOptions (tech.pegasys.teku.core.ChainBuilder.BlockOptions)7 Checkpoint (tech.pegasys.teku.spec.datastructures.state.Checkpoint)6 Bytes32 (org.apache.tuweni.bytes.Bytes32)5 SignedBeaconBlock (tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock)5 AnchorPoint (tech.pegasys.teku.spec.datastructures.state.AnchorPoint)5 Eth1Data (tech.pegasys.teku.spec.datastructures.blocks.Eth1Data)4 StoreTransaction (tech.pegasys.teku.storage.store.UpdatableStore.StoreTransaction)4 Attestation (tech.pegasys.teku.spec.datastructures.operations.Attestation)3 ChainUpdater (tech.pegasys.teku.storage.client.ChainUpdater)3 HashSet (java.util.HashSet)2 AttestationGenerator (tech.pegasys.teku.core.AttestationGenerator)2 BlockAndCheckpointEpochs (tech.pegasys.teku.spec.datastructures.blocks.BlockAndCheckpointEpochs)2 BeaconState (tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState)2 ReorgEvent (tech.pegasys.teku.storage.api.TrackingChainHeadChannel.ReorgEvent)2 StorageSystem (tech.pegasys.teku.storage.storageSystem.StorageSystem)2 ArrayList (java.util.ArrayList)1