use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.
the class ForkChoiceTest method onBlock_shouldNotProcessAttestationsForBlocksThatDoNotYetExist.
@Test
void onBlock_shouldNotProcessAttestationsForBlocksThatDoNotYetExist() {
final ChainBuilder forkChain = chainBuilder.fork();
// Create a fork block, but don't import it.
final SignedBlockAndState forkBlock = forkChain.generateBlockAtSlot(UInt64.valueOf(2), BlockOptions.create().setEth1Data(new Eth1Data(Bytes32.ZERO, UInt64.valueOf(6), Bytes32.ZERO)));
// Now create the canonical chain and import.
final List<SignedBlockAndState> betterChain = chainBuilder.generateBlocksUpToSlot(3);
betterChain.forEach(this::importBlock);
// And create a block containing an attestation for forkBlock
final BlockOptions options = BlockOptions.create();
final Attestation attestation = chainBuilder.streamValidAttestationsWithTargetBlock(forkBlock).findFirst().orElseThrow(() -> new IllegalStateException("Failed to create attestation for block " + forkBlock.getRoot() + " genesis root: " + genesis.getRoot() + " chain head: " + chainBuilder.getLatestBlockAndState().getRoot() + " fork block: " + forkBlock.getRoot() + " validators: " + chainBuilder.getValidatorKeys().stream().map(BLSKeyPair::getPublicKey).map(BLSPublicKey::toString).collect(Collectors.joining(", "))));
options.addAttestation(attestation);
final SignedBlockAndState blockWithAttestations = chainBuilder.generateBlockAtSlot(UInt64.valueOf(4), options);
importBlock(blockWithAttestations);
// Apply these votes
processHead(blockWithAttestations.getSlot());
assertThat(recentChainData.getBestBlockRoot()).contains(blockWithAttestations.getRoot());
// Now we import the fork block
importBlock(forkBlock);
// Then we get a later attestation from the same validator pointing to a different chain
final UInt64 updatedAttestationSlot = applyAttestationFromValidator(UInt64.ZERO, blockWithAttestations);
// And we should be able to apply the new weightings without making the fork block's weight
// negative
assertDoesNotThrow(() -> forkChoice.processHead(updatedAttestationSlot));
}
use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.
the class ForkChoiceTest method onBlock_shouldNotifyOptimisticSyncChangeOnlyWhenImportingOnCanonicalHead.
@Test
void onBlock_shouldNotifyOptimisticSyncChangeOnlyWhenImportingOnCanonicalHead() {
doMerge();
UInt64 slotToImport = prepFinalizeEpoch(2);
// since protoArray initializes with optimistic nodes,
// we expect a first notification to be optimistic false
verify(optimisticSyncStateTracker).onOptimisticHeadChanged(false);
final SignedBlockAndState epoch4Block = chainBuilder.generateBlockAtSlot(slotToImport);
importBlock(epoch4Block);
slotToImport = prepFinalizeEpoch(4);
// make EL returning SYNCING
executionEngine.setPayloadStatus(PayloadStatus.SYNCING);
// generate block which finalize epoch 4
final SignedBlockAndState epoch6Block = chainBuilder.generateBlockAtSlot(slotToImport);
importBlockOptimistically(epoch6Block);
verify(optimisticSyncStateTracker).onOptimisticHeadChanged(true);
UInt64 forkSlot = slotToImport.increment();
storageSystem.chainUpdater().setCurrentSlot(forkSlot);
ChainBuilder alternativeChain = chainBuilder.fork();
// make EL returning SYNCING
executionEngine.setPayloadStatus(PayloadStatus.VALID);
importBlock(chainBuilder.generateBlockAtSlot(forkSlot));
verify(optimisticSyncStateTracker, times(2)).onOptimisticHeadChanged(false);
// builds atop the canonical chain
storageSystem.chainUpdater().setCurrentSlot(forkSlot.plus(1));
importBlock(chainBuilder.generateBlockAtSlot(forkSlot.plus(1)));
// make EL returning SYNCING
executionEngine.setPayloadStatus(PayloadStatus.SYNCING);
// import a fork which won't be canonical
importBlockOptimistically(alternativeChain.generateBlockAtSlot(forkSlot));
// no notification is expected
verifyNoMoreInteractions(optimisticSyncStateTracker);
}
use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.
the class RecentChainDataTest method testCommitPruningOfParallelBlocks.
/**
* Builds 2 parallel chains, one of which will get pruned when a block in the middle of the other
* chain is finalized. Keep one chain in the finalizing transaction, the other chain is already
* saved to the store.
*
* @param pruneNewBlocks Whether to keep the blocks to be pruned in the finalizing transaction, or
* keep the blocks to be kept in the finalizing transaction @
*/
private void testCommitPruningOfParallelBlocks(final boolean pruneNewBlocks) {
final UInt64 epoch2Slot = spec.computeStartSlotAtEpoch(UInt64.valueOf(2));
// Create a fork by skipping the next slot on the fork chain
ChainBuilder fork = chainBuilder.fork();
// Generate the next 2 blocks on the primary chain
final SignedBlockAndState firstCanonicalBlock = chainBuilder.generateNextBlock();
saveBlock(recentChainData, firstCanonicalBlock);
saveBlock(recentChainData, chainBuilder.generateNextBlock());
// Skip a block and then generate the next block on the fork chain
final SignedBlockAndState firstForkBlock = fork.generateNextBlock(1);
saveBlock(recentChainData, firstForkBlock);
// Build both the primary and fork chain past epoch1
// Make sure both chains are at the same slot
assertThat(chainBuilder.getLatestSlot()).isEqualTo(fork.getLatestSlot());
while (chainBuilder.getLatestSlot().compareTo(epoch2Slot) < 0) {
chainBuilder.generateNextBlock();
fork.generateNextBlock();
}
// Save one chain to the store, setup the other chain to be saved in the finalizing transaction
final List<SignedBlockAndState> newBlocks = new ArrayList<>();
if (pruneNewBlocks) {
// Save canonical blocks now, put fork blocks in the transaction
chainBuilder.streamBlocksAndStates(firstCanonicalBlock.getSlot()).forEach(b -> saveBlock(recentChainData, b));
fork.streamBlocksAndStates(firstForkBlock.getSlot()).forEach(newBlocks::add);
} else {
// Save fork blocks now, put canonical blocks in the transaction
chainBuilder.streamBlocksAndStates(firstCanonicalBlock.getSlot()).forEach(newBlocks::add);
fork.streamBlocksAndStates(firstForkBlock.getSlot()).forEach(b -> saveBlock(recentChainData, b));
}
// Add blocks and finalize epoch 1, so that blocks will be pruned
final StoreTransaction tx = recentChainData.startStoreTransaction();
final Checkpoint finalizedCheckpoint = chainBuilder.getCurrentCheckpointForEpoch(1);
tx.setFinalizedCheckpoint(finalizedCheckpoint);
newBlocks.forEach(tx::putBlockAndState);
tx.commit().reportExceptions();
// Check that only recent, canonical blocks at or after the latest finalized block are left in
// the store
final List<SignedBlockAndState> expectedBlocks = chainBuilder.streamBlocksAndStates(finalizedCheckpoint.getEpochStartSlot(spec)).collect(Collectors.toList());
final Set<Bytes32> blockRoots = expectedBlocks.stream().map(SignedBlockAndState::getRoot).collect(Collectors.toSet());
// Collect blocks that should be pruned
final Set<Bytes32> prunedBlocks = fork.streamBlocksAndStates(firstForkBlock.getSlot()).map(SignedBlockAndState::getRoot).collect(Collectors.toSet());
// Check expected blocks
assertThat(recentChainData.getStore().getOrderedBlockRoots()).containsExactlyInAnyOrderElementsOf(blockRoots);
for (SignedBlockAndState expectedBlock : expectedBlocks) {
assertThat(recentChainData.retrieveSignedBlockByRoot(expectedBlock.getRoot())).isCompletedWithValue(Optional.of(expectedBlock.getBlock()));
assertThat(recentChainData.retrieveBlockState(expectedBlock.getRoot())).isCompletedWithValue(Optional.of(expectedBlock.getState()));
}
// Check pruned blocks
for (Bytes32 prunedBlock : prunedBlocks) {
assertThatSafeFuture(recentChainData.retrieveSignedBlockByRoot(prunedBlock)).isCompletedWithEmptyOptional();
assertThat(recentChainData.retrieveBlockState(prunedBlock)).isCompletedWithValue(Optional.empty());
}
}
use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.
the class RecentChainDataTest method initializeFromAnchorPoint_withTimeLessThanGenesisTime.
@Test
public void initializeFromAnchorPoint_withTimeLessThanGenesisTime() {
initPreGenesis();
final ChainBuilder chainBuilder = ChainBuilder.create(spec);
final UInt64 genesisTime = UInt64.valueOf(5000);
chainBuilder.generateGenesis(genesisTime, true);
// Build a small chain
chainBuilder.generateBlocksUpToSlot(10);
final SignedBlockAndState anchor = chainBuilder.generateNextBlock();
final AnchorPoint anchorPoint = AnchorPoint.fromInitialState(spec, anchor.getState());
final UInt64 anchorBlockTime = anchorPoint.getBlockSlot().times(genesisSpecConfig.getSecondsPerSlot()).plus(genesisTime);
recentChainData.initializeFromAnchorPoint(anchorPoint, UInt64.valueOf(100));
assertThat(recentChainData.getStore().getTime()).isEqualTo(anchorBlockTime);
}
use of tech.pegasys.teku.core.ChainBuilder in project teku by ConsenSys.
the class RecentChainDataTest method initializeFromAnchorPoint_withTimeGreaterThanAnchorBlockTime.
@Test
public void initializeFromAnchorPoint_withTimeGreaterThanAnchorBlockTime() {
initPreGenesis();
final ChainBuilder chainBuilder = ChainBuilder.create(spec);
final UInt64 genesisTime = UInt64.valueOf(5000);
chainBuilder.generateGenesis(genesisTime, true);
// Build a small chain
chainBuilder.generateBlocksUpToSlot(10);
final SignedBlockAndState anchor = chainBuilder.generateNextBlock();
final AnchorPoint anchorPoint = AnchorPoint.fromInitialState(spec, anchor.getState());
final UInt64 anchorBlockTime = anchorPoint.getBlockSlot().times(genesisSpecConfig.getSecondsPerSlot()).plus(genesisTime);
final UInt64 time = anchorBlockTime.plus(100);
recentChainData.initializeFromAnchorPoint(anchorPoint, time);
assertThat(recentChainData.getStore().getTime()).isEqualTo(time);
}
Aggregations