Skip to content

Commit cf60080

Browse files
committed
Merge remote-tracking branch 'origin/unstable' into queue-http-attestations
2 parents 6043b0c + e7ef2a3 commit cf60080

File tree

30 files changed

+441
-352
lines changed

30 files changed

+441
-352
lines changed

Cargo.lock

Lines changed: 24 additions & 72 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ tree_hash = "0.5"
170170
tree_hash_derive = "0.5"
171171
url = "2"
172172
uuid = { version = "0.8", features = ["serde", "v4"] }
173-
# TODO update to warp 0.3.6 after released.
174-
warp = { git = "https://github.com/seanmonstar/warp.git", default-features = false, features = ["tls"] }
173+
warp = { version = "0.3.6", default-features = false, features = ["tls"] }
175174
zeroize = { version = "1", features = ["zeroize_derive"] }
176175
zip = "0.6"
177176

@@ -235,6 +234,3 @@ inherits = "release"
235234
lto = "fat"
236235
codegen-units = 1
237236
incremental = false
238-
239-
[patch.crates-io]
240-
curve25519-dalek = { git = "https://github.com/jimmygchen/curve25519-dalek.git", rev = "24019783e9bb9dc1464e7e503732f273a69969c6" }

beacon_node/beacon_chain/tests/payload_invalidation.rs

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,81 +1820,94 @@ struct InvalidHeadSetup {
18201820
}
18211821

18221822
impl InvalidHeadSetup {
1823+
/// This function aims to produce two things:
1824+
///
1825+
/// 1. A chain where the only viable head block has an invalid execution payload.
1826+
/// 2. A block (`fork_block`) which will become the head of the chain when
1827+
/// it is imported.
18231828
async fn new() -> InvalidHeadSetup {
1829+
let slots_per_epoch = E::slots_per_epoch();
18241830
let mut rig = InvalidPayloadRig::new().enable_attestations();
18251831
rig.move_to_terminal_block();
18261832
rig.import_block(Payload::Valid).await; // Import a valid transition block.
18271833

1828-
// Import blocks until the first time the chain finalizes.
1834+
// Import blocks until the first time the chain finalizes. This avoids
1835+
// some edge-cases around genesis.
18291836
while rig.cached_head().finalized_checkpoint().epoch == 0 {
18301837
rig.import_block(Payload::Syncing).await;
18311838
}
18321839

1833-
let slots_per_epoch = E::slots_per_epoch();
1834-
let start_slot = rig.cached_head().head_slot() + 1;
1835-
let mut opt_fork_block = None;
1836-
1837-
assert_eq!(start_slot % slots_per_epoch, 1);
1838-
for i in 0..slots_per_epoch - 1 {
1839-
let slot = start_slot + i;
1840-
let slot_offset = slot.as_u64() % slots_per_epoch;
1841-
1842-
rig.harness.set_current_slot(slot);
1843-
1844-
if slot_offset == slots_per_epoch - 1 {
1845-
// Optimistic head block right before epoch boundary.
1846-
let is_valid = Payload::Syncing;
1847-
rig.import_block_parametric(is_valid, is_valid, Some(slot), |error| {
1848-
matches!(
1849-
error,
1850-
BlockError::ExecutionPayloadError(
1851-
ExecutionPayloadError::RejectedByExecutionEngine { .. }
1852-
)
1853-
)
1854-
})
1855-
.await;
1856-
} else if 3 * slot_offset < 2 * slots_per_epoch {
1857-
// Valid block in previous epoch.
1858-
rig.import_block(Payload::Valid).await;
1859-
} else if slot_offset == slots_per_epoch - 2 {
1860-
// Fork block one slot prior to invalid head, not applied immediately.
1861-
let parent_state = rig
1862-
.harness
1863-
.chain
1864-
.state_at_slot(slot - 1, StateSkipConfig::WithStateRoots)
1865-
.unwrap();
1866-
let (fork_block_tuple, _) = rig.harness.make_block(parent_state, slot).await;
1867-
opt_fork_block = Some(fork_block_tuple.0);
1868-
} else {
1869-
// Skipped slot.
1870-
};
1840+
// Define a helper function.
1841+
let chain = rig.harness.chain.clone();
1842+
let get_unrealized_justified_epoch = move || {
1843+
chain
1844+
.canonical_head
1845+
.fork_choice_read_lock()
1846+
.unrealized_justified_checkpoint()
1847+
.epoch
1848+
};
1849+
1850+
// Import more blocks until there is a new and higher unrealized
1851+
// justified checkpoint.
1852+
//
1853+
// The result will be a single chain where the head block has a higher
1854+
// unrealized justified checkpoint than all other blocks in the chain.
1855+
let initial_unrealized_justified = get_unrealized_justified_epoch();
1856+
while get_unrealized_justified_epoch() == initial_unrealized_justified {
1857+
rig.import_block(Payload::Syncing).await;
18711858
}
18721859

1860+
// Create a forked block that competes with the head block. Both the
1861+
// head block and this fork block will share the same parent.
1862+
//
1863+
// The fork block and head block will both have an unrealized justified
1864+
// checkpoint at epoch `N` whilst their parent is at `N - 1`.
1865+
let head_slot = rig.cached_head().head_slot();
1866+
let parent_slot = head_slot - 1;
1867+
let fork_block_slot = head_slot + 1;
1868+
let parent_state = rig
1869+
.harness
1870+
.chain
1871+
.state_at_slot(parent_slot, StateSkipConfig::WithStateRoots)
1872+
.unwrap();
1873+
let (fork_block_tuple, _) = rig.harness.make_block(parent_state, fork_block_slot).await;
1874+
let fork_block = fork_block_tuple.0;
1875+
18731876
let invalid_head = rig.cached_head();
1874-
assert_eq!(
1875-
invalid_head.head_slot() % slots_per_epoch,
1876-
slots_per_epoch - 1
1877-
);
18781877

1879-
// Advance clock to new epoch to realize the justification of soon-to-be-invalid head block.
1880-
rig.harness.set_current_slot(invalid_head.head_slot() + 1);
1878+
// Advance the chain forward two epochs past the current head block.
1879+
//
1880+
// This ensures that `voting_source.epoch + 2 >= current_epoch` is
1881+
// `false` in the `node_is_viable_for_head` function. In effect, this
1882+
// ensures that no other block but the current head block is viable as a
1883+
// head block.
1884+
let invalid_head_epoch = invalid_head.head_slot().epoch(slots_per_epoch);
1885+
let new_wall_clock_epoch = invalid_head_epoch + 2;
1886+
rig.harness
1887+
.set_current_slot(new_wall_clock_epoch.start_slot(slots_per_epoch));
18811888

18821889
// Invalidate the head block.
18831890
rig.invalidate_manually(invalid_head.head_block_root())
18841891
.await;
18851892

1893+
// Since our setup ensures that there is only a single, invalid block
1894+
// that's viable for head (according to FFG filtering), setting the
1895+
// head block as invalid should not result in another head being chosen.
1896+
// Rather, it should fail to run fork choice and leave the invalid block as
1897+
// the head.
18861898
assert!(rig
18871899
.canonical_head()
18881900
.head_execution_status()
18891901
.unwrap()
18901902
.is_invalid());
18911903

1892-
// Finding a new head should fail since the only possible head is not valid.
1904+
// Ensure that we're getting the correct error when trying to find a new
1905+
// head.
18931906
rig.assert_get_head_error_contains("InvalidBestNode");
18941907

18951908
Self {
18961909
rig,
1897-
fork_block: opt_fork_block.unwrap(),
1910+
fork_block,
18981911
invalid_head,
18991912
}
19001913
}

0 commit comments

Comments
 (0)