diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fc13f57..45731dc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ find_package(prometheus-cpp CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED) find_package(qdrvm-crates CONFIG REQUIRED) find_package(qtils CONFIG REQUIRED) -find_package(qdrvm-crates CONFIG REQUIRED) +find_package(RapidJSON CONFIG REQUIRED) find_package(RocksDB CONFIG REQUIRED) find_package(Snappy CONFIG REQUIRED) find_package(soralog CONFIG REQUIRED) diff --git a/src/serde/json.hpp b/src/serde/json.hpp new file mode 100644 index 00000000..753f3b52 --- /dev/null +++ b/src/serde/json.hpp @@ -0,0 +1,167 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#include +#include + +#include "serde/json_fwd.hpp" +#include "types/state.hpp" + +#define JSON_ASSERT(c) \ + if (not(c)) throw std::runtime_error{"json"} + +namespace lean::json { + struct Json { + const rapidjson::Value &v; + }; + + void decode(auto &v, std::string_view json_str) { + rapidjson::Document document; + document.Parse(json_str.data(), json_str.size()); + decode(v, Json{document}); + } + + inline std::string_view decodeStr(Json json) { + JSON_ASSERT(json.v.IsString()); + return {json.v.GetString(), json.v.GetStringLength()}; + } + + inline void decode(std::string &v, Json json) { + v = decodeStr(json); + } + + template + void decode(std::unordered_map &v, Json json) { + v.clear(); + JSON_ASSERT(json.v.IsObject()); + for (auto it = json.v.MemberBegin(); it != json.v.MemberEnd(); ++it) { + std::string key; + decode(key, Json{it->name}); + T value; + decode(value, Json{it->value}); + v.emplace(std::move(key), std::move(value)); + } + } + + template + void decode(std::optional &v, Json json) { + v.reset(); + if (not json.v.IsNull()) { + T value; + decode(value, json); + v.emplace(std::move(value)); + } + } + + template + void decode(std::vector &v, Json json) { + v.clear(); + JSON_ASSERT(json.v.IsArray()); + for (auto it = json.v.Begin(); it != json.v.End(); ++it) { + T value; + decode(value, Json{*it}); + v.emplace_back(std::move(value)); + } + } + + template + void decode(T &v, Json json) { + if constexpr (std::is_same_v) { + JSON_ASSERT(json.v.IsBool()); + v = json.v.GetBool(); + } else if constexpr (std::is_unsigned_v) { + JSON_ASSERT(json.v.IsUint()); + v = json.v.GetUint(); + } else { + JSON_ASSERT(json.v.IsInt()); + v = json.v.GetInt(); + } + } + + template + void decodeFields(const T &fields, const auto &field_names, Json json) { + JSON_ASSERT(json.v.IsObject()); + auto &field = std::get(fields); + auto &field_name = field_names.at(I); + auto it = json.v.FindMember(field_name.c_str()); + static const rapidjson::Value json_null; + decode(field, Json{it != json.v.MemberEnd() ? it->value : json_null}); + if constexpr (I + 1 < std::tuple_size_v) { + decodeFields(fields, field_names, json); + } + } + + template + requires requires(T &v) { + v.fieldNames(); + v.fields(); + } + void decode(T &v, Json json) { + auto fields = v.fields(); + auto &field_names = v.fieldNames(); + decodeFields<0>(fields, field_names, json); + } + + template + void decode(qtils::ByteArr &v, Json json) { + v = qtils::ByteArr::fromHexWithPrefix(decodeStr(json)).value(); + } + + template + void decode(ssz::list &v, Json json) { + static std::array field_names{"data"}; + decodeFields<0>(std::tie(v.data()), field_names, json); + } + + template + void decodeDiscriminator(std::variant &v, + const auto &type_field_values, + const std::string &type_field_value, + Json json) { + if (type_field_value == type_field_values.at(I)) { + decode(v.template emplace(), json); + return; + } + if constexpr (I + 1 < sizeof...(T)) { + decodeDiscriminator(v, type_field_values, type_field_value, json); + } else { + JSON_ASSERT(false); + } + } + + template + requires requires(T &v) { + v.typeFieldName(); + v.typeFieldValues(); + } + void decode(T &v, Json json) { + auto &type_field_name = v.typeFieldName(); + auto &type_field_values = v.typeFieldValues(); + static std::array field_names{type_field_name}; + std::string type_field_value; + decodeFields<0>(std::tie(type_field_value), field_names, json); + decodeDiscriminator<0>(v.v, type_field_values, type_field_value, json); + } + + template + requires requires(T &v) { enumValues(v); } + void decode(T &v, Json json) { + auto &enum_values = enumValues(v); + auto str = decodeStr(json); + for (auto &[enum_value, enum_str] : enum_values) { + if (str == enum_str) { + v = enum_value; + return; + } + } + JSON_ASSERT(false); + } +} // namespace lean::json diff --git a/src/serde/json_fwd.hpp b/src/serde/json_fwd.hpp new file mode 100644 index 00000000..14eff235 --- /dev/null +++ b/src/serde/json_fwd.hpp @@ -0,0 +1,96 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include +#include + +#define _JSON_CAMEL_NAMES_1(name) ::lean::json::toCamelCase(#name) +#define _JSON_CAMEL_NAMES_2(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_1(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_3(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_2(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_4(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_3(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_5(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_4(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_6(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_5(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_7(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_6(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_8(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_7(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_9(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_8(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_10(name, ...) \ + _JSON_CAMEL_NAMES_1(name), _JSON_CAMEL_NAMES_9(__VA_ARGS__) +#define _JSON_CAMEL_NAMES_OVERLOAD( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, macro, ...) \ + macro +#define _JSON_CAMEL_NAMES_OVERLOAD_CALL(macro, ...) macro(__VA_ARGS__) +#define _JSON_CAMEL_NAMES(...) \ + _JSON_CAMEL_NAMES_OVERLOAD_CALL( \ + _JSON_CAMEL_NAMES_OVERLOAD(__VA_ARGS__, \ + _JSON_CAMEL_NAMES_10, \ + _JSON_CAMEL_NAMES_9, \ + _JSON_CAMEL_NAMES_8, \ + _JSON_CAMEL_NAMES_7, \ + _JSON_CAMEL_NAMES_6, \ + _JSON_CAMEL_NAMES_5, \ + _JSON_CAMEL_NAMES_4, \ + _JSON_CAMEL_NAMES_3, \ + _JSON_CAMEL_NAMES_2, \ + _JSON_CAMEL_NAMES_1), \ + __VA_ARGS__) + +#define JSON_CAMEL(...) \ + static const auto &fieldNames() { \ + static std::array field_names{_JSON_CAMEL_NAMES(__VA_ARGS__)}; \ + return field_names; \ + } \ + auto fields() { \ + return std::tie(__VA_ARGS__); \ + } + +#define JSON_CAMEL_DISCRIMINATOR(type_field_name, ...) \ + static const std::string &typeFieldName() { \ + static auto name = ::lean::json::toCamelCase(type_field_name); \ + return name; \ + } \ + static const auto &typeFieldValues() { \ + static std::array values{__VA_ARGS__}; \ + return values; \ + } + +#define JSON_ENUM(type, ...) \ + inline const auto &enumValues(const type &) { \ + static std::vector> values{__VA_ARGS__}; \ + return values; \ + } + +namespace lean::json { + inline std::string toCamelCase(std::string_view name) { + std::string camel; + bool capitalize = false; + for (auto &c : name) { + if (c == '_') { + capitalize = true; + continue; + } + if (capitalize) { + capitalize = false; + camel.push_back(std::toupper(c)); + } else { + camel.push_back(c); + } + } + return camel; + } +} // namespace lean::json diff --git a/src/types/attestation.hpp b/src/types/attestation.hpp index 8207d152..42e3f9da 100644 --- a/src/types/attestation.hpp +++ b/src/types/attestation.hpp @@ -8,6 +8,7 @@ #include +#include "serde/json_fwd.hpp" #include "types/attestation_data.hpp" #include "types/validator_index.hpp" @@ -18,5 +19,7 @@ namespace lean { SSZ_CONT(validator_id, data); bool operator==(const Attestation &) const = default; + + JSON_CAMEL(validator_id, data); }; } // namespace lean diff --git a/src/types/attestation_data.hpp b/src/types/attestation_data.hpp index 24d77843..c135508c 100644 --- a/src/types/attestation_data.hpp +++ b/src/types/attestation_data.hpp @@ -8,6 +8,7 @@ #include +#include "serde/json_fwd.hpp" #include "types/checkpoint.hpp" #include "types/slot.hpp" @@ -20,5 +21,7 @@ namespace lean { SSZ_CONT(slot, head, target, source); bool operator==(const AttestationData &) const = default; + + JSON_CAMEL(slot, head, target, source); }; } // namespace lean diff --git a/src/types/block.hpp b/src/types/block.hpp index 7a8a8af7..324da24d 100644 --- a/src/types/block.hpp +++ b/src/types/block.hpp @@ -6,6 +6,7 @@ #pragma once +#include "serde/json_fwd.hpp" #include "types/block_body.hpp" #include "types/block_header.hpp" @@ -20,6 +21,8 @@ namespace lean { SSZ_CONT(slot, proposer_index, parent_root, state_root, body); bool operator==(const Block &) const = default; + JSON_CAMEL(slot, proposer_index, parent_root, state_root, body); + BlockHeader getHeader() const { BlockHeader header; header.slot = slot; diff --git a/src/types/block_body.hpp b/src/types/block_body.hpp index 3dabf13d..14902cfa 100644 --- a/src/types/block_body.hpp +++ b/src/types/block_body.hpp @@ -8,6 +8,7 @@ #include +#include "serde/json_fwd.hpp" #include "types/attestations.hpp" namespace lean { @@ -17,6 +18,8 @@ namespace lean { SSZ_CONT(attestations); bool operator==(const BlockBody &) const = default; + + JSON_CAMEL(attestations); }; } // namespace lean diff --git a/src/types/block_header.hpp b/src/types/block_header.hpp index dc60c329..4dd968cc 100644 --- a/src/types/block_header.hpp +++ b/src/types/block_header.hpp @@ -9,6 +9,7 @@ #include #include +#include "serde/json_fwd.hpp" #include "serde/serialization.hpp" #include "types/block_index.hpp" @@ -44,6 +45,8 @@ namespace lean { SSZ_CONT(slot, proposer_index, parent_root, state_root, body_root); + JSON_CAMEL(slot, proposer_index, parent_root, state_root, body_root); + const HeaderHash &hash() const { BOOST_ASSERT_MSG(hash_opt.has_value(), "Hash must be calculated and saved before that"); diff --git a/src/types/block_with_attestation.hpp b/src/types/block_with_attestation.hpp index b2be35e3..28760468 100644 --- a/src/types/block_with_attestation.hpp +++ b/src/types/block_with_attestation.hpp @@ -8,6 +8,7 @@ #include +#include "serde/json_fwd.hpp" #include "types/attestation.hpp" #include "types/block.hpp" @@ -18,5 +19,7 @@ namespace lean { SSZ_CONT(block, proposer_attestation); bool operator==(const BlockWithAttestation &) const = default; + + JSON_CAMEL(block, proposer_attestation); }; } // namespace lean diff --git a/src/types/checkpoint.hpp b/src/types/checkpoint.hpp index a751c15d..e1862568 100644 --- a/src/types/checkpoint.hpp +++ b/src/types/checkpoint.hpp @@ -9,6 +9,7 @@ #include #include "log/formatters/block_index_ref.hpp" +#include "serde/json_fwd.hpp" namespace lean { @@ -22,6 +23,8 @@ namespace lean { SSZ_CONT(root, slot); bool operator==(const Checkpoint &) const = default; + + JSON_CAMEL(root, slot); }; } // namespace lean diff --git a/src/types/config.hpp b/src/types/config.hpp index 321daf59..a44fad40 100644 --- a/src/types/config.hpp +++ b/src/types/config.hpp @@ -8,6 +8,8 @@ #include +#include "serde/json_fwd.hpp" + namespace lean { struct Config : ssz::ssz_container { uint64_t genesis_time; @@ -15,5 +17,7 @@ namespace lean { SSZ_CONT(genesis_time); bool operator==(const Config &) const = default; + + JSON_CAMEL(genesis_time); }; } // namespace lean diff --git a/src/types/fork_choice_test_json.hpp b/src/types/fork_choice_test_json.hpp new file mode 100644 index 00000000..139df32e --- /dev/null +++ b/src/types/fork_choice_test_json.hpp @@ -0,0 +1,101 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "serde/json_fwd.hpp" +#include "types/block.hpp" +#include "types/block_with_attestation.hpp" +#include "types/signed_attestation.hpp" +#include "types/state.hpp" + +namespace lean { + enum class AttestationCheckLocation { + NEW, + KNOWN, + }; + JSON_ENUM(AttestationCheckLocation, + {AttestationCheckLocation::NEW, "new"}, + {AttestationCheckLocation::KNOWN, "known"}); + + struct AttestationCheck { + ValidatorIndex validator; + Slot attestation_slot; + std::optional head_slot; + std::optional source_slot; + std::optional target_slot; + AttestationCheckLocation location; + + JSON_CAMEL(validator, + attestation_slot, + head_slot, + source_slot, + target_slot, + location); + }; + + struct StoreChecks { + std::optional time; + std::optional head_slot; + std::optional head_root; + std::optional latest_justified_slot; + std::optional latest_justified_root; + std::optional latest_finalized_slot; + std::optional latest_finalized_root; + std::optional safe_target; + std::optional attestation_target_slot; + std::optional> attestation_checks; + + JSON_CAMEL(time, + head_slot, + head_root, + latest_justified_slot, + latest_justified_root, + latest_finalized_slot, + latest_finalized_root, + safe_target, + attestation_target_slot, + attestation_checks); + }; + + struct BaseForkChoiceStep { + bool valid; + std::optional checks; + }; + + struct TickStep : BaseForkChoiceStep { + TimestampSeconds time; + + JSON_CAMEL(valid, checks, time); + }; + + struct BlockStep : BaseForkChoiceStep { + BlockWithAttestation block; + + JSON_CAMEL(valid, checks, block); + }; + + struct AttestationStep : BaseForkChoiceStep { + SignedAttestation attestation; + + JSON_CAMEL(valid, checks, attestation); + }; + + struct ForkChoiceStep { + std::variant v; + + JSON_CAMEL_DISCRIMINATOR("step_type", "tick", "block", "attestation"); + }; + + struct ForkChoiceTestJson { + State anchor_state; + Block anchor_block; + std::vector steps; + Slot max_slot; + + JSON_CAMEL(anchor_state, anchor_block, steps, max_slot); + }; +} // namespace lean diff --git a/src/types/signed_attestation.hpp b/src/types/signed_attestation.hpp index fdd8fea3..8f408e1c 100644 --- a/src/types/signed_attestation.hpp +++ b/src/types/signed_attestation.hpp @@ -8,6 +8,7 @@ #include +#include "serde/json_fwd.hpp" #include "types/attestation.hpp" #include "types/signature.hpp" @@ -17,5 +18,7 @@ namespace lean { Signature signature; SSZ_CONT(message, signature); + + JSON_CAMEL(message, signature); }; } // namespace lean diff --git a/src/types/state.hpp b/src/types/state.hpp index 9342b4f2..d0916037 100644 --- a/src/types/state.hpp +++ b/src/types/state.hpp @@ -6,6 +6,7 @@ #pragma once +#include "serde/json_fwd.hpp" #include "types/block_header.hpp" #include "types/checkpoint.hpp" #include "types/config.hpp" @@ -45,6 +46,17 @@ namespace lean { justifications_validators); bool operator==(const State &) const = default; + JSON_CAMEL(config, + slot, + latest_block_header, + latest_justified, + latest_finalized, + historical_block_hashes, + justified_slots, + validators, + justifications_roots, + justifications_validators); + ValidatorIndex validatorCount() const { return validators.size(); } diff --git a/src/types/state_transition_test_json.hpp b/src/types/state_transition_test_json.hpp new file mode 100644 index 00000000..7cd76a4d --- /dev/null +++ b/src/types/state_transition_test_json.hpp @@ -0,0 +1,44 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "serde/json_fwd.hpp" +#include "types/block.hpp" +#include "types/state.hpp" + +namespace lean { + struct StateExpectation { + Slot slot; + std::optional latest_justified_slot; + std::optional latest_justified_root; + std::optional latest_finalized_slot; + std::optional latest_finalized_root; + std::optional validator_count; + std::optional latest_block_header_slot; + std::optional latest_block_header_state_root; + std::optional historical_block_hashes_count; + + JSON_CAMEL(slot, + latest_justified_slot, + latest_justified_root, + latest_finalized_slot, + latest_finalized_root, + validator_count, + latest_block_header_slot, + latest_block_header_state_root, + historical_block_hashes_count); + }; + + struct StateTransitionTestJson { + State pre; + std::vector blocks; + std::optional post; + std::optional expect_exception; + + JSON_CAMEL(pre, blocks, post, expect_exception); + }; +} // namespace lean diff --git a/src/types/validator.hpp b/src/types/validator.hpp index 13451601..3efb7ec1 100644 --- a/src/types/validator.hpp +++ b/src/types/validator.hpp @@ -10,6 +10,7 @@ #include #include "crypto/xmss/types.hpp" +#include "serde/json_fwd.hpp" #include "types/validator_index.hpp" namespace lean { @@ -19,5 +20,7 @@ namespace lean { SSZ_CONT(pubkey, index); bool operator==(const Validator &) const = default; + + JSON_CAMEL(pubkey, index); }; } // namespace lean diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 76c8a710..522febd5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,5 +44,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/tests ) +add_subdirectory(test_vectors) add_subdirectory(testutil) add_subdirectory(unit) diff --git a/tests/test_vectors/CMakeLists.txt b/tests/test_vectors/CMakeLists.txt new file mode 100644 index 00000000..3c756fa5 --- /dev/null +++ b/tests/test_vectors/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright Quadrivium LLC +# All Rights Reserved +# SPDX-License-Identifier: Apache-2.0 +# + +addtest(test_vectors_test + test_vectors_test.cpp +) +target_link_libraries(test_vectors_test + blockchain +) +target_compile_definitions(test_vectors_test PRIVATE + PROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}" +) diff --git a/tests/test_vectors/fixtures.md b/tests/test_vectors/fixtures.md new file mode 100644 index 00000000..d7c521c3 --- /dev/null +++ b/tests/test_vectors/fixtures.md @@ -0,0 +1,5 @@ + +https://github.com/leanEthereum/leanSpec +```bash +uv run fill --clean --fork=devnet +``` diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_accumulation_full_validator_set.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_accumulation_full_validator_set.json new file mode 100644 index 00000000..ea1a8463 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_accumulation_full_validator_set.json @@ -0,0 +1,293 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestation_accumulation_full_validator_set[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "targetSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "targetSlot": 2, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "targetSlot": 3, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "location": "known" + }, + { + "validator": 0, + "attestationSlot": 4, + "targetSlot": 4, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + } + } + } + ], + "maxSlot": 4, + "_info": { + "hash": "0xfce480d1f6c30d3f57ad0b636d5d2b3fbcfe1a55874d86fd30fcaa307e7a0708", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestation_accumulation_full_validator_set[fork_Devnet]", + "description": "All validators contribute attestations across both dictionaries.\n\nScenario\n--------\nProcess blocks at slots 1, 2, 3, 4 (complete validator rotation).\n\nExpected:\n - After slot 1: new attestations = 1, known attestations = 0\n - After slot 2: new attestations = 1, known attestations = 1\n - After slot 3: new attestations = 1, known attestations = 2\n - After slot 4: new attestations = 1, known attestations = 3 (total: 4 validators)\n\nWhy This Matters\n----------------\nWith 4 validators and consecutive blocks, each validator proposes once.\n\nAttestations accumulate across both dictionaries:\n- new: current slot's proposer\n- known: all previous proposers\n\nThe total (new + known) equals the number of unique validators who proposed.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_superseding_same_validator.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_superseding_same_validator.json new file mode 100644 index 00000000..1e4dd5cd --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestation_superseding_same_validator.json @@ -0,0 +1,174 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestation_superseding_same_validator[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "headSlot": 1, + "sourceSlot": 0, + "targetSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 5, + "headSlot": 5, + "targetSlot": 5, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0x63d6ed6ce4545f599a6cd94e96ce162ea7a7ef59863228c2d14febc8bd6e2ce1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0xf9b01a91b0b7c607af6a3bec2114ec275c5a65feb29749cca575a5de20068f30", + "slot": 5 + }, + "target": { + "root": "0xf9b01a91b0b7c607af6a3bec2114ec275c5a65feb29749cca575a5de20068f30", + "slot": 5 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0x175208373ca70a83057955466dbac8c6d90cfcea509bef78b9336a6fdf08a961", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestation_superseding_same_validator[fork_Devnet]", + "description": "Newer attestation from same validator supersedes older attestation.\n\nScenario\n--------\nProcess blocks at slots 1 and 5 (same proposer: validator 1).\n\nExpected:\n - After slot 1: validator 1 attests to slot 1\n - After slot 5: validator 1 attests to slot 5 (supersedes slot 1)\n\nWhy This Matters\n----------------\nWith round-robin proposer selection, slots 1 and 5 use the same validator.\n\nWhen that validator proposes again, their newer attestation supersedes the older one.\nBoth dictionaries are keyed by validator index, so only the most recent\nattestation per validator is retained.\n\nKey insight: Attestations accumulate across validators but supersede within validators.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestations_move_to_known_between_blocks.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestations_move_to_known_between_blocks.json new file mode 100644 index 00000000..5b583991 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_attestations_move_to_known_between_blocks.json @@ -0,0 +1,183 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestations_move_to_known_between_blocks[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "headSlot": 1, + "sourceSlot": 0, + "targetSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "headSlot": 1, + "sourceSlot": 0, + "targetSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "headSlot": 2, + "sourceSlot": 1, + "targetSlot": 2, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + } + ], + "maxSlot": 2, + "_info": { + "hash": "0x8e3615d86cfbe4e222a16464083b12977fd267104817fde3c04da52330f2e755", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_attestations_move_to_known_between_blocks[fork_Devnet]", + "description": "Attestations move from latest_new to latest_known between blocks.\n\nScenario\n--------\nProcess blocks at slots 1 and 2 (different proposers: validators 1 and 2).\n\nExpected:\n - After slot 1: new attestations = 1, known attestations = 0\n - After slot 2: new attestations = 1, known attestations = 1\n - Validator 1's attestation moved to known with correct checkpoints\n - Validator 2's attestation in new with correct checkpoints\n\nWhy This Matters\n----------------\nThe interval tick system drives attestation migration between slots.\n\nBefore processing the next block, interval ticks move all attestations from\nnew \u2192 known and clear the new dictionary. Then the next block's proposer\nattestation enters the now-empty new dictionary.\n\nThis creates the attestation pipeline:\n- Enter via new (arrivals)\n- Graduate to known (accepted for fork choice)", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_extended_chain_attestation_superseding_pattern.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_extended_chain_attestation_superseding_pattern.json new file mode 100644 index 00000000..5bd32fc5 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_extended_chain_attestation_superseding_pattern.json @@ -0,0 +1,529 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_extended_chain_attestation_superseding_pattern[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "location": "known" + }, + { + "validator": 0, + "attestationSlot": 4, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 5, + "location": "new" + }, + { + "validator": 0, + "attestationSlot": 4, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 2, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "location": "known" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "attestationChecks": [ + { + "validator": 2, + "attestationSlot": 6, + "location": "new" + }, + { + "validator": 0, + "attestationSlot": 4, + "location": "known" + }, + { + "validator": 1, + "attestationSlot": 5, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "location": "known" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "stateRoot": "0x6faedde65fafaab574997ecdff9099bfed9f3c0791fd974d960eb1493f965568", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 6, + "head": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + }, + "target": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + }, + "source": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "attestationChecks": [ + { + "validator": 3, + "attestationSlot": 7, + "location": "new" + }, + { + "validator": 0, + "attestationSlot": 4, + "location": "known" + }, + { + "validator": 1, + "attestationSlot": 5, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 6, + "location": "known" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "stateRoot": "0xfc5dce49282828fcde3140191ea2d0e985f837523ea0126c04dc341cdc7592a1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + }, + "target": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + }, + "source": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 8, + "attestationChecks": [ + { + "validator": 0, + "attestationSlot": 8, + "location": "new" + }, + { + "validator": 1, + "attestationSlot": 5, + "location": "known" + }, + { + "validator": 2, + "attestationSlot": 6, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 7, + "location": "known" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "stateRoot": "0x63880bd0e6da9f5a68ae84867243d8b6f097b9905306bd6a57713c65e9f1e078", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 8, + "head": { + "root": "0xad89e020ed105a85697fa04011f480d68da1745b792c3a5fd6f516aaf24530cd", + "slot": 8 + }, + "target": { + "root": "0xad89e020ed105a85697fa04011f480d68da1745b792c3a5fd6f516aaf24530cd", + "slot": 8 + }, + "source": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + } + } + } + } + } + ], + "maxSlot": 8, + "_info": { + "hash": "0xc9c43ab9050669f8868bdf872155f928eb97b2de77ce8ad78d2ccdee1e35188d", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_extended_chain_attestation_superseding_pattern[fork_Devnet]", + "description": "Attestation superseding pattern over two complete validator rotations.\n\nScenario\n--------\nProcess blocks at slots 1-8 (two complete validator rotations).\n\nPhase 1 (slots 1-4): Accumulation\n Validators each propose once, attestations accumulate to 4 total.\n\nPhase 2 (slots 5-8): Steady State\n Validators propose again, newer attestations supersede older ones.\n Total stays at 4, composition changes.\n\nExpected:\n - After slot 4: All 4 validators have attestations (v0 in new, v1-v3 in known)\n - After slot 5: Validator 1 supersedes their slot 1 attestation\n - After slot 8: All validators have their latest attestations from slots 5-8\n\nWhy This Matters\n----------------\nThe system reaches steady state: one attestation per validator.\n\nAs each validator proposes again, their new attestation supersedes their old one.\nThe count remains constant (4), but the composition updates.\n\nThis confirms superseding maintains correct state over time with no attestation\nleaks or unbounded growth.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_proposer_attestation_appears_in_latest_new.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_proposer_attestation_appears_in_latest_new.json new file mode 100644 index 00000000..0e85eecc --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_proposer_attestation_appears_in_latest_new.json @@ -0,0 +1,127 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_proposer_attestation_appears_in_latest_new[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "headSlot": 1, + "sourceSlot": 0, + "targetSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + } + ], + "maxSlot": 1, + "_info": { + "hash": "0x17ad773c17f0474dffe9f200261dfb6a11b15008f2a22be98ea3180fd3eaeef5", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_proposer_attestation_appears_in_latest_new[fork_Devnet]", + "description": "Proposer attestation appears in latest_new after block processing.\n\nScenario\n--------\nProcess one block at slot 1 (proposer: validator 1).\n\nExpected:\n - validator 1's attestation has correct slot and checkpoint slots\n\nWhy This Matters\n----------------\nNew proposer attestations enter the pipeline through `latest_new_attestations`,\nnot directly into `latest_known_attestations`.\n\nThis baseline test verifies the entry point of the attestation pipeline.\nAll new attestations must enter through the \"new\" stage before graduating to \"known\".", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_slot_gaps_with_attestation_superseding.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_slot_gaps_with_attestation_superseding.json new file mode 100644 index 00000000..83b3badd --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_processing/test_slot_gaps_with_attestation_superseding.json @@ -0,0 +1,278 @@ +{ + "tests/consensus/devnet/fc/test_attestation_processing.py::test_slot_gaps_with_attestation_superseding[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "targetSlot": 1, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 1, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 3, + "targetSlot": 3, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0x52299092cb8fa2daff77887f36a0a0e0127cdb5745fcc1f1f0fa8286b2ef12d1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "target": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationChecks": [ + { + "validator": 3, + "attestationSlot": 3, + "location": "known" + }, + { + "validator": 1, + "attestationSlot": 5, + "targetSlot": 5, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "stateRoot": "0xf8484eef6235dc31d56a0515ad390e016d43b058609649c84661e08aa52026b0", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "target": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "source": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "attestationChecks": [ + { + "validator": 1, + "attestationSlot": 5, + "location": "known" + }, + { + "validator": 3, + "attestationSlot": 7, + "targetSlot": 7, + "location": "new" + } + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "stateRoot": "0x548f45bad5a36007455d169c4d03cea239f522460bbe97dbd98562c1f857de5f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "slot": 7 + }, + "target": { + "root": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "slot": 7 + }, + "source": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + } + } + } + } + } + ], + "maxSlot": 7, + "_info": { + "hash": "0x9cdbb46700540924db77f5f67aed33ff4a039cff116d67ac70b62190b63a64cf", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_processing.py::test_slot_gaps_with_attestation_superseding[fork_Devnet]", + "description": "Attestation superseding works correctly with missed slots.\n\nScenario\n--------\nProcess blocks at slots 1, 3, 5, 7 (skipping even slots).\nProposers: validators 1, 3, 1, 3 (same validators repeat).\n\nExpected:\n - After slot 1: Validator 1 attests\n - After slot 3: Validator 3 attests, validator 1 moved to known\n - After slot 5: Validator 1 attests again (supersedes old), validator 3 in known\n - After slot 7: Validator 3 attests again (supersedes old), validator 1 in known\n\nWhy This Matters\n----------------\nMissed slots are normal when proposers fail to produce blocks.\n\nWith non-contiguous slots, round-robin means validators propose multiple times.\nWhen they do, their newer attestations supersede their older ones.\n\nTotal count stays at 2 (unique validators) throughout slots 5-7.\n\nThis confirms attestation processing and superseding work correctly with slot gaps\nacross both dictionaries.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_advances_with_attestations.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_advances_with_attestations.json new file mode 100644 index 00000000..53b59ed3 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_advances_with_attestations.json @@ -0,0 +1,274 @@ +{ + "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_advances_with_attestations[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "attestationTargetSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationTargetSlot": 2 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + } + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0xc48a0961253f9926ca8ecb38f45ea898afd7a0ebadddc640d8991107a780e7ce", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_advances_with_attestations[fork_Devnet]", + "description": "Attestation target advances as attestation weight accumulates.\n\nScenario\n--------\nBuild a longer chain (slots 1-5) where attestations cause target advancement.\n\nExpected:\n - Initial blocks: target stays at genesis (slot 0)\n - Later blocks: target advances as attestations accumulate\n - Target remains behind head for safety\n\nWhy This Matters\n----------------\nAs validators attest to blocks, the safe target advances, which in turn\nallows the attestation target to move forward.\n\nThis demonstrates the dynamic nature of target selection: conservative initially,\nbut advancing as consensus strengthens through attestation accumulation.\n\nThe target advances only when sufficient attestation weight supports it.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_at_genesis_initially.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_at_genesis_initially.json new file mode 100644 index 00000000..b01b56ca --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_at_genesis_initially.json @@ -0,0 +1,157 @@ +{ + "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_at_genesis_initially[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + } + ], + "maxSlot": 2, + "_info": { + "hash": "0xb9515e817c75d139945728fbbfc352b543063aca2e1df1e5090c326b19ca35e1", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_at_genesis_initially[fork_Devnet]", + "description": "Attestation target starts at genesis before safe target updates.\n\nScenario\n--------\nProcess two blocks at slots 1 and 2.\n\nExpected:\n - After slot 1: target = slot 0 (genesis/finalized)\n - After slot 2: target = slot 0 (genesis/finalized)\n - Target root automatically validated against block at slot 0\n\nWhy This Matters\n----------------\nInitially, the safe target is at genesis (slot 0), so the attestation\ntarget walks back from head to genesis.\n\nThis conservative behavior ensures validators don't attest too far ahead\nbefore there's sufficient attestation weight to advance the safe target.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_justifiable_constraint.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_justifiable_constraint.json new file mode 100644 index 00000000..4285322c --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_justifiable_constraint.json @@ -0,0 +1,1249 @@ +{ + "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_justifiable_constraint[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x10e670451731da463e9f39177f44500759cfb42bea781d0fb154052e3c27156820b3394d69b6f225da39ba0d251d001f9aa2f61a", + "index": 0 + }, + { + "pubkey": "0x9cf650628da8d4614d6d897e067e7411c02afd2cc29403799f660937d395f37641321647c905da6eee96462a0cbb442ba5a7f82f", + "index": 1 + }, + { + "pubkey": "0x73dc1a61fa471b7601f426468532246428f7ba10d71682615991820f2abb0b480ee1424a26c711225a1a1f17619bf0030f6aaa56", + "index": 2 + }, + { + "pubkey": "0x91bcd1462388153a77b9382124b5c42989a32e3e370e52408a04fe6b35246562fa8cc1433a49265c248a1d307ccd126304e9d520", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xdbc753c51cc8d826edac5cff41126a6d7ad1c4cddd60b497dbe9ee6bb0393bfe", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xf63aa52fb8966777c37589ef513500c055291ce331d5bba46342ee21eeaf211a", + "stateRoot": "0xca648f388b13e8fc49d77bd92b890772eef4a02823b8570cb5836621bf77d5ab", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + }, + "target": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + }, + "source": { + "root": "0xf63aa52fb8966777c37589ef513500c055291ce331d5bba46342ee21eeaf211a", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "stateRoot": "0xbd99145b8074f1fb919c99d2a0d072898eec174b19c9998b4d4c251a19b28596", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xe0c37d6403dca689298287e6ccb63b0d9ef5583ffdf9641b8858701713df3a02", + "slot": 2 + }, + "target": { + "root": "0xe0c37d6403dca689298287e6ccb63b0d9ef5583ffdf9641b8858701713df3a02", + "slot": 2 + }, + "source": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xe0c37d6403dca689298287e6ccb63b0d9ef5583ffdf9641b8858701713df3a02", + "stateRoot": "0x77e28527063fb527ca6b54be84bf51a271e6444a1824f81b2936e39341c967d7", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0xb4b88d975d9bbf7b8962ef921309be1903e9d4e33677b008375deedb05b86853", + "slot": 3 + }, + "target": { + "root": "0xb4b88d975d9bbf7b8962ef921309be1903e9d4e33677b008375deedb05b86853", + "slot": 3 + }, + "source": { + "root": "0xe0c37d6403dca689298287e6ccb63b0d9ef5583ffdf9641b8858701713df3a02", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "attestationTargetSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0xb4b88d975d9bbf7b8962ef921309be1903e9d4e33677b008375deedb05b86853", + "stateRoot": "0xa661c2e44c1fb9c9938267224bb4c68be4aad2c4a38908475f329e324df4148b", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0xdd5f96ebb77a3d0f7bd234f6043d8dbea09c593e11cbacb15ed9bb042752185e", + "slot": 4 + }, + "target": { + "root": "0xdd5f96ebb77a3d0f7bd234f6043d8dbea09c593e11cbacb15ed9bb042752185e", + "slot": 4 + }, + "source": { + "root": "0xb4b88d975d9bbf7b8962ef921309be1903e9d4e33677b008375deedb05b86853", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationTargetSlot": 2 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0xdd5f96ebb77a3d0f7bd234f6043d8dbea09c593e11cbacb15ed9bb042752185e", + "stateRoot": "0xc446bb77d3710753507713cf157ec0ac33f00c641e3d854912f938e0f5ecd16b", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0xab610b1c084b9a7cb9bf1707b5b0eb03c91fc2e68922e5273a87b103a85b1658", + "slot": 5 + }, + "target": { + "root": "0xab610b1c084b9a7cb9bf1707b5b0eb03c91fc2e68922e5273a87b103a85b1658", + "slot": 5 + }, + "source": { + "root": "0xdd5f96ebb77a3d0f7bd234f6043d8dbea09c593e11cbacb15ed9bb042752185e", + "slot": 4 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "attestationTargetSlot": 3 + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0xab610b1c084b9a7cb9bf1707b5b0eb03c91fc2e68922e5273a87b103a85b1658", + "stateRoot": "0x84074d4cd165a05a5c1703448996d80271f4bd966d8017dae977b09811972063", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 6, + "head": { + "root": "0xd945235963081a454cd28a354370f09021cd15dab316d569fc93a185d95a6ca2", + "slot": 6 + }, + "target": { + "root": "0xd945235963081a454cd28a354370f09021cd15dab316d569fc93a185d95a6ca2", + "slot": 6 + }, + "source": { + "root": "0xab610b1c084b9a7cb9bf1707b5b0eb03c91fc2e68922e5273a87b103a85b1658", + "slot": 5 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "attestationTargetSlot": 4 + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0xd945235963081a454cd28a354370f09021cd15dab316d569fc93a185d95a6ca2", + "stateRoot": "0xf4133b7d6f1b337e478c6d204b912f542789611819759ca1b729e780f886a65e", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0x7c36d263163145b72881544ae311c51398dfbaa26cea3ee4b861273c8b53004b", + "slot": 7 + }, + "target": { + "root": "0x7c36d263163145b72881544ae311c51398dfbaa26cea3ee4b861273c8b53004b", + "slot": 7 + }, + "source": { + "root": "0xd945235963081a454cd28a354370f09021cd15dab316d569fc93a185d95a6ca2", + "slot": 6 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 8, + "attestationTargetSlot": 5 + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0x7c36d263163145b72881544ae311c51398dfbaa26cea3ee4b861273c8b53004b", + "stateRoot": "0x595d3c178a37967e683c5967462f71dde61ee24495681c1f0b9fa6c2885caa21", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 8, + "head": { + "root": "0xcd41eb22381d77eab15c4dffbbee7c6feddf2a4c7eff4eacd5a0cf4b2c96fabd", + "slot": 8 + }, + "target": { + "root": "0xcd41eb22381d77eab15c4dffbbee7c6feddf2a4c7eff4eacd5a0cf4b2c96fabd", + "slot": 8 + }, + "source": { + "root": "0x7c36d263163145b72881544ae311c51398dfbaa26cea3ee4b861273c8b53004b", + "slot": 7 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 9, + "attestationTargetSlot": 6 + }, + "stepType": "block", + "block": { + "block": { + "slot": 9, + "proposerIndex": 1, + "parentRoot": "0xcd41eb22381d77eab15c4dffbbee7c6feddf2a4c7eff4eacd5a0cf4b2c96fabd", + "stateRoot": "0x8b69fb9d4e5ae9962ff45d7753e1699ab1c99101264171dc9c01c4e7160d2814", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 9, + "head": { + "root": "0x57a3db6d77e9ef7910019e28792a49afe15da7886fb55efd9d9907ee973f1b16", + "slot": 9 + }, + "target": { + "root": "0x57a3db6d77e9ef7910019e28792a49afe15da7886fb55efd9d9907ee973f1b16", + "slot": 9 + }, + "source": { + "root": "0xcd41eb22381d77eab15c4dffbbee7c6feddf2a4c7eff4eacd5a0cf4b2c96fabd", + "slot": 8 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 10, + "attestationTargetSlot": 6 + }, + "stepType": "block", + "block": { + "block": { + "slot": 10, + "proposerIndex": 2, + "parentRoot": "0x57a3db6d77e9ef7910019e28792a49afe15da7886fb55efd9d9907ee973f1b16", + "stateRoot": "0xcd48d606284b7d04665212586d7c6102629e918e94c8de3a6fb3a233adaa97c5", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 10, + "head": { + "root": "0x341e4a12f6de10cd30e5da3601cdf29107ea145db999ee9dcb115b26c97d6706", + "slot": 10 + }, + "target": { + "root": "0x341e4a12f6de10cd30e5da3601cdf29107ea145db999ee9dcb115b26c97d6706", + "slot": 10 + }, + "source": { + "root": "0x57a3db6d77e9ef7910019e28792a49afe15da7886fb55efd9d9907ee973f1b16", + "slot": 9 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 11, + "attestationTargetSlot": 6 + }, + "stepType": "block", + "block": { + "block": { + "slot": 11, + "proposerIndex": 3, + "parentRoot": "0x341e4a12f6de10cd30e5da3601cdf29107ea145db999ee9dcb115b26c97d6706", + "stateRoot": "0xdeefec182dc4619e4155b90cbd761699a34de6ce3f60d15113bad4e9ed4a7745", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 11, + "head": { + "root": "0x7cba817cdb7bbe04fe628da817784f3712bf16f6ba8681ddb08e676914f6393a", + "slot": 11 + }, + "target": { + "root": "0x7cba817cdb7bbe04fe628da817784f3712bf16f6ba8681ddb08e676914f6393a", + "slot": 11 + }, + "source": { + "root": "0x341e4a12f6de10cd30e5da3601cdf29107ea145db999ee9dcb115b26c97d6706", + "slot": 10 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 12, + "attestationTargetSlot": 9 + }, + "stepType": "block", + "block": { + "block": { + "slot": 12, + "proposerIndex": 0, + "parentRoot": "0x7cba817cdb7bbe04fe628da817784f3712bf16f6ba8681ddb08e676914f6393a", + "stateRoot": "0x10af0f8f003eb054ea1e63742bb0d3003cd91e71ab0e40309accdc0ddf23fd8c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 12, + "head": { + "root": "0x7b032d37dd6388f40edf3738b59081110092be37ae043b60c9eca8754a3786ce", + "slot": 12 + }, + "target": { + "root": "0x7b032d37dd6388f40edf3738b59081110092be37ae043b60c9eca8754a3786ce", + "slot": 12 + }, + "source": { + "root": "0x7cba817cdb7bbe04fe628da817784f3712bf16f6ba8681ddb08e676914f6393a", + "slot": 11 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 13, + "attestationTargetSlot": 9 + }, + "stepType": "block", + "block": { + "block": { + "slot": 13, + "proposerIndex": 1, + "parentRoot": "0x7b032d37dd6388f40edf3738b59081110092be37ae043b60c9eca8754a3786ce", + "stateRoot": "0x4b87272255febf020b68d7bb9e080eb792009c3d08cbe111c9cae53149d2bb59", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 13, + "head": { + "root": "0x9d6e44f3232c947ccea7d5fd82c1dda49ef7a732f6f65bd320ce3653c56ebff8", + "slot": 13 + }, + "target": { + "root": "0x9d6e44f3232c947ccea7d5fd82c1dda49ef7a732f6f65bd320ce3653c56ebff8", + "slot": 13 + }, + "source": { + "root": "0x7b032d37dd6388f40edf3738b59081110092be37ae043b60c9eca8754a3786ce", + "slot": 12 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 14, + "attestationTargetSlot": 9 + }, + "stepType": "block", + "block": { + "block": { + "slot": 14, + "proposerIndex": 2, + "parentRoot": "0x9d6e44f3232c947ccea7d5fd82c1dda49ef7a732f6f65bd320ce3653c56ebff8", + "stateRoot": "0x4c6e9790de2d45146e46660e725e0c1352ce98538875fb31edf7497024f097bb", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 14, + "head": { + "root": "0x6ba9dc99d48b49275aa2fa9dfc5e5ca1a4861e50e90e4b467d058f88180d9f11", + "slot": 14 + }, + "target": { + "root": "0x6ba9dc99d48b49275aa2fa9dfc5e5ca1a4861e50e90e4b467d058f88180d9f11", + "slot": 14 + }, + "source": { + "root": "0x9d6e44f3232c947ccea7d5fd82c1dda49ef7a732f6f65bd320ce3653c56ebff8", + "slot": 13 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 15, + "attestationTargetSlot": 12 + }, + "stepType": "block", + "block": { + "block": { + "slot": 15, + "proposerIndex": 3, + "parentRoot": "0x6ba9dc99d48b49275aa2fa9dfc5e5ca1a4861e50e90e4b467d058f88180d9f11", + "stateRoot": "0x599a27fef20d12286c16eb14cd0082f82fa888fd93420afb55dcdb249b424932", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 15, + "head": { + "root": "0xbc04a9f9e2922ad9b012babdd83171ff49ccc92ccaaff83035b83ad1f6f381cc", + "slot": 15 + }, + "target": { + "root": "0xbc04a9f9e2922ad9b012babdd83171ff49ccc92ccaaff83035b83ad1f6f381cc", + "slot": 15 + }, + "source": { + "root": "0x6ba9dc99d48b49275aa2fa9dfc5e5ca1a4861e50e90e4b467d058f88180d9f11", + "slot": 14 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 16, + "attestationTargetSlot": 12 + }, + "stepType": "block", + "block": { + "block": { + "slot": 16, + "proposerIndex": 0, + "parentRoot": "0xbc04a9f9e2922ad9b012babdd83171ff49ccc92ccaaff83035b83ad1f6f381cc", + "stateRoot": "0xf9824cace5b8bab6401fe163d2edbdc024b6e75b842bd1acb78159aca3be9148", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 16, + "head": { + "root": "0x9bf715c4c4a099d286081d4973cd180967e923ebf61d85f2d64f065ee1460239", + "slot": 16 + }, + "target": { + "root": "0x9bf715c4c4a099d286081d4973cd180967e923ebf61d85f2d64f065ee1460239", + "slot": 16 + }, + "source": { + "root": "0xbc04a9f9e2922ad9b012babdd83171ff49ccc92ccaaff83035b83ad1f6f381cc", + "slot": 15 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 17, + "attestationTargetSlot": 12 + }, + "stepType": "block", + "block": { + "block": { + "slot": 17, + "proposerIndex": 1, + "parentRoot": "0x9bf715c4c4a099d286081d4973cd180967e923ebf61d85f2d64f065ee1460239", + "stateRoot": "0x6c936e5d8f1e56f8de80b0ec552fb20c1f7584a2f83592c892ffe9df9b3daf0f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 17, + "head": { + "root": "0x5ab5e0e2dd52b9076fce846dc0df7dedbbb809f5ad86594836cdf300aa52e89c", + "slot": 17 + }, + "target": { + "root": "0x5ab5e0e2dd52b9076fce846dc0df7dedbbb809f5ad86594836cdf300aa52e89c", + "slot": 17 + }, + "source": { + "root": "0x9bf715c4c4a099d286081d4973cd180967e923ebf61d85f2d64f065ee1460239", + "slot": 16 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 18, + "attestationTargetSlot": 12 + }, + "stepType": "block", + "block": { + "block": { + "slot": 18, + "proposerIndex": 2, + "parentRoot": "0x5ab5e0e2dd52b9076fce846dc0df7dedbbb809f5ad86594836cdf300aa52e89c", + "stateRoot": "0x0dddad591cac1af9b2a6fb13cf06110a115fb87f4e6fbc127e1d63dc3684b57f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 18, + "head": { + "root": "0xa10475de3e420df861e24d46c7268a4ce79390d5b6be108edadc1837e2513a1f", + "slot": 18 + }, + "target": { + "root": "0xa10475de3e420df861e24d46c7268a4ce79390d5b6be108edadc1837e2513a1f", + "slot": 18 + }, + "source": { + "root": "0x5ab5e0e2dd52b9076fce846dc0df7dedbbb809f5ad86594836cdf300aa52e89c", + "slot": 17 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 19, + "attestationTargetSlot": 16 + }, + "stepType": "block", + "block": { + "block": { + "slot": 19, + "proposerIndex": 3, + "parentRoot": "0xa10475de3e420df861e24d46c7268a4ce79390d5b6be108edadc1837e2513a1f", + "stateRoot": "0x1b3b24afa247a15b16c78bf8794e8714147a064ea6a87c95b542d2446c5c7294", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 19, + "head": { + "root": "0x1e444c5fdb8e44542f0e551713cea7ee9f5170e00e35db1b39f32ee0af326e2a", + "slot": 19 + }, + "target": { + "root": "0x1e444c5fdb8e44542f0e551713cea7ee9f5170e00e35db1b39f32ee0af326e2a", + "slot": 19 + }, + "source": { + "root": "0xa10475de3e420df861e24d46c7268a4ce79390d5b6be108edadc1837e2513a1f", + "slot": 18 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 20, + "attestationTargetSlot": 16 + }, + "stepType": "block", + "block": { + "block": { + "slot": 20, + "proposerIndex": 0, + "parentRoot": "0x1e444c5fdb8e44542f0e551713cea7ee9f5170e00e35db1b39f32ee0af326e2a", + "stateRoot": "0x509175b34255a39867d79d9cc52d03f7b861dcb486f84359105245e2fc3bf645", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 20, + "head": { + "root": "0x160e696177ca522f53d8c7a393aee76f03d568a47d1df8b7ec70a28c67dc289b", + "slot": 20 + }, + "target": { + "root": "0x160e696177ca522f53d8c7a393aee76f03d568a47d1df8b7ec70a28c67dc289b", + "slot": 20 + }, + "source": { + "root": "0x1e444c5fdb8e44542f0e551713cea7ee9f5170e00e35db1b39f32ee0af326e2a", + "slot": 19 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 21, + "attestationTargetSlot": 16 + }, + "stepType": "block", + "block": { + "block": { + "slot": 21, + "proposerIndex": 1, + "parentRoot": "0x160e696177ca522f53d8c7a393aee76f03d568a47d1df8b7ec70a28c67dc289b", + "stateRoot": "0x79bb08c3f64723e4f213f46bd7426eed16010ec637884c3311c12f23704847f6", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 21, + "head": { + "root": "0x1d755139ad769203ab454a4a2e7d52fe63236a4115b3968ff166f4a598b1576b", + "slot": 21 + }, + "target": { + "root": "0x1d755139ad769203ab454a4a2e7d52fe63236a4115b3968ff166f4a598b1576b", + "slot": 21 + }, + "source": { + "root": "0x160e696177ca522f53d8c7a393aee76f03d568a47d1df8b7ec70a28c67dc289b", + "slot": 20 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 22, + "attestationTargetSlot": 16 + }, + "stepType": "block", + "block": { + "block": { + "slot": 22, + "proposerIndex": 2, + "parentRoot": "0x1d755139ad769203ab454a4a2e7d52fe63236a4115b3968ff166f4a598b1576b", + "stateRoot": "0xb73b78fa1a8d19c3ee1dc7b853ec5f697efdd45e8584c7a06a9ee6fe289e51c3", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 22, + "head": { + "root": "0x68efe79fefbdf33abc606b078ce6fe62a773353e6aa899bce52a6ec1f53e010d", + "slot": 22 + }, + "target": { + "root": "0x68efe79fefbdf33abc606b078ce6fe62a773353e6aa899bce52a6ec1f53e010d", + "slot": 22 + }, + "source": { + "root": "0x1d755139ad769203ab454a4a2e7d52fe63236a4115b3968ff166f4a598b1576b", + "slot": 21 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 23, + "attestationTargetSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 23, + "proposerIndex": 3, + "parentRoot": "0x68efe79fefbdf33abc606b078ce6fe62a773353e6aa899bce52a6ec1f53e010d", + "stateRoot": "0xd3c53d832adc3bf00f17c4e3f10c5f8210103c9af17681b0432d3f8baf9bd3ed", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 23, + "head": { + "root": "0x644ab973f7c89646f9e82bb7ea5175a4ca34563a81c8da2237720eb57fe1f242", + "slot": 23 + }, + "target": { + "root": "0x644ab973f7c89646f9e82bb7ea5175a4ca34563a81c8da2237720eb57fe1f242", + "slot": 23 + }, + "source": { + "root": "0x68efe79fefbdf33abc606b078ce6fe62a773353e6aa899bce52a6ec1f53e010d", + "slot": 22 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 24, + "attestationTargetSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 24, + "proposerIndex": 0, + "parentRoot": "0x644ab973f7c89646f9e82bb7ea5175a4ca34563a81c8da2237720eb57fe1f242", + "stateRoot": "0xe0a513ac888aa11b36f0df3ddbfcf0f687170eaa86825c80af4c89e199efab5d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 24, + "head": { + "root": "0x0234314daa2c54da18568501272e0647fba0b7fcbba0192d4891e78c722d4ea7", + "slot": 24 + }, + "target": { + "root": "0x0234314daa2c54da18568501272e0647fba0b7fcbba0192d4891e78c722d4ea7", + "slot": 24 + }, + "source": { + "root": "0x644ab973f7c89646f9e82bb7ea5175a4ca34563a81c8da2237720eb57fe1f242", + "slot": 23 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 25, + "attestationTargetSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 25, + "proposerIndex": 1, + "parentRoot": "0x0234314daa2c54da18568501272e0647fba0b7fcbba0192d4891e78c722d4ea7", + "stateRoot": "0x7b674b0db5c15561d09dfd2971a3c56d8f11141b7c87958b805d2edb79e6fa89", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 25, + "head": { + "root": "0x1eb98f1d121a3b1c8f220a8b6c2342db60cb4a230d114cedc4535a506c42ebb1", + "slot": 25 + }, + "target": { + "root": "0x1eb98f1d121a3b1c8f220a8b6c2342db60cb4a230d114cedc4535a506c42ebb1", + "slot": 25 + }, + "source": { + "root": "0x0234314daa2c54da18568501272e0647fba0b7fcbba0192d4891e78c722d4ea7", + "slot": 24 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 26, + "attestationTargetSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 26, + "proposerIndex": 2, + "parentRoot": "0x1eb98f1d121a3b1c8f220a8b6c2342db60cb4a230d114cedc4535a506c42ebb1", + "stateRoot": "0xdc21edfbb53be848249d76c0a93d6f4e1552aa2893d97001757fcf5204e384b3", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 26, + "head": { + "root": "0x66648a97c6d60562c9bb5d4931563ef470ca94013cb7b689ca3d9e097a5e4eb5", + "slot": 26 + }, + "target": { + "root": "0x66648a97c6d60562c9bb5d4931563ef470ca94013cb7b689ca3d9e097a5e4eb5", + "slot": 26 + }, + "source": { + "root": "0x1eb98f1d121a3b1c8f220a8b6c2342db60cb4a230d114cedc4535a506c42ebb1", + "slot": 25 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 27, + "attestationTargetSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 27, + "proposerIndex": 3, + "parentRoot": "0x66648a97c6d60562c9bb5d4931563ef470ca94013cb7b689ca3d9e097a5e4eb5", + "stateRoot": "0x71e6af3c7c39577d8b196328bcb0c670ab9dcc6510c6d55e2c40c7fafc88eaac", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 27, + "head": { + "root": "0x6b0e96c384ff2567e03d11e64c24213cc9c72a0653673069dcf6ebb551d56b5a", + "slot": 27 + }, + "target": { + "root": "0x6b0e96c384ff2567e03d11e64c24213cc9c72a0653673069dcf6ebb551d56b5a", + "slot": 27 + }, + "source": { + "root": "0x66648a97c6d60562c9bb5d4931563ef470ca94013cb7b689ca3d9e097a5e4eb5", + "slot": 26 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 28, + "attestationTargetSlot": 25 + }, + "stepType": "block", + "block": { + "block": { + "slot": 28, + "proposerIndex": 0, + "parentRoot": "0x6b0e96c384ff2567e03d11e64c24213cc9c72a0653673069dcf6ebb551d56b5a", + "stateRoot": "0xa965f6bc4d054a079c30cfb2a3214388b21f8c50174ef8833588bbb695d1bfdc", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 28, + "head": { + "root": "0xcd1bb122b881dbb195073c58a3efc9aa5e15624c0fcfea456adaea00d1063b41", + "slot": 28 + }, + "target": { + "root": "0xcd1bb122b881dbb195073c58a3efc9aa5e15624c0fcfea456adaea00d1063b41", + "slot": 28 + }, + "source": { + "root": "0x6b0e96c384ff2567e03d11e64c24213cc9c72a0653673069dcf6ebb551d56b5a", + "slot": 27 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 29, + "attestationTargetSlot": 25 + }, + "stepType": "block", + "block": { + "block": { + "slot": 29, + "proposerIndex": 1, + "parentRoot": "0xcd1bb122b881dbb195073c58a3efc9aa5e15624c0fcfea456adaea00d1063b41", + "stateRoot": "0xd13df2b3510ba367dd1caab358afb488c5fddc93deb6a4555a7912f6f2d16c5e", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 29, + "head": { + "root": "0xf15bf290ab87593e34252d3e0e4df7c42f52b213423d6eb2c853450ce826891d", + "slot": 29 + }, + "target": { + "root": "0xf15bf290ab87593e34252d3e0e4df7c42f52b213423d6eb2c853450ce826891d", + "slot": 29 + }, + "source": { + "root": "0xcd1bb122b881dbb195073c58a3efc9aa5e15624c0fcfea456adaea00d1063b41", + "slot": 28 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 30, + "attestationTargetSlot": 25 + }, + "stepType": "block", + "block": { + "block": { + "slot": 30, + "proposerIndex": 2, + "parentRoot": "0xf15bf290ab87593e34252d3e0e4df7c42f52b213423d6eb2c853450ce826891d", + "stateRoot": "0x26e27ecd1f35e797e7a3dec0f99c3d2b1e18a8ee98d207c713cb5d6cf0bf3952", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 30, + "head": { + "root": "0x3723b611b7a26e94fe8d9aee1e197ec1bc14491d0fda545e1a557da30446acde", + "slot": 30 + }, + "target": { + "root": "0x3723b611b7a26e94fe8d9aee1e197ec1bc14491d0fda545e1a557da30446acde", + "slot": 30 + }, + "source": { + "root": "0xf15bf290ab87593e34252d3e0e4df7c42f52b213423d6eb2c853450ce826891d", + "slot": 29 + } + } + } + } + } + ], + "maxSlot": 30, + "_info": { + "hash": "0xb1e567c6cc5f6b7572aa1a939c8f14cb8222862a678821414f8202e16b465bbb", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_justifiable_constraint[fork_Devnet]", + "description": "Attestation target advances while respecting justifiability rules.\n\nScenario\n--------\nBuild a 10-slot chain and observe how the attestation target advances\nover time while remaining justifiable relative to genesis (finalized at slot 0).\n\nJustifiability Rules (see Slot.is_justifiable_after)\n-----------------------------------------------------\n\nThe target starts from current head and looks back at most 3 slots towards safe target.\n\nThen, a slot is deemed justifiable at distance delta from finalization if:\n1. delta \u2264 5\n2. delta is a perfect square (1, 4, 9, 16, 25, ...)\n3. delta is a pronic number (2, 6, 12, 20, 30, ...)\n\nWhy This Matters\n----------------\nThe justifiability rules prevent long-range attacks by restricting which\ncheckpoints validators can attest to. The mathematical pattern (perfect squares\nand pronic numbers) creates increasingly sparse justifiable slots as the chain\ngrows beyond finalization, providing security guarantees.\n\nThe test verifies that the target selection algorithm respects these rules\nand never selects a non-justifiable target.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_extended_chain.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_extended_chain.json new file mode 100644 index 00000000..a8aa6f6c --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_extended_chain.json @@ -0,0 +1,391 @@ +{ + "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_with_extended_chain[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "attestationTargetSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationTargetSlot": 2 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "attestationTargetSlot": 3 + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "stateRoot": "0x6faedde65fafaab574997ecdff9099bfed9f3c0791fd974d960eb1493f965568", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 6, + "head": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + }, + "target": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + }, + "source": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "attestationTargetSlot": 4 + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "stateRoot": "0xfc5dce49282828fcde3140191ea2d0e985f837523ea0126c04dc341cdc7592a1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + }, + "target": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + }, + "source": { + "root": "0x787df4f8e62ba7f53959a8f5cbb8ef0908ebc7797424a23ebd59802fbee13e16", + "slot": 6 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 8, + "attestationTargetSlot": 5 + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "stateRoot": "0x63880bd0e6da9f5a68ae84867243d8b6f097b9905306bd6a57713c65e9f1e078", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 8, + "head": { + "root": "0xad89e020ed105a85697fa04011f480d68da1745b792c3a5fd6f516aaf24530cd", + "slot": 8 + }, + "target": { + "root": "0xad89e020ed105a85697fa04011f480d68da1745b792c3a5fd6f516aaf24530cd", + "slot": 8 + }, + "source": { + "root": "0x288aaa9ecce7157977a132a11060477e46a3bb6fc75a4faae68f73cc7de45182", + "slot": 7 + } + } + } + } + } + ], + "maxSlot": 8, + "_info": { + "hash": "0xeeb87588c51014b324c1020800cf5eda2dcd20594305baf77a269f92d43cefb3", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_with_extended_chain[fork_Devnet]", + "description": "Attestation target advances progressively over extended chain.\n\nScenario\n--------\nBuild a longer chain (slots 1-8) observing target advancement pattern.\n\nExpected:\n - Initial slots: target at genesis (conservative)\n - Middle slots: target advances to slot 1\n - Target advances gradually, not jumping to head\n\nWhy This Matters\n----------------\nOver extended chains, the target selection should show smooth,\ngradual advancement as attestation weight accumulates.\n\nThe target lags behind the head, providing a stable reference point that\nadvances only when sufficient consensus has formed. This prevents validators\nfrom attesting too far ahead without adequate safety guarantees.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_slot_gaps.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_slot_gaps.json new file mode 100644 index 00000000..febadc00 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_attestation_target_selection/test_attestation_target_with_slot_gaps.json @@ -0,0 +1,196 @@ +{ + "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_with_slot_gaps[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0x52299092cb8fa2daff77887f36a0a0e0127cdb5745fcc1f1f0fa8286b2ef12d1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "target": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "attestationTargetSlot": 0 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "stateRoot": "0xf8484eef6235dc31d56a0515ad390e016d43b058609649c84661e08aa52026b0", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "target": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "source": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + } + } + } + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0x81ddfbd33ec5baf7816c62c64d6cbbbad985d7bdae34be56f25ced5856846214", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_attestation_target_selection.py::test_attestation_target_with_slot_gaps[fork_Devnet]", + "description": "Attestation target handles missed slots correctly.\n\nScenario\n--------\nProcess blocks at slots 1, 3, 5 (skipping even slots).\n\nExpected:\n - Targets advance despite gaps\n - Targets remain justifiable\n - Safe target stays valid\n\nWhy This Matters\n----------------\nMissed slots are common when proposers fail or network partitions occur.\n\nThe target selection must handle sparse block production gracefully,\nensuring validators can still make progress even with gaps in the chain.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_advances_through_deep_chain.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_advances_through_deep_chain.json new file mode 100644 index 00000000..d6de27c5 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_advances_through_deep_chain.json @@ -0,0 +1,842 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_advances_through_deep_chain[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x5b27de645ac0eb3ebcc0183529f5fb700c3e0c1af217d84cd419716ef7f9ca0cb4641417e7f3d142c932d55aec7c996a5ff6274f", + "index": 0 + }, + { + "pubkey": "0x59537c4b334153515854951621e68136b3c5754a74a0fb07d053940512803132736d4377a3b2ac1e0efb7808d303d11c5a726172", + "index": 1 + }, + { + "pubkey": "0xfb2cd66945687c56f1e73c6510ed3709fadc490856af303000d8e359f7555814da4bfc65418edc7c59760d00715f3b317c965222", + "index": 2 + }, + { + "pubkey": "0x72e9d60c4e5b6819bc7d5452f9ceda70aaa70b33ac68c701510f7a32d26903653803f668b699cd4260ff620b4e0bde5824c59a5d", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x3057a3bc92322925476f228434c50be539568226104e3532fa971ac14933d99d", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xca3d3aba115af87adc0d98dda0e9647789e1e5c58ac399da7871a9e070a816df", + "stateRoot": "0xe06b4e6646ce84e72052a1ebe99002482d314410bd88122b8288d46692dcc4bf", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0xa686be44a409e684a5eab6923d5d7758e38088b0b5824507f3fd131b1f37b8b0", + "slot": 1 + }, + "target": { + "root": "0xa686be44a409e684a5eab6923d5d7758e38088b0b5824507f3fd131b1f37b8b0", + "slot": 1 + }, + "source": { + "root": "0xca3d3aba115af87adc0d98dda0e9647789e1e5c58ac399da7871a9e070a816df", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 2 + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0xa686be44a409e684a5eab6923d5d7758e38088b0b5824507f3fd131b1f37b8b0", + "stateRoot": "0xb63d97476aeffaec6003c9582ca3f19e7b47f913443e210e3883e61b1e30df72", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xb94167821b0515385d5e6e2901ca845e30bd2b960ad1042ef35af02aef2b01c2", + "slot": 2 + }, + "target": { + "root": "0xb94167821b0515385d5e6e2901ca845e30bd2b960ad1042ef35af02aef2b01c2", + "slot": 2 + }, + "source": { + "root": "0xa686be44a409e684a5eab6923d5d7758e38088b0b5824507f3fd131b1f37b8b0", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xb94167821b0515385d5e6e2901ca845e30bd2b960ad1042ef35af02aef2b01c2", + "stateRoot": "0xa3967d3a4ab387206f2cb82847bd366f32c230b6c7fb6350bf4507fb71ec438e", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x6bfb86316698c15ba1e3865b229ff9131ce08db78485c0e0d2912a496cb42e67", + "slot": 3 + }, + "target": { + "root": "0x6bfb86316698c15ba1e3865b229ff9131ce08db78485c0e0d2912a496cb42e67", + "slot": 3 + }, + "source": { + "root": "0xb94167821b0515385d5e6e2901ca845e30bd2b960ad1042ef35af02aef2b01c2", + "slot": 2 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 4 + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x6bfb86316698c15ba1e3865b229ff9131ce08db78485c0e0d2912a496cb42e67", + "stateRoot": "0x725268e978537148dcf619bce17e360d3b84a86d47b75ffdbaa82f1b5663211d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0xca1c993cfe2058eeed6ca34c1f34157a1fb72f31b8dd33b8d0413bc28dc8bace", + "slot": 4 + }, + "target": { + "root": "0xca1c993cfe2058eeed6ca34c1f34157a1fb72f31b8dd33b8d0413bc28dc8bace", + "slot": 4 + }, + "source": { + "root": "0x6bfb86316698c15ba1e3865b229ff9131ce08db78485c0e0d2912a496cb42e67", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0xca1c993cfe2058eeed6ca34c1f34157a1fb72f31b8dd33b8d0413bc28dc8bace", + "stateRoot": "0x9c8be4111caf283073ead013fb181d756038047c81b2c4ef24c27beeef466ff8", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0xd635223cef5ad929ff22ac58e9e03d0994fdf3c0dac42af2208c2b283ca91cfc", + "slot": 5 + }, + "target": { + "root": "0xd635223cef5ad929ff22ac58e9e03d0994fdf3c0dac42af2208c2b283ca91cfc", + "slot": 5 + }, + "source": { + "root": "0xca1c993cfe2058eeed6ca34c1f34157a1fb72f31b8dd33b8d0413bc28dc8bace", + "slot": 4 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 6 + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0xd635223cef5ad929ff22ac58e9e03d0994fdf3c0dac42af2208c2b283ca91cfc", + "stateRoot": "0x2f714e708f48e737075ba94269cd46f8a64156ae7da3f53b074453618b9d3c6d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 6, + "head": { + "root": "0xf73eaf3815e2c0da2f61f4395ce25752ebaf0581418756d3f20b0f0dd263d58b", + "slot": 6 + }, + "target": { + "root": "0xf73eaf3815e2c0da2f61f4395ce25752ebaf0581418756d3f20b0f0dd263d58b", + "slot": 6 + }, + "source": { + "root": "0xd635223cef5ad929ff22ac58e9e03d0994fdf3c0dac42af2208c2b283ca91cfc", + "slot": 5 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7 + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0xf73eaf3815e2c0da2f61f4395ce25752ebaf0581418756d3f20b0f0dd263d58b", + "stateRoot": "0x85e96b1a1e226a512429b597329022834e3f5d78b3430d5f99f62ccd57b91d68", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0xa25d1989523b19dedf46df096b96ab9929b52b87dde1c865cebbaf8f0bde59ef", + "slot": 7 + }, + "target": { + "root": "0xa25d1989523b19dedf46df096b96ab9929b52b87dde1c865cebbaf8f0bde59ef", + "slot": 7 + }, + "source": { + "root": "0xf73eaf3815e2c0da2f61f4395ce25752ebaf0581418756d3f20b0f0dd263d58b", + "slot": 6 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 8 + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0xa25d1989523b19dedf46df096b96ab9929b52b87dde1c865cebbaf8f0bde59ef", + "stateRoot": "0xf965a39410ae082ea2a8cdb7cc72f175d2188c732288b40ee309aa8c83a267b1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 8, + "head": { + "root": "0x7969f418b7b77002320cd943f9b6b3079a1e77ab6ce8eba2821862af6f91925b", + "slot": 8 + }, + "target": { + "root": "0x7969f418b7b77002320cd943f9b6b3079a1e77ab6ce8eba2821862af6f91925b", + "slot": 8 + }, + "source": { + "root": "0xa25d1989523b19dedf46df096b96ab9929b52b87dde1c865cebbaf8f0bde59ef", + "slot": 7 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 9 + }, + "stepType": "block", + "block": { + "block": { + "slot": 9, + "proposerIndex": 1, + "parentRoot": "0x7969f418b7b77002320cd943f9b6b3079a1e77ab6ce8eba2821862af6f91925b", + "stateRoot": "0x2e995c265245db3eed946683386d7221e3337e921506d4250bd1fbd1064a2001", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 9, + "head": { + "root": "0xd2e3e8cdeb79f6d5f986aa1ae37bd76217b12f0630bc1d24c287e655e3408380", + "slot": 9 + }, + "target": { + "root": "0xd2e3e8cdeb79f6d5f986aa1ae37bd76217b12f0630bc1d24c287e655e3408380", + "slot": 9 + }, + "source": { + "root": "0x7969f418b7b77002320cd943f9b6b3079a1e77ab6ce8eba2821862af6f91925b", + "slot": 8 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 10 + }, + "stepType": "block", + "block": { + "block": { + "slot": 10, + "proposerIndex": 2, + "parentRoot": "0xd2e3e8cdeb79f6d5f986aa1ae37bd76217b12f0630bc1d24c287e655e3408380", + "stateRoot": "0xb4b8ace0b9907db2fe60d9845fd28ad5ff8acb99783d12a7cf77dbb5e049d509", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 10, + "head": { + "root": "0xb50e446e0108122d5148283138f428dee1fbe586b5924573dc8f666b1d16c306", + "slot": 10 + }, + "target": { + "root": "0xb50e446e0108122d5148283138f428dee1fbe586b5924573dc8f666b1d16c306", + "slot": 10 + }, + "source": { + "root": "0xd2e3e8cdeb79f6d5f986aa1ae37bd76217b12f0630bc1d24c287e655e3408380", + "slot": 9 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 11 + }, + "stepType": "block", + "block": { + "block": { + "slot": 11, + "proposerIndex": 3, + "parentRoot": "0xb50e446e0108122d5148283138f428dee1fbe586b5924573dc8f666b1d16c306", + "stateRoot": "0x886cc6928f0b27d24b4ad4468c8a1dc6ce1c2be9271953cb0a15bba34fa99e20", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 11, + "head": { + "root": "0xf0e38c5c39420cce3beb4264d38fe3533776cba01d1d891e8a60922c53519d21", + "slot": 11 + }, + "target": { + "root": "0xf0e38c5c39420cce3beb4264d38fe3533776cba01d1d891e8a60922c53519d21", + "slot": 11 + }, + "source": { + "root": "0xb50e446e0108122d5148283138f428dee1fbe586b5924573dc8f666b1d16c306", + "slot": 10 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 12 + }, + "stepType": "block", + "block": { + "block": { + "slot": 12, + "proposerIndex": 0, + "parentRoot": "0xf0e38c5c39420cce3beb4264d38fe3533776cba01d1d891e8a60922c53519d21", + "stateRoot": "0x81d72385bb9fc0805ff3620cdb9dbe451bac10b23b52ea920c1c1e28fe1d02ee", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 12, + "head": { + "root": "0xf7c43320b83f14895f164a310acc07de781112bcf62b45e44bb95ee6132a2796", + "slot": 12 + }, + "target": { + "root": "0xf7c43320b83f14895f164a310acc07de781112bcf62b45e44bb95ee6132a2796", + "slot": 12 + }, + "source": { + "root": "0xf0e38c5c39420cce3beb4264d38fe3533776cba01d1d891e8a60922c53519d21", + "slot": 11 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 13 + }, + "stepType": "block", + "block": { + "block": { + "slot": 13, + "proposerIndex": 1, + "parentRoot": "0xf7c43320b83f14895f164a310acc07de781112bcf62b45e44bb95ee6132a2796", + "stateRoot": "0x44ba249aa09d691b65665337057cfcb16d74062444160bfe6d04ad24d2afa4b4", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 13, + "head": { + "root": "0xeda183f8e29126c3e8fa2a78d93ed14c41043f54da8da327e51337f629518832", + "slot": 13 + }, + "target": { + "root": "0xeda183f8e29126c3e8fa2a78d93ed14c41043f54da8da327e51337f629518832", + "slot": 13 + }, + "source": { + "root": "0xf7c43320b83f14895f164a310acc07de781112bcf62b45e44bb95ee6132a2796", + "slot": 12 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 14 + }, + "stepType": "block", + "block": { + "block": { + "slot": 14, + "proposerIndex": 2, + "parentRoot": "0xeda183f8e29126c3e8fa2a78d93ed14c41043f54da8da327e51337f629518832", + "stateRoot": "0x4f0700bc93e057a94f9d9927b713ea8478c88a68ba533babe62992d0139cb880", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 14, + "head": { + "root": "0x77da6962903ffdf615c67b9947a6c7ea5577778110977e30b022b5b0d901c15c", + "slot": 14 + }, + "target": { + "root": "0x77da6962903ffdf615c67b9947a6c7ea5577778110977e30b022b5b0d901c15c", + "slot": 14 + }, + "source": { + "root": "0xeda183f8e29126c3e8fa2a78d93ed14c41043f54da8da327e51337f629518832", + "slot": 13 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 15 + }, + "stepType": "block", + "block": { + "block": { + "slot": 15, + "proposerIndex": 3, + "parentRoot": "0x77da6962903ffdf615c67b9947a6c7ea5577778110977e30b022b5b0d901c15c", + "stateRoot": "0x238fc8d10d3daebf1d6c90c835db2c1b8c6f92c1fb15d9999435bd2af00297b2", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 15, + "head": { + "root": "0xa49db3c225ae9b38d553effacbe0c8b8e2eee7195ae5f03c694d073ecf894cc6", + "slot": 15 + }, + "target": { + "root": "0xa49db3c225ae9b38d553effacbe0c8b8e2eee7195ae5f03c694d073ecf894cc6", + "slot": 15 + }, + "source": { + "root": "0x77da6962903ffdf615c67b9947a6c7ea5577778110977e30b022b5b0d901c15c", + "slot": 14 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 16 + }, + "stepType": "block", + "block": { + "block": { + "slot": 16, + "proposerIndex": 0, + "parentRoot": "0xa49db3c225ae9b38d553effacbe0c8b8e2eee7195ae5f03c694d073ecf894cc6", + "stateRoot": "0xcaed813e81b574e68b8519b3a4f924dc98fdd3348614778d8fb4766fd37f1ae8", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 16, + "head": { + "root": "0x8943519147ca8595a0f2333b8b9da73696e516ae8546fdfcc1de52bfce8d606c", + "slot": 16 + }, + "target": { + "root": "0x8943519147ca8595a0f2333b8b9da73696e516ae8546fdfcc1de52bfce8d606c", + "slot": 16 + }, + "source": { + "root": "0xa49db3c225ae9b38d553effacbe0c8b8e2eee7195ae5f03c694d073ecf894cc6", + "slot": 15 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 17 + }, + "stepType": "block", + "block": { + "block": { + "slot": 17, + "proposerIndex": 1, + "parentRoot": "0x8943519147ca8595a0f2333b8b9da73696e516ae8546fdfcc1de52bfce8d606c", + "stateRoot": "0x2bdf70090badcfd9f5b280599b58b3c162cdc8786fe32f153613a5b9e9fd3221", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 17, + "head": { + "root": "0x989640c455e9cea4d60dec77641a4bd990be1971c5078142c8b0e9c00d72e442", + "slot": 17 + }, + "target": { + "root": "0x989640c455e9cea4d60dec77641a4bd990be1971c5078142c8b0e9c00d72e442", + "slot": 17 + }, + "source": { + "root": "0x8943519147ca8595a0f2333b8b9da73696e516ae8546fdfcc1de52bfce8d606c", + "slot": 16 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 18 + }, + "stepType": "block", + "block": { + "block": { + "slot": 18, + "proposerIndex": 2, + "parentRoot": "0x989640c455e9cea4d60dec77641a4bd990be1971c5078142c8b0e9c00d72e442", + "stateRoot": "0x75c058eeb814c4c9d911f3d4956eac9d63a2acc367f19a507ac1332b51626d1b", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 18, + "head": { + "root": "0xb5f5ae05ab63196fb2e3c30a53f0164b02f6dc23cbcc576d341caf0406732a0e", + "slot": 18 + }, + "target": { + "root": "0xb5f5ae05ab63196fb2e3c30a53f0164b02f6dc23cbcc576d341caf0406732a0e", + "slot": 18 + }, + "source": { + "root": "0x989640c455e9cea4d60dec77641a4bd990be1971c5078142c8b0e9c00d72e442", + "slot": 17 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 19 + }, + "stepType": "block", + "block": { + "block": { + "slot": 19, + "proposerIndex": 3, + "parentRoot": "0xb5f5ae05ab63196fb2e3c30a53f0164b02f6dc23cbcc576d341caf0406732a0e", + "stateRoot": "0x62f4206cb8a53fe36f248c4dda135aa146a8ad886b54244c98498d055a9a8287", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 19, + "head": { + "root": "0x88088a9e6572609b989b9ac3076b6be3e2d2b29af623f2383323237997b36be6", + "slot": 19 + }, + "target": { + "root": "0x88088a9e6572609b989b9ac3076b6be3e2d2b29af623f2383323237997b36be6", + "slot": 19 + }, + "source": { + "root": "0xb5f5ae05ab63196fb2e3c30a53f0164b02f6dc23cbcc576d341caf0406732a0e", + "slot": 18 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 20, + "headRoot": "0x97e8216e32c0a013c4e88b33cdf6dd8f691981143aa86fcb9c7cb508cc6f87a9", + "headRootLabel": "block_20" + }, + "stepType": "block", + "block": { + "block": { + "slot": 20, + "proposerIndex": 0, + "parentRoot": "0x88088a9e6572609b989b9ac3076b6be3e2d2b29af623f2383323237997b36be6", + "stateRoot": "0x34fdc6d6820c04cea41fdbfcd8c8d34da4939421455ff157886877a821fcb9cf", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 20, + "head": { + "root": "0x97e8216e32c0a013c4e88b33cdf6dd8f691981143aa86fcb9c7cb508cc6f87a9", + "slot": 20 + }, + "target": { + "root": "0x97e8216e32c0a013c4e88b33cdf6dd8f691981143aa86fcb9c7cb508cc6f87a9", + "slot": 20 + }, + "source": { + "root": "0x88088a9e6572609b989b9ac3076b6be3e2d2b29af623f2383323237997b36be6", + "slot": 19 + } + } + }, + "blockRootLabel": "block_20" + } + } + ], + "maxSlot": 20, + "_info": { + "hash": "0xe5f2d2cf98add4f72278977b7c2cdab176c0b0f83632fb85b324e32dd5d54742", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_advances_through_deep_chain[fork_Devnet]", + "description": "Fork choice head advances through a deep chain correctly.\n\nScenario\n--------\nBuild a long chain (slots 1-20) and verify head reaches the end.\n\nExpected Behavior:\n - Head advances through all 20 blocks\n - Final head = slot 20\n - Fork choice scales to longer chains\n\nWhy This Matters\n----------------\nThis tests that the fork choice algorithm scales to longer chains and\ncorrectly handles the tree-walking logic through many blocks.\n\nReal networks have chains thousands of blocks long. The algorithm must:\n- Efficiently traverse deep trees\n- Maintain correct head even with many ancestors\n- Not degrade in performance or correctness with depth\n\nA 20-block chain is a modest test of this scalability.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_switches_to_heavier_fork.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_switches_to_heavier_fork.json new file mode 100644 index 00000000..8d098fa4 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_switches_to_heavier_fork.json @@ -0,0 +1,243 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_switches_to_heavier_fork[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "common" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "common" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_b_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + } + ], + "maxSlot": 3, + "_info": { + "hash": "0xd1c1fd4d780866ee766f5aaf671bee4509b7318c5cd190f77914051d7158fa11", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_switches_to_heavier_fork[fork_Devnet]", + "description": "Fork choice head switches when a competing fork becomes heavier.\n\nScenario\n--------\nCreate two forks at slot 2, then extend one fork to make it heavier.\n\nExpected Behavior:\n - After fork A (slot 2): head = fork A\n - After fork B (slot 2): head = still fork A (tie-breaker)\n - After extending fork B (slot 3): head = slot 3 (fork B wins!)\n\nWhy This Matters\n----------------\nThis demonstrates the core LMD-GHOST property: the head follows the heaviest\nsubtree. When fork B is extended with a child block, that child's proposer\nimplicitly attests to fork B, giving it more weight.\n\nFork choice recognizes this weight increase and switches the head to fork B's\ndescendant. This is how the protocol reaches consensus - validators converge\non the fork with the most support (weight).\n\nThis is also how reorgs happen: a previously non-canonical fork can become\ncanonical if it gains more attestation weight.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_deep_fork_split.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_deep_fork_split.json new file mode 100644 index 00000000..b77dfb3f --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_deep_fork_split.json @@ -0,0 +1,407 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_deep_fork_split[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "common" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "common" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_b_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "headRoot": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "headRootLabel": "fork_b_5" + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + }, + "blockRootLabel": "fork_b_5" + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0xc0ba21567150219fae85c95c40a345c04758436f0e4a6f35b7442ce5f7edcef6", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_deep_fork_split[fork_Devnet]", + "description": "Fork choice handles deep fork splits correctly.\n\nScenario\n--------\nCreate two forks that diverge at slot 2 and extend to different depths.\n\nExpected Behavior:\n - Fork A extends to slot 4\n - Fork B extends to slot 5\n - Head follows the longer (heavier) fork B\n\nWhy This Matters\n----------------\nIn practice, forks can persist for multiple slots before one gains dominance.\nThis tests that fork choice correctly follows the deeper fork, which has\naccumulated more proposer attestations along its chain.\n\nEach block in a fork adds weight from its proposer's attestation. A longer\nfork has more accumulated weight from the proposers along its length.\n\nThis is how the protocol ensures liveness: the chain that continues to grow\n(accumulating blocks and attestations) becomes the canonical chain.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_gaps_in_slots.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_gaps_in_slots.json new file mode 100644 index 00000000..c0c25bd8 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_gaps_in_slots.json @@ -0,0 +1,269 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_gaps_in_slots[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 3 + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0x52299092cb8fa2daff77887f36a0a0e0127cdb5745fcc1f1f0fa8286b2ef12d1", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "target": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 5 + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "stateRoot": "0xf8484eef6235dc31d56a0515ad390e016d43b058609649c84661e08aa52026b0", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "target": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + }, + "source": { + "root": "0xb266f4e81e3a8004ac8e0441118216fe7ece1e10512bca075f0485d7426d785b", + "slot": 3 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 7 + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "stateRoot": "0x548f45bad5a36007455d169c4d03cea239f522460bbe97dbd98562c1f857de5f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 7, + "head": { + "root": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "slot": 7 + }, + "target": { + "root": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "slot": 7 + }, + "source": { + "root": "0x76718c36c92f046146f6d27114fc4f61afbbdd67f6e653a5e946c8cce0330b97", + "slot": 5 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 9 + }, + "stepType": "block", + "block": { + "block": { + "slot": 9, + "proposerIndex": 1, + "parentRoot": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "stateRoot": "0x41601573dd6f80b0a3a2463a1bd00cc4fc4a272f667ab268283e88470a05e2ab", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 9, + "head": { + "root": "0xa31f8bda88d6802d265440788a23d87824ff1639cf73aabe03ae4c98ddb96dde", + "slot": 9 + }, + "target": { + "root": "0xa31f8bda88d6802d265440788a23d87824ff1639cf73aabe03ae4c98ddb96dde", + "slot": 9 + }, + "source": { + "root": "0xeb6da2e664677b61a27d6326358a0ea5a4e4d079b553901b829a1c4783660aee", + "slot": 7 + } + } + } + } + } + ], + "maxSlot": 9, + "_info": { + "hash": "0x605acdb8c4ab6dfd03133fbd2dc7c6952f0f59b8d1645819bf4b519f29affc00", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_gaps_in_slots[fork_Devnet]", + "description": "Fork choice head handles missing slots correctly.\n\nScenario\n--------\nBuild blocks at slots 1, 3, 5, 7, 9 (skipping even slots).\n\nExpected Behavior:\n - Head advances to each present block\n - Skipped slots don't affect fork choice\n - Head correctly identifies the leaf despite gaps\n\nWhy This Matters\n----------------\nMissed slots are common in production:\n- Offline proposers\n- Network partitions\n- Proposer failures\n\nFork choice must handle sparse block production correctly. The algorithm\ndoesn't require consecutive slots - it works with any tree structure where\ngaps are simply missing nodes.\n\nThis verifies the algorithm handles real-world conditions where not every\nslot has a block, which is the norm rather than the exception.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_large_gaps.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_large_gaps.json new file mode 100644 index 00000000..62ef7db6 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_large_gaps.json @@ -0,0 +1,231 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_large_gaps[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x10e670451731da463e9f39177f44500759cfb42bea781d0fb154052e3c27156820b3394d69b6f225da39ba0d251d001f9aa2f61a", + "index": 0 + }, + { + "pubkey": "0x9cf650628da8d4614d6d897e067e7411c02afd2cc29403799f660937d395f37641321647c905da6eee96462a0cbb442ba5a7f82f", + "index": 1 + }, + { + "pubkey": "0x73dc1a61fa471b7601f426468532246428f7ba10d71682615991820f2abb0b480ee1424a26c711225a1a1f17619bf0030f6aaa56", + "index": 2 + }, + { + "pubkey": "0x91bcd1462388153a77b9382124b5c42989a32e3e370e52408a04fe6b35246562fa8cc1433a49265c248a1d307ccd126304e9d520", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xdbc753c51cc8d826edac5cff41126a6d7ad1c4cddd60b497dbe9ee6bb0393bfe", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1 + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xf63aa52fb8966777c37589ef513500c055291ce331d5bba46342ee21eeaf211a", + "stateRoot": "0xca648f388b13e8fc49d77bd92b890772eef4a02823b8570cb5836621bf77d5ab", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + }, + "target": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + }, + "source": { + "root": "0xf63aa52fb8966777c37589ef513500c055291ce331d5bba46342ee21eeaf211a", + "slot": 0 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 10 + }, + "stepType": "block", + "block": { + "block": { + "slot": 10, + "proposerIndex": 2, + "parentRoot": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "stateRoot": "0x3b0700dbd82c6106525a59a3ea8d12304b262dc335c313e4e4f2e5e565b2aa24", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 10, + "head": { + "root": "0x2164ad7902767912582416e3e33ef80b71ba1b522de5ef6340d43a58613bef77", + "slot": 10 + }, + "target": { + "root": "0x2164ad7902767912582416e3e33ef80b71ba1b522de5ef6340d43a58613bef77", + "slot": 10 + }, + "source": { + "root": "0x5549b592c682438d34303b79fc1d5d494c0aa88dd3ca4d37a58783ecdc74e503", + "slot": 1 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 20 + }, + "stepType": "block", + "block": { + "block": { + "slot": 20, + "proposerIndex": 0, + "parentRoot": "0x2164ad7902767912582416e3e33ef80b71ba1b522de5ef6340d43a58613bef77", + "stateRoot": "0x325002f103d0769a069d9d82850d65c3704c7c39712693de02d6207bf926e9ff", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 20, + "head": { + "root": "0x6e6d3cdf96c6414629d859e63bded9f206af73dfc13836b78749a1b173e6e125", + "slot": 20 + }, + "target": { + "root": "0x6e6d3cdf96c6414629d859e63bded9f206af73dfc13836b78749a1b173e6e125", + "slot": 20 + }, + "source": { + "root": "0x2164ad7902767912582416e3e33ef80b71ba1b522de5ef6340d43a58613bef77", + "slot": 10 + } + } + } + } + }, + { + "valid": true, + "checks": { + "headSlot": 30 + }, + "stepType": "block", + "block": { + "block": { + "slot": 30, + "proposerIndex": 2, + "parentRoot": "0x6e6d3cdf96c6414629d859e63bded9f206af73dfc13836b78749a1b173e6e125", + "stateRoot": "0xfdb27f373cb43dc17b9f88acd2ed9388f8dd465da277859f535c5cabca7604d8", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 30, + "head": { + "root": "0xf64f2ea1063132ba33651662e9031bd3c4ca06be1bde45f5dc8a84e4c5919e4f", + "slot": 30 + }, + "target": { + "root": "0xf64f2ea1063132ba33651662e9031bd3c4ca06be1bde45f5dc8a84e4c5919e4f", + "slot": 30 + }, + "source": { + "root": "0x6e6d3cdf96c6414629d859e63bded9f206af73dfc13836b78749a1b173e6e125", + "slot": 20 + } + } + } + } + } + ], + "maxSlot": 30, + "_info": { + "hash": "0xe8287cffd06164e6539e8a1660432d717727a8f7e8d9682f9d5e4498aab27849", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_large_gaps[fork_Devnet]", + "description": "Fork choice head handles large gaps between blocks.\n\nScenario\n--------\nBuild blocks at slots 1, 10, 20, 30 (gaps of 9-10 slots).\n\nExpected Behavior:\n - Head advances despite large gaps\n - Fork choice is gap-size independent\n - Head reaches the furthest block\n\nWhy This Matters\n----------------\nLarge gaps can occur during:\n- Extended network partitions\n- Chain reorganizations\n- Periods of high validator downtime\n- Initial sync after being offline\n\nThe fork choice algorithm must remain correct regardless of gap size.\nDistance between blocks should not affect the correctness of head selection -\nonly the tree structure matters.\n\nThis test verifies that even with dramatic gaps (representing severe network\nconditions), fork choice still identifies the correct head.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_two_competing_forks.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_two_competing_forks.json new file mode 100644 index 00000000..3fed1c9f --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_head/test_head_with_two_competing_forks.json @@ -0,0 +1,202 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_two_competing_forks[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "common" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "common" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b" + } + } + ], + "maxSlot": 2, + "_info": { + "hash": "0xbd6b7e5dc113ad2ea1ff4b5927e9261ca860b0a1bd3669594925d9fcfebd16b2", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_head.py::test_head_with_two_competing_forks[fork_Devnet]", + "description": "Fork choice selects head when two forks compete at the same slot.\n\nScenario\n--------\nCreate two competing blocks at slot 2, both building on slot 1.\n\nExpected Behavior:\n - After slot 1: head = slot 1 (common ancestor)\n - After fork A (slot 2): head = slot 2 (fork A, first seen)\n - After fork B (slot 2): head = slot 2 (still fork A)\n - Both forks have equal weight (1 proposer attestation each)\n - Head breaks tie lexicographically by block root\n\nWhy This Matters\n----------------\nThis is an important fork choice scenario: two blocks competing for the\nsame slot. Even with equal attestation weight, fork choice must deterministically\nselect a head.\n\nThe algorithm uses lexicographic order of block roots as a tie-breaker,\nensuring all nodes agree on the same head even when forks have equal weight.\n\nThis prevents network splits and ensures consensus converges.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_back_and_forth_reorg_oscillation.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_back_and_forth_reorg_oscillation.json new file mode 100644 index 00000000..fc63bbc1 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_back_and_forth_reorg_oscillation.json @@ -0,0 +1,407 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_back_and_forth_reorg_oscillation[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_b_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_b_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_b_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "headRoot": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "headRootLabel": "fork_b_5" + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + }, + "blockRootLabel": "fork_b_5" + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0xb7cca37edd73f0f4ab5ac2699826bb3891e098b9482b3cd646348115b7b957db", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_back_and_forth_reorg_oscillation[fork_Devnet]", + "description": "Multiple reorgs as two forks alternately extend (pathological case).\n\nScenario\n--------\nTwo forks alternate extensions, causing head to oscillate back and forth.\nThis is a pathological case that shouldn't happen in healthy networks but\ntests fork choice correctness under extreme conditions.\n\nOscillation Pattern:\n Slot 2: Fork A leads (1 block) \u2190 head\n Slot 3: Fork B catches up (1 block each) \u2192 tie\n Slot 4: Fork B extends (2 vs 1) \u2190 head switches to B\n Slot 5: Fork A extends (2 vs 2) \u2192 tie\n Slot 6: Fork A extends (3 vs 2) \u2190 head switches to A\n Slot 7: Fork B extends (3 vs 3) \u2192 tie\n Slot 8: Fork B extends (4 vs 3) \u2190 head switches to B\n\nExpected Behavior\n-----------------\n1. Head oscillates: A \u2192 B \u2192 A \u2192 B\n2. Each extension triggers reorg to that fork\n3. All reorgs are 1-2 blocks deep\n4. Fork choice remains consistent and correct throughout\n\nReorg Count: 3 reorgs in 6 slots (very high rate)\n\nWhy This Matters\n----------------\nWhile extremely rare, this scenario can theoretically occur:\n- Two validator groups in different network segments\n- Each group primarily seeing their own fork first\n- Alternating proposer selection between groups\n- High network latency preventing convergence\n\nProperties Tested:\n- Fork choice handles rapid reorg sequences\n- No state corruption despite frequent head changes\n- Tie-breaking remains consistent\n- Weight calculation correct after multiple reorgs\n- System eventually stabilizes to heaviest fork\n\nThis stress test verifies robustness under worst-case fork competition,\nensuring the protocol remains safe even in pathological network conditions.\nIn practice, networks self-heal from such scenarios through attestation\nconvergence.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_on_newly_justified_slot.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_on_newly_justified_slot.json new file mode 100644 index 00000000..af19ca7b --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_on_newly_justified_slot.json @@ -0,0 +1,457 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_on_newly_justified_slot[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + }, + { + "pubkey": "0x4251390932051e208b39ea62194e02085ed11218cd8e5117d126a26b131d3e172915311a0ff35f56f10db737b00e9277cc80af02", + "index": 4 + }, + { + "pubkey": "0xad5a6c64e66607145d00ad31baee5d4614f86317a4857d00fed3bf437dea015183d7ee04caa0920a19542626568fb14e3fb4f15e", + "index": 5 + }, + { + "pubkey": "0xcc5a81072e36a40fe2c46d5215feef6a2c08930ee26ff70f8a9f5e5946caeb23cf12912ab09e0f41d9257e0b7520e66ff400e61e", + "index": 6 + }, + { + "pubkey": "0xd33f30792f27d33ed14f437aca83ce337a329971503ef957c3a162526e9c952abf5fd330dfbcae21e949622be072093d54fd4768", + "index": 7 + }, + { + "pubkey": "0x778ade5662bd7f5669e7cc413d94b64f00b3915fdd0d151329e63d2c86e4f12637609d57b85dd34deee1e961aed1c459d0ce6124", + "index": 8 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xa5da51368a2112877be16fed7182f7cc52836c520d1fe918a72681aacaceb7b6", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "stateRoot": "0x519577e3c564375689b44f2978230f45cd45ac79502f1730148f0815ef689f39", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "slot": 1 + }, + "target": { + "root": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "slot": 1 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xe627e8b35161355fcc14ca814c3a16b500dccee1271f8859152464f727277e38", + "headRootLabel": "fork_a_1" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "stateRoot": "0x4d18cedc29fe901886fcbbe79404678cc59497d99f8eb69999ac0af3bd20255c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xe627e8b35161355fcc14ca814c3a16b500dccee1271f8859152464f727277e38", + "slot": 2 + }, + "target": { + "root": "0xe627e8b35161355fcc14ca814c3a16b500dccee1271f8859152464f727277e38", + "slot": 2 + }, + "source": { + "root": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_1" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x646afcc8ef7340da60d61312739beeb8bb718bbe2943ba45a3d2db304f301b90", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xe627e8b35161355fcc14ca814c3a16b500dccee1271f8859152464f727277e38", + "stateRoot": "0x862adca6993abb73611b4698729624cbd0970b36be9419c8522f69b028c14294", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x646afcc8ef7340da60d61312739beeb8bb718bbe2943ba45a3d2db304f301b90", + "slot": 3 + }, + "target": { + "root": "0x646afcc8ef7340da60d61312739beeb8bb718bbe2943ba45a3d2db304f301b90", + "slot": 3 + }, + "source": { + "root": "0xe627e8b35161355fcc14ca814c3a16b500dccee1271f8859152464f727277e38", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x18d7abd999922661013fcc494184c30a1c585207fbde17ea97bec46e702eb332", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 4, + "parentRoot": "0x646afcc8ef7340da60d61312739beeb8bb718bbe2943ba45a3d2db304f301b90", + "stateRoot": "0x4145b4e472534a7c8ea25c729a66d247f720e819a4854a8843d6ed3aed2624df", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 4, + "data": { + "slot": 4, + "head": { + "root": "0x18d7abd999922661013fcc494184c30a1c585207fbde17ea97bec46e702eb332", + "slot": 4 + }, + "target": { + "root": "0x18d7abd999922661013fcc494184c30a1c585207fbde17ea97bec46e702eb332", + "slot": 4 + }, + "source": { + "root": "0x646afcc8ef7340da60d61312739beeb8bb718bbe2943ba45a3d2db304f301b90", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x18d7abd999922661013fcc494184c30a1c585207fbde17ea97bec46e702eb332", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 5, + "parentRoot": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "stateRoot": "0xf50a444600fe5baa1204dae6ed63c48541006af55c98fd7e65db56b356afa1ee", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 5, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x4344d0e27a0db13dcc7392e16f2a82fdc28d1c517765cd4f025e989667838caa", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_1" + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "headRoot": "0x8450c2df6b28b57963630b79f347312315e7fb152d83aa67c0c69addb0f8cf2d", + "headRootLabel": "fork_b_2", + "latestJustifiedSlot": 5, + "latestJustifiedRoot": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "latestJustifiedRootLabel": "fork_b_1" + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 6, + "parentRoot": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "stateRoot": "0x9222e572e0a4622a85005767adb584f9a31ab37557960f694618b5ad3d78c553", + "body": { + "attestations": { + "data": [ + { + "validatorId": 0, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + { + "validatorId": 5, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + { + "validatorId": 6, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + { + "validatorId": 7, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + }, + { + "validatorId": 8, + "data": { + "slot": 5, + "head": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "target": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + }, + "source": { + "root": "0x6122819b44291a2f6b68911a5656f2e0f1c99807ca9c52b22a72d952d6a99a5f", + "slot": 0 + } + } + } + ] + } + } + }, + "proposerAttestation": { + "validatorId": 6, + "data": { + "slot": 6, + "head": { + "root": "0x8450c2df6b28b57963630b79f347312315e7fb152d83aa67c0c69addb0f8cf2d", + "slot": 6 + }, + "target": { + "root": "0x8450c2df6b28b57963630b79f347312315e7fb152d83aa67c0c69addb0f8cf2d", + "slot": 6 + }, + "source": { + "root": "0xcaa31ba4cc318004f5ded2a27cc337eca43f73c64ed882d6e56763ae7e2c02d7", + "slot": 5 + } + } + }, + "blockRootLabel": "fork_b_2" + } + } + ], + "maxSlot": 6, + "_info": { + "hash": "0xc7192b9dce707a85ab9d84959936cc9533fecc76c8d563a39e80ecee9675388f", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_on_newly_justified_slot[fork_Devnet]", + "description": "Reorg occurs correctly when forks cross justification boundaries.\n\nScenario\n--------\nTwo forks compete. Fork A is heavier and longer, but Fork B manages to\nbecome justified. Fork choice must switch to the justified fork regardless\nof weight/length.\n\n- Slot 1: Base\n- Slots 2-4: Fork A extends (becomes head with depth 3)\n- Slot 5: Fork B appears (descending from Base, skipping slots 2-4)\n- Slot 6: Fork B extends. This block contains enough attestations to\n justify Fork B at Slot 5.\n\nExpected Behavior\n-----------------\n1. Fork A takes the lead initially (Slots 2-4) as the heaviest chain.\n2. Fork B appears at Slot 5 but is initially lighter.\n3. At Slot 6, the new block includes attestations that justify Fork B at Slot 5.\n4. The justified checkpoint updates to Slot 5 (fork_b_1).\n5. Fork A is immediately discarded because it does not descend from the new\n justified checkpoint (Fork A is on a branch from Slot 1).\n6. Fork B becomes the canonical head.\n\nWhy This Matters\n----------------\nJustification is a critical safety mechanism:\n- Limits which blocks can be attested to\n- Ensures fork choice respects finality constraints\n\nThis test ensures:\n- Reorgs respect justification boundaries\n- Fork choice works correctly across justifiable slots\n- Safety guarantees maintained during reorgs", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_prevention_heavy_fork_resists_light_competition.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_prevention_heavy_fork_resists_light_competition.json new file mode 100644 index 00000000..ae77cfe4 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_prevention_heavy_fork_resists_light_competition.json @@ -0,0 +1,480 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_prevention_heavy_fork_resists_light_competition[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + }, + { + "pubkey": "0x4251390932051e208b39ea62194e02085ed11218cd8e5117d126a26b131d3e172915311a0ff35f56f10db737b00e9277cc80af02", + "index": 4 + }, + { + "pubkey": "0xad5a6c64e66607145d00ad31baee5d4614f86317a4857d00fed3bf437dea015183d7ee04caa0920a19542626568fb14e3fb4f15e", + "index": 5 + }, + { + "pubkey": "0xcc5a81072e36a40fe2c46d5215feef6a2c08930ee26ff70f8a9f5e5946caeb23cf12912ab09e0f41d9257e0b7520e66ff400e61e", + "index": 6 + }, + { + "pubkey": "0xd33f30792f27d33ed14f437aca83ce337a329971503ef957c3a162526e9c952abf5fd330dfbcae21e949622be072093d54fd4768", + "index": 7 + }, + { + "pubkey": "0x778ade5662bd7f5669e7cc413d94b64f00b3915fdd0d151329e63d2c86e4f12637609d57b85dd34deee1e961aed1c459d0ce6124", + "index": 8 + }, + { + "pubkey": "0x9b726d0adac48d0cff74b33549299d2340026938e4bd077a13c6653d973274499d1b2b160ea29a7130fa43202925203980a6d026", + "index": 9 + }, + { + "pubkey": "0xcdd3573782b73a323c7c713f5a6da8218cc8a5570f7a036b66072b7c18aff60dfe23e406aa6a8e2c5ef12076f22e412de98c0b0c", + "index": 10 + }, + { + "pubkey": "0xea6b4f1e1d42ea2465f84231317bf73052642a4ff714035279fab0043157f807ef39e05dd735490bb3e79a797a24373cf3f6fa36", + "index": 11 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xf3bccde16bb93c17c8a9599235f45dbb3794ada9b4d62683342436b32a865d00", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xeae1d3f173435c3da848a1e541d62502df22b65c0c3020032df56724a3942f3f", + "stateRoot": "0xf359b6fbc9ddf247bb05d1b65bdb0b3ceb04f09165dd01c14f44c3a554aa25ce", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "slot": 1 + }, + "target": { + "root": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "slot": 1 + }, + "source": { + "root": "0xeae1d3f173435c3da848a1e541d62502df22b65c0c3020032df56724a3942f3f", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0x9f8622857da241c65fb22bca9c59f62aed07ade62ceb3336ba96d496f2504dfa", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "stateRoot": "0xaec7f3600636adce21028f4f7d021c686c945c0f1af92b2373565780225c5b1a", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0x9f8622857da241c65fb22bca9c59f62aed07ade62ceb3336ba96d496f2504dfa", + "slot": 2 + }, + "target": { + "root": "0x9f8622857da241c65fb22bca9c59f62aed07ade62ceb3336ba96d496f2504dfa", + "slot": 2 + }, + "source": { + "root": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x56424f75840ae028d4cc601f13d7665af0209c441eafc8c7ec3da5c1f70cb7ed", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0x9f8622857da241c65fb22bca9c59f62aed07ade62ceb3336ba96d496f2504dfa", + "stateRoot": "0x94bbf6330a20778e43821d40144501cf7bc6af41dd923a722e6aab012ca05398", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x56424f75840ae028d4cc601f13d7665af0209c441eafc8c7ec3da5c1f70cb7ed", + "slot": 3 + }, + "target": { + "root": "0x56424f75840ae028d4cc601f13d7665af0209c441eafc8c7ec3da5c1f70cb7ed", + "slot": 3 + }, + "source": { + "root": "0x9f8622857da241c65fb22bca9c59f62aed07ade62ceb3336ba96d496f2504dfa", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0xa5f4610cd5f9d870d17751eb647cf8eb3d769fb8931beee6dcf5de1d4e11bc71", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 4, + "parentRoot": "0x56424f75840ae028d4cc601f13d7665af0209c441eafc8c7ec3da5c1f70cb7ed", + "stateRoot": "0xf22555d40caebd5596aa5c3c694ddf7e270169159343595ea017fe443d60c3ce", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 4, + "data": { + "slot": 4, + "head": { + "root": "0xa5f4610cd5f9d870d17751eb647cf8eb3d769fb8931beee6dcf5de1d4e11bc71", + "slot": 4 + }, + "target": { + "root": "0xa5f4610cd5f9d870d17751eb647cf8eb3d769fb8931beee6dcf5de1d4e11bc71", + "slot": 4 + }, + "source": { + "root": "0x56424f75840ae028d4cc601f13d7665af0209c441eafc8c7ec3da5c1f70cb7ed", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "headRoot": "0xf0b79ee21fde8731c7eed5c9b129c6a5cbf1fac554334b2acdca957e521ed75d", + "headRootLabel": "fork_a_5" + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 5, + "parentRoot": "0xa5f4610cd5f9d870d17751eb647cf8eb3d769fb8931beee6dcf5de1d4e11bc71", + "stateRoot": "0x6a0c73566ff3349a711438c1415a01c26bc6d099b7f9e14b6f4d2f90de315c79", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 5, + "data": { + "slot": 5, + "head": { + "root": "0xf0b79ee21fde8731c7eed5c9b129c6a5cbf1fac554334b2acdca957e521ed75d", + "slot": 5 + }, + "target": { + "root": "0xf0b79ee21fde8731c7eed5c9b129c6a5cbf1fac554334b2acdca957e521ed75d", + "slot": 5 + }, + "source": { + "root": "0xa5f4610cd5f9d870d17751eb647cf8eb3d769fb8931beee6dcf5de1d4e11bc71", + "slot": 4 + } + } + }, + "blockRootLabel": "fork_a_5" + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "headRoot": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "headRootLabel": "fork_a_6" + }, + "stepType": "block", + "block": { + "block": { + "slot": 6, + "proposerIndex": 6, + "parentRoot": "0xf0b79ee21fde8731c7eed5c9b129c6a5cbf1fac554334b2acdca957e521ed75d", + "stateRoot": "0xaa9237b9aa4d942e027a6f66505b45a154c83a2a7c971d1ec9483ebe457022f6", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 6, + "data": { + "slot": 6, + "head": { + "root": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "slot": 6 + }, + "target": { + "root": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "slot": 6 + }, + "source": { + "root": "0xf0b79ee21fde8731c7eed5c9b129c6a5cbf1fac554334b2acdca957e521ed75d", + "slot": 5 + } + } + }, + "blockRootLabel": "fork_a_6" + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "headRoot": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "headRootLabel": "fork_a_6" + }, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 7, + "parentRoot": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "stateRoot": "0xdecb3c9de3afaa20b994cf38cf5262304fc674a7e6e5b4a12e4e2f1f07db7e9b", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 7, + "data": { + "slot": 7, + "head": { + "root": "0x2559d79768469979da9cad2fdaeba8d799729a67285f22c6e87194cb937a758c", + "slot": 7 + }, + "target": { + "root": "0x2559d79768469979da9cad2fdaeba8d799729a67285f22c6e87194cb937a758c", + "slot": 7 + }, + "source": { + "root": "0xc4365f0e7cb693afe37f818b002e354ffca3665027592e3c3b10e05500b23bf6", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "headRoot": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "headRootLabel": "fork_a_6" + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 8, + "parentRoot": "0x2559d79768469979da9cad2fdaeba8d799729a67285f22c6e87194cb937a758c", + "stateRoot": "0xd873e7f161da29b6731f537eeedb4304cdf9d2eb344fe321347d12d1efe50b05", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 8, + "data": { + "slot": 8, + "head": { + "root": "0x7d27bca26ae9a4be3066d371cfc7320293566d0aa8a708608aa665e07a63562d", + "slot": 8 + }, + "target": { + "root": "0x7d27bca26ae9a4be3066d371cfc7320293566d0aa8a708608aa665e07a63562d", + "slot": 8 + }, + "source": { + "root": "0x2559d79768469979da9cad2fdaeba8d799729a67285f22c6e87194cb937a758c", + "slot": 7 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 6, + "headRoot": "0x233d99e5dca9d3d79ad3453edcf5d9ecc6a8d0eb42971403e50f3ba7a55d5f05", + "headRootLabel": "fork_a_6" + }, + "stepType": "block", + "block": { + "block": { + "slot": 9, + "proposerIndex": 9, + "parentRoot": "0x7d27bca26ae9a4be3066d371cfc7320293566d0aa8a708608aa665e07a63562d", + "stateRoot": "0xa69ff4615f26a39cb4ccafd8520eed5da01c5fcfff76d1d0bacc7c81f5f0ff89", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 9, + "data": { + "slot": 9, + "head": { + "root": "0xde4cf11da00d8308e1599f3f6d0e1da3da6bb36fc169b6918773c1e5802bdcc2", + "slot": 9 + }, + "target": { + "root": "0xde4cf11da00d8308e1599f3f6d0e1da3da6bb36fc169b6918773c1e5802bdcc2", + "slot": 9 + }, + "source": { + "root": "0x7d27bca26ae9a4be3066d371cfc7320293566d0aa8a708608aa665e07a63562d", + "slot": 8 + } + } + }, + "blockRootLabel": "fork_b_4" + } + } + ], + "maxSlot": 9, + "_info": { + "hash": "0xfdab73eab7cc7a62be14d12b590fc4c722861b62dd537c74ce9ad0d211845e35", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_prevention_heavy_fork_resists_light_competition[fork_Devnet]", + "description": "Established heavy fork successfully resists light competing fork.\n\nScenario\n--------\n- Fork A builds substantial lead (5 blocks)\n- Fork B created late, builds 3 blocks\n- Fork A maintains head despite fork B's growth\n\nChain Evolution:\n Slots 1-5: Fork A builds uncontested (5 blocks)\n Slot 6: Fork B starts from slot 1 (late competitor)\n Slots 6-8: Fork B builds 3 blocks (total 3 vs fork A's 5)\n Result: Fork A remains canonical (reorg prevented)\n\nExpected Behavior\n-----------------\n1. Fork A establishes 5-block lead\n2. Fork B starts competing from an earlier slot\n3. Fork B builds rapidly but can't match fork A's depth\n4. Head remains on fork A throughout (no reorg)\n\nWhy This Matters\n----------------\nReorg resistance is crucial for chain stability:\n- Prevents cheap disruption of established chain\n- Requires substantial work to overtake canonical fork\n- Protects against late-arriving competing forks\n- Ensures finality can eventually be reached\n\nAttack Prevention:\n- Attacker can't easily reorg established blocks\n- Must match or exceed weight of canonical chain\n- Time advantage gives canonical chain strong position\n- Network naturally converges on heaviest fork", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_with_slot_gaps.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_with_slot_gaps.json new file mode 100644 index 00000000..4b05a0bd --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_reorg_with_slot_gaps.json @@ -0,0 +1,359 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_with_slot_gaps[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + }, + { + "pubkey": "0x4251390932051e208b39ea62194e02085ed11218cd8e5117d126a26b131d3e172915311a0ff35f56f10db737b00e9277cc80af02", + "index": 4 + }, + { + "pubkey": "0xad5a6c64e66607145d00ad31baee5d4614f86317a4857d00fed3bf437dea015183d7ee04caa0920a19542626568fb14e3fb4f15e", + "index": 5 + }, + { + "pubkey": "0xcc5a81072e36a40fe2c46d5215feef6a2c08930ee26ff70f8a9f5e5946caeb23cf12912ab09e0f41d9257e0b7520e66ff400e61e", + "index": 6 + }, + { + "pubkey": "0xd33f30792f27d33ed14f437aca83ce337a329971503ef957c3a162526e9c952abf5fd330dfbcae21e949622be072093d54fd4768", + "index": 7 + }, + { + "pubkey": "0x778ade5662bd7f5669e7cc413d94b64f00b3915fdd0d151329e63d2c86e4f12637609d57b85dd34deee1e961aed1c459d0ce6124", + "index": 8 + }, + { + "pubkey": "0x9b726d0adac48d0cff74b33549299d2340026938e4bd077a13c6653d973274499d1b2b160ea29a7130fa43202925203980a6d026", + "index": 9 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x46d7b41aace1ad653c68369e06dd07851bf573b9a71eed73fceefaea419f57ff", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xab263f65af69956639d73a2eb70a02b3ea1ea6551f7b6697a1503a5fe090033e", + "stateRoot": "0xc9c7615654817e1f886b43ac4924c2dd7ef45cbdeddee3582f3ebfeb97886fb9", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "slot": 1 + }, + "target": { + "root": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "slot": 1 + }, + "source": { + "root": "0xab263f65af69956639d73a2eb70a02b3ea1ea6551f7b6697a1503a5fe090033e", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "stateRoot": "0xe965e7ea6bb63b1797b3c942859ee2f9c3e1bed26e1f7731265a685c850abfb2", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "slot": 3 + }, + "target": { + "root": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "slot": 3 + }, + "source": { + "root": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 4, + "parentRoot": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "stateRoot": "0x2d1c578dc303c5d2e7fa5a2d7211b634a7e33e7b253ff561a58f52be6ddbda12", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 4, + "data": { + "slot": 4, + "head": { + "root": "0x4b4180dc099f2905ea46ed4d59da130c6e8e1e2dc6109bb3aa33462c4aabd83d", + "slot": 4 + }, + "target": { + "root": "0x4b4180dc099f2905ea46ed4d59da130c6e8e1e2dc6109bb3aa33462c4aabd83d", + "slot": 4 + }, + "source": { + "root": "0x381f3e4d89e440e6a9f2c14d20d3eb5a9199cda6d3d585694cfaf6cba7684019", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_4" + } + }, + { + "valid": true, + "stepType": "block", + "block": { + "block": { + "slot": 7, + "proposerIndex": 7, + "parentRoot": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "stateRoot": "0x7fbf1aebfc95f3dc52f5a62b680cf361e28045459b10055a7a67074fc4613db3", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 7, + "data": { + "slot": 7, + "head": { + "root": "0x4b7a6c1ec50419385a7481bc77cc0e1456f488d5e34365fc4a277fea2649ccfc", + "slot": 7 + }, + "target": { + "root": "0x4b7a6c1ec50419385a7481bc77cc0e1456f488d5e34365fc4a277fea2649ccfc", + "slot": 7 + }, + "source": { + "root": "0x8e9a4f0682bd52c96b8b2e40d606abd0686af9490ae9cc7406f8ae8bbf904b4b", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_7" + } + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "headRoot": "0x4b7a6c1ec50419385a7481bc77cc0e1456f488d5e34365fc4a277fea2649ccfc", + "headRootLabel": "fork_a_7" + }, + "stepType": "tick", + "time": 31 + }, + { + "valid": true, + "checks": { + "headSlot": 7, + "headRoot": "0x4b7a6c1ec50419385a7481bc77cc0e1456f488d5e34365fc4a277fea2649ccfc", + "headRootLabel": "fork_a_7" + }, + "stepType": "block", + "block": { + "block": { + "slot": 8, + "proposerIndex": 8, + "parentRoot": "0x4b4180dc099f2905ea46ed4d59da130c6e8e1e2dc6109bb3aa33462c4aabd83d", + "stateRoot": "0x5599f9cdd6ab24c20c4d2a568b0cc60ae3f2831ed610463896775d16fb043596", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 8, + "data": { + "slot": 8, + "head": { + "root": "0x248f6b936f84103bfdf9f0410e73dc89132b1535fa7296267c65feb23274b324", + "slot": 8 + }, + "target": { + "root": "0x248f6b936f84103bfdf9f0410e73dc89132b1535fa7296267c65feb23274b324", + "slot": 8 + }, + "source": { + "root": "0x4b4180dc099f2905ea46ed4d59da130c6e8e1e2dc6109bb3aa33462c4aabd83d", + "slot": 4 + } + } + }, + "blockRootLabel": "fork_b_8" + } + }, + { + "valid": true, + "stepType": "block", + "block": { + "block": { + "slot": 9, + "proposerIndex": 9, + "parentRoot": "0x248f6b936f84103bfdf9f0410e73dc89132b1535fa7296267c65feb23274b324", + "stateRoot": "0x3f1fe5cf089bf817f2755d3f8911a16eb8ef81e94eefa438f868ec7023778ccc", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 9, + "data": { + "slot": 9, + "head": { + "root": "0x806e151305773b14b549139583303a30c5420bbcc1aa866c543fd7ca124c4947", + "slot": 9 + }, + "target": { + "root": "0x806e151305773b14b549139583303a30c5420bbcc1aa866c543fd7ca124c4947", + "slot": 9 + }, + "source": { + "root": "0x248f6b936f84103bfdf9f0410e73dc89132b1535fa7296267c65feb23274b324", + "slot": 8 + } + } + }, + "blockRootLabel": "fork_b_9" + } + }, + { + "valid": true, + "checks": { + "headSlot": 9, + "headRoot": "0x806e151305773b14b549139583303a30c5420bbcc1aa866c543fd7ca124c4947", + "headRootLabel": "fork_b_9" + }, + "stepType": "tick", + "time": 39 + } + ], + "maxSlot": 9, + "_info": { + "hash": "0xa40c0990a00f15ab47144ab0f6dc17eeda30a44fc714355f613accb44b294221", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_reorg_with_slot_gaps[fork_Devnet]", + "description": "Reorg occurs correctly even with missed slots in the chain.\n\nScenario\n--------\n- Slot 1: Base\n- Slot 3: Fork A (skipping slot 2)\n- Slot 4: Fork B (competing)\n- Slot 7: Fork A extended (skipping slots 4-6)\n- Slot 8: Fork B extended (skipping slots 5-7)\n- Slot 9: Fork B extended again \u2192 triggers reorg\n\nMissed Slots: 2, 5, 6 (no blocks produced)\n\nExpected Behavior\n-----------------\n1. Sparse block production doesn't affect fork choice logic\n2. Weight calculation only considers actual blocks\n3. Reorg happens based on block count, not slot numbers\n4. Fork B with 3 blocks beats fork A with 2 blocks\n\nReorg Details:\n - **Depth**: 2 blocks (fork_a slots 3, 7)\n - **Trigger**: Progressive building despite gaps\n - **Weight**: 3 proposer attestations vs 2\n\nWhy This Matters\n----------------\nMissed slots are extremely common in production:\n- Offline validators (expected ~1% downtime)\n- Network issues preventing timely block propagation\n- Intentional skips during network congestion\n\nFork choice must remain robust with sparse block production:\n- Gaps don't create bias toward any fork\n- Only actual blocks contribute weight\n- Reorg logic works identically whether slots are consecutive or sparse\n\nThis test ensures the algorithm works correctly in realistic network\nconditions where perfect block production is impossible.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_simple_one_block_reorg.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_simple_one_block_reorg.json new file mode 100644 index 00000000..a6a85448 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_simple_one_block_reorg.json @@ -0,0 +1,243 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_simple_one_block_reorg[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "chain_base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "chain_base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_b_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + } + ], + "maxSlot": 3, + "_info": { + "hash": "0x8d42eca65d7375978f3ad3d72d68984ac62d73821f94cf4608e54c5744ff5643", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_simple_one_block_reorg[fork_Devnet]", + "description": "Simplest reorg: one-block fork overtakes another via extension.\n\nScenario\n--------\n- Slot 1: Common ancestor (chain_base)\n- Slot 2: Fork A created, becomes head\n- Slot 2: Fork B created (competing fork at same slot)\n- Slot 3: Fork B extended \u2192 triggers reorg from A to B\n\nExpected Behavior\n-----------------\n1. After fork_a_2: head = fork_a_2 (first fork created)\n2. After fork_b_2: head = fork_a_2 (equal weight, head remains unchanged)\n3. After fork_b_3: head = fork_b_3 (fork B heavier due to extension)\n\nReorg Details:\n - **Depth**: 1 block (fork_a_2 becomes non-canonical)\n - **Trigger**: Fork extension (proposer attestation)\n - **Weight advantage**: Fork B has 2 proposer attestations vs 1\n\nWhy This Matters\n----------------\nThis is the most common reorg scenario in practice:\n- Two blocks proposed at nearly the same time\n- Network temporarily splits (half see A first, half see B first)\n- Next proposer builds on one fork, resolving the split\n- Fork choice converges to the extended fork\n\nTests the fundamental property: extending a fork makes it heavier.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_block_deep_reorg.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_block_deep_reorg.json new file mode 100644 index 00000000..3720e42a --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_block_deep_reorg.json @@ -0,0 +1,407 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_three_block_deep_reorg[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_a_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_a_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_b_4" + } + }, + { + "valid": true, + "checks": { + "headSlot": 5, + "headRoot": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "headRootLabel": "fork_b_5" + }, + "stepType": "block", + "block": { + "block": { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "stateRoot": "0xbe35c27ff4f7e0a5a2cb21d6760815985b114e04310e9c08a93ecdb4a6c87d47", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 5, + "head": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "target": { + "root": "0x7888b0a44c5e6cf03a7a25c950ac7a0d37f51b58c971bc158cbc3e3924801ad7", + "slot": 5 + }, + "source": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + } + } + }, + "blockRootLabel": "fork_b_5" + } + } + ], + "maxSlot": 5, + "_info": { + "hash": "0x1d97465ff632fe145308cc77f53aa6eb5f0c9ffaf24c09e4031961ce38042447", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_three_block_deep_reorg[fork_Devnet]", + "description": "Deep three-block reorg from established fork to alternative.\n\nScenario\n--------\n- Slot 1: Common base\n- Slots 2-4: Fork A builds 3-block lead\n- Slots 2-5: Fork B slowly builds, then surpasses with 4 blocks\n\nTimeline:\n Slot 2: Fork A leads (1 vs 0)\n Slot 3: Fork A leads (2 vs 1)\n Slot 4: Fork A leads (3 vs 2)\n Slot 5: Fork B overtakes (4 vs 3) \u2192 3-block deep reorg\n\nExpected Behavior\n-----------------\n1. Fork A establishes 3-block canonical chain (slots 2-4)\n2. Fork B steadily builds parallel chain\n3. At slot 5, fork B has 4 blocks vs fork A's 3 blocks\n4. Fork choice switches to fork B\n5. Three blocks (fork_a slots 2-4) become non-canonical\n\nReorg Details:\n - **Depth**: 3 blocks (deepest in this test suite)\n - **Trigger**: Alternative fork becomes longer\n - **Weight advantage**: 4 proposer attestations vs 3\n\nWhy This Matters\n----------------\nDeep reorgs (3+ blocks) are rare in healthy networks but can happen:\n- Network partitions lasting multiple slots\n- Coordinated validator behavior (intentional or accidental)\n- Major network latency events\n\nProperties verified:\n- Fork choice correctly switches even after multiple canonical blocks\n- Weight calculation works correctly over extended depth\n- No \"stickiness\" bias toward existing head\n- Objective heaviest fork always wins\n\nThis tests the protocol's ability to recover from significant disagreement\nabout chain history, ensuring safety and liveness even in adversarial scenarios.", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_way_fork_competition.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_way_fork_competition.json new file mode 100644 index 00000000..426c264e --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_three_way_fork_competition.json @@ -0,0 +1,366 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_three_way_fork_competition[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_c_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_c_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_c_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_c_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_b_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_b_4" + } + } + ], + "maxSlot": 4, + "_info": { + "hash": "0x43b577b461bc06da1f55e2a6a83678c66c06399c8267eff25f5cbe6075f61a78", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_three_way_fork_competition[fork_Devnet]", + "description": "Three competing forks with progressive elimination until one wins.\n\nScenario\n--------\nThree forks (A, B, C) compete simultaneously. Fork choice progressively\neliminates weaker forks as stronger ones extend.\n\nFork Topology:\n base (slot 1)\n / | / | fork_a fork_b fork_c (slot 2)\n | | |\n | | +--- fork_c_3 (slot 3)\n | +--- fork_b_3 (slot 3)\n | +--- fork_b_4 (slot 4) \u2190 Winner\n +--- abandoned\n\nExpected Behavior\n-----------------\n1. All three forks start at slot 2 (three-way tie)\n2. Fork C extends to slot 3 \u2192 becomes head\n3. Fork B extends to slot 3 \u2192 ties with fork C at depth 2\n4. Fork B extends to slot 4 \u2192 wins with depth 3\n5. Forks A and C become non-canonical\n\nReorg Sequence:\n - Initial: fork_a (tie-breaker among three)\n - After fork_c_3: fork_c (depth advantage)\n - After fork_b_3: fork_c (tie, maintains head)\n - After fork_b_4: fork_b (final winner)\n\nWhy This Matters\n----------------\nMulti-fork scenarios can occur during:\n- Network partitions splitting validators 3+ ways\n- Rapid block production creating multiple conflicting proposals\n- Byzantine validators intentionally creating competing forks\n\nProperties verified:\n- Fork choice handles 3+ simultaneous competing forks\n- Head selection remains consistent and deterministic\n- Progressive elimination works correctly\n- Final winner is objectively the heaviest fork", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_two_block_reorg_progressive_building.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_two_block_reorg_progressive_building.json new file mode 100644 index 00000000..f9c01049 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_fork_choice_reorgs/test_two_block_reorg_progressive_building.json @@ -0,0 +1,325 @@ +{ + "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_two_block_reorg_progressive_building[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 4, + "headRoot": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "headRootLabel": "fork_b_4" + }, + "stepType": "block", + "block": { + "block": { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "stateRoot": "0x6991fe4776a3a756d96035af09d0329aa69de036b81a78a5f8e845a1d699674c", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 0, + "data": { + "slot": 4, + "head": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "target": { + "root": "0x43e759608e4063a4e6f57646d97a1dfaf246d33762b2a306be81d9c7a4155816", + "slot": 4 + }, + "source": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + } + } + }, + "blockRootLabel": "fork_b_4" + } + } + ], + "maxSlot": 4, + "_info": { + "hash": "0x116f8796a0fc85768372c158c0eda23a02909e431dd48e2ae0f558f47109736e", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_fork_choice_reorgs.py::test_two_block_reorg_progressive_building[fork_Devnet]", + "description": "Two-block reorg via progressive fork building.\n\nScenario\n--------\n- Slot 1: Common ancestor\n- Slots 2-3: Fork A extends to 2 blocks ahead\n- Slots 2-4: Fork B slowly catches up, then overtakes\n\nChain State Evolution:\n Slot 1: base\n Slot 2: base \u2190 fork_a_2 (head)\n base \u2190 fork_b_2\n Slot 3: base \u2190 fork_a_2 \u2190 fork_a_3 (head)\n base \u2190 fork_b_2\n Slot 4: base \u2190 fork_a_2 \u2190 fork_a_3 (was head)\n base \u2190 fork_b_2 \u2190 fork_b_3 (tie at depth 2)\n Slot 5: base \u2190 fork_a_2 \u2190 fork_a_3 (abandoned)\n base \u2190 fork_b_2 \u2190 fork_b_3 \u2190 fork_b_4 (head - REORG!)\n\nExpected Behavior\n-----------------\n1. Fork A leads for slots 2-3 (2 blocks ahead)\n2. Fork B catches up at slot 4 (both at depth 2)\n3. Fork B overtakes at slot 5 (3 blocks vs 2)\n4. Two-block reorg: fork_a_2 and fork_a_3 become non-canonical\n\nReorg Details:\n - **Depth**: 2 blocks\n - **Trigger**: Progressive building on alternative fork\n - **Weight advantage**: Fork B has 3 proposer attestations vs 2\n\nWhy This Matters\n----------------\nDemonstrates that an initially leading fork can be overtaken if:\n- Proposers switch to building on the alternative fork\n- The alternative fork accumulates more blocks over time\n- Network temporarily favored one fork but consensus shifted", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_lexicographic_tiebreaker/test_equal_weight_forks_use_lexicographic_tiebreaker.json b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_lexicographic_tiebreaker/test_equal_weight_forks_use_lexicographic_tiebreaker.json new file mode 100644 index 00000000..afcaf00b --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/fork_choice/devnet/fc/test_lexicographic_tiebreaker/test_equal_weight_forks_use_lexicographic_tiebreaker.json @@ -0,0 +1,286 @@ +{ + "tests/consensus/devnet/fc/test_lexicographic_tiebreaker.py::test_equal_weight_forks_use_lexicographic_tiebreaker[fork_Devnet][fork_devnet-fork_choice_test]": { + "network": "Devnet", + "anchorState": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x52a0b128a2c37f2a6a3c90587a4e1f79f2787972c8215e3e604c2c6cb907464867aefa03401c8c10b318ac7d34326a7cb824e800", + "index": 0 + }, + { + "pubkey": "0x1e412e3c4b980d1816027c301b496e73d67bfc7b4b18130229cc2e75b9056031793fb63df88104467cfe3f19f8b9227a5068654f", + "index": 1 + }, + { + "pubkey": "0x081d204ef8d439786dd68231a79c2a4e41b837128477f5356293077b9b85ab4cb28d5d0dd7df644a43cb0631748d076a9049006d", + "index": 2 + }, + { + "pubkey": "0x209e8c1cb34889756bdd045c5b57190b664f8e79a89b043b31e2c32f52648443ece75c4dcfd39251844deb1d1bf5f52a8dc60c4e", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "anchorBlock": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0xbc9b2d86697f4a1b1c4968f020285912717ec43eb1c00f05e93bb9c51ee9df25", + "body": { + "attestations": { + "data": [] + } + } + }, + "steps": [ + { + "valid": true, + "checks": { + "headSlot": 1, + "headRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "headRootLabel": "base" + }, + "stepType": "block", + "block": { + "block": { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "stateRoot": "0xd56a97e2c5d0622ddfa2e3701e053bae5c77811a32d83e00d90ebb12d6fe9507", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 1, + "data": { + "slot": 1, + "head": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "target": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + }, + "source": { + "root": "0x52ebe8b6d8a416928e3145bb7031deb974d991aeb97b0f427c345046d8e45b22", + "slot": 0 + } + } + }, + "blockRootLabel": "base" + } + }, + { + "valid": true, + "checks": { + "headSlot": 2, + "headRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "headRootLabel": "fork_a_2" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_a_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_a_3" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "headRoot": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "headRootLabel": "fork_a_3" + }, + "stepType": "block", + "block": { + "block": { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "stateRoot": "0xf0d53f86ba36f03189f8b7e69a6ed370f6b3a674f6c4c709c0b94314b8c31b3d", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 2, + "data": { + "slot": 2, + "head": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "target": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + }, + "source": { + "root": "0x98bd6e07acd1b58443246f6685da123f6263546f47af185637db4b488eec9302", + "slot": 1 + } + } + }, + "blockRootLabel": "fork_b_2" + } + }, + { + "valid": true, + "checks": { + "headSlot": 3, + "lexicographicHeadAmong": [ + "fork_a_3", + "fork_b_3" + ] + }, + "stepType": "block", + "block": { + "block": { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "stateRoot": "0x1ecff71b91f823263c790685da835d50f81d4ee41391b0b0944b5fcf0cffa07f", + "body": { + "attestations": { + "data": [] + } + } + }, + "proposerAttestation": { + "validatorId": 3, + "data": { + "slot": 3, + "head": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "target": { + "root": "0x4573e8f28a03352db68476fd5901330d9fd63aee58d7fd282eb9645440b1e8cf", + "slot": 3 + }, + "source": { + "root": "0xa8405e710d350250aad48257572cc6675a70f6b8b91a5f4138b353d422f47151", + "slot": 2 + } + } + }, + "blockRootLabel": "fork_b_3" + } + } + ], + "maxSlot": 3, + "_info": { + "hash": "0xa04b884ed74d63997de3fad0533a059bfc41b2558f28f678ed35eafaeac1b7ea", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/fc/test_lexicographic_tiebreaker.py::test_equal_weight_forks_use_lexicographic_tiebreaker[fork_Devnet]", + "description": "Fork choice selects lexicographically highest branch when fork weights tie.\n\nScenario\n--------\n- Slot 1: Build common ancestor\n- Slots 2-3: Build fork A to depth 2 (slots 2 & 3)\n- Slots 2-3: Build fork B to depth 2 (slots 2 & 3)\n\nBoth forks have identical structure:\n- Same depth (2 blocks each)\n- Same attestation weight (2 proposer attestations each)\n- Same parent (common ancestor at slot 1)\n\nExpected Behavior\n-----------------\nThe competing forks have identical attestation weight. The head is chosen\nvia lexicographic ordering of the block roots. The framework automatically\nverifies that:\n1. Both forks are at the same slot (equal depth)\n2. The head is the lexicographically highest root among them", + "fixtureFormat": "fork_choice_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_at_large_slot_number.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_at_large_slot_number.json new file mode 100644 index 00000000..a5d51b97 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_at_large_slot_number.json @@ -0,0 +1,81 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_at_large_slot_number[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 100, + "proposerIndex": 0, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xdaf207f3a7508c9a7cd9c8465c96f39574f7a260eeb6d1e523d2a244b6313a77", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 100 + }, + "_info": { + "hash": "0x7f660383e3aaa4604e1e2d7c392dfb766a45628ca9bcf58c88242546763d7a21", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_at_large_slot_number[fork_Devnet]", + "description": "Test block processing at high slot numbers.\n\nScenario\n--------\nJump directly from genesis to slot 100, simulating:\n- Network bootstrap after long downtime\n- Test environment with artificial time jump\n- Integer overflow boundary testing\n\nExpected Behavior\n-----------------\n1. Process 99 empty slots: 1\u21922\u2192...\u219299\u2192100\n2. Block at slot 100 processes correctly\n3. No integer overflow or wraparound\n4. State remains consistent", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_extends_deep_chain.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_extends_deep_chain.json new file mode 100644 index 00000000..9a698df6 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_extends_deep_chain.json @@ -0,0 +1,290 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_extends_deep_chain[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x969f9416fab6113291a285e265854c54f0dbfbf89d2402c3cf34342377029f1c", + "stateRoot": "0xa30f6c0a36b46929450b745c2916208ec2e8ed22982fcc86aea114bb84d883b1", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xd573536cd15625d5937e6280bb8f0c11586b54f70eabaa0eae73a727415fdca6", + "stateRoot": "0xf06bbd06313dbc38a469e92affa6f86295977fa168599e95a658de410724e018", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x124026a2e6205c8c225a7bbac822f8233e658a995254caee597d58f37dff3b06", + "stateRoot": "0x77bea35f01fb6de6602fd894b007b7a7f7a127033a053d2bff1cfa11bfe6bf99", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x08ea682f61849068c040fa42c55931a053e59a37e7e422ebededbcd1617dbc0c", + "stateRoot": "0x7b2fd7cdd7311dcff7c07fe4d0bc7d657c446b87a5f7102beefcdc11828db5aa", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0xe6ddae6bd83aae8173e0015bb6276a957c20f3eccbddc4c0d786bce6b116d3ee", + "stateRoot": "0xf61cb7509e3b42d6607a5902b12a24d87f850f9f2598c84f9f8be635e36f6761", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 7, + "proposerIndex": 3, + "parentRoot": "0xc433a6f15cdc8a5661360512842193f894b4ffd2add5e4077e10a6a4d75701a8", + "stateRoot": "0x402484306564c45507edd99aa84008a89fa945444af30e3140e9883a50d7c07b", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0xfe885a6e4805e18da0b0f556e48d1168a50202fcf7feb26b2e36b63fe471aedb", + "stateRoot": "0x115d432fcb3c22c3decca8179c271b3ed03b2edfa1d17a4cf1c0410fca331b06", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 9, + "proposerIndex": 1, + "parentRoot": "0x7b5d955659b1cfa0f36bb7812934766b3371c1d860247300d78d65476213a61b", + "stateRoot": "0x75ebcc4af807c4fa1de8e9906c0775094ca4b85cdc50715aeaee9225dcb1777d", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 10, + "proposerIndex": 2, + "parentRoot": "0xea9bb89244562ced80f3c282c3e1712769134694775d2a0b0bec0621b7796418", + "stateRoot": "0x7f632729311615c809496e5cdf804bafb0f7f1fae6694d2f2b9f1f2003b4b49f", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 11, + "proposerIndex": 3, + "parentRoot": "0x0ff4a6408efb3ff54a97813c732a62c5730595c4b98255d80ad69c66d67e810f", + "stateRoot": "0xda5cb4c67bd3d7d68ad03b73b053191373f177a4705adae0029320cb326941d0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 12, + "proposerIndex": 0, + "parentRoot": "0xbbdb69261d01c57e711345ad842284ea77e17dda9ff7171ad8761d8f48a9813c", + "stateRoot": "0xc0e3488f15ff51025dfbab17fd0219a9d773d479d9e4d00c4533a94d6a8df70d", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 13, + "proposerIndex": 1, + "parentRoot": "0x8eb24a430333568736d93aff04a4d510df8a70aecea532a0c022b622719a2124", + "stateRoot": "0x0e3c7e21bc5225ec160f8add3b9659615d3d764c5c5435e3c0ad3d774151ee7e", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 14, + "proposerIndex": 2, + "parentRoot": "0xf7be6c4ead3b044f7265cb6582c22c2048b288d76dd5f2b3c58dac790d2945ee", + "stateRoot": "0x71809a04f50a2031411f4df372401b14e871db81807ad2bcb443e8cdec202ae9", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 15, + "proposerIndex": 3, + "parentRoot": "0xc932964ee6af954a426400bb39b0f30b23a97823c8a1efecab55e78398065c64", + "stateRoot": "0x5bbb0dd30a2e4ce5bc79a0271f9078a4d2d55fdbc3a918d3c20f3f8c77e81874", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 16, + "proposerIndex": 0, + "parentRoot": "0x560d2a3702ceb6df0bf52e097ec0b5b5e3771945cbdddd6d68529290b25dbb7e", + "stateRoot": "0x87076d3899317921b68291e07ee3c2a51658235ab4c0a10beae5634f3ba5b512", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 17, + "proposerIndex": 1, + "parentRoot": "0x7136ff2c60ccd8cb2328adb006bd4191050e4176aaa9a15094a418cec056a6ff", + "stateRoot": "0x0255974dc75eb8caca8ab81917dbc65fbe7b1a64762ee5a1a6a59edfd6708e44", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 18, + "proposerIndex": 2, + "parentRoot": "0x8eefd9e1dad9490393446821a103c7cbcd8e0e79ac634aa22cf1a5255a5eb22f", + "stateRoot": "0xb77e8608be391abba09309e20535ae9185aa6ba0de53acf52cc4a8270be8218f", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 19, + "proposerIndex": 3, + "parentRoot": "0xf57aaa8ea14ca1ed41f76f9dde78549b1b79c76d178feb1f39e312ed43a880a2", + "stateRoot": "0xdb18ac37e594b7e210f6ad8d23542dd6138e09267f6dde19f2f4c428c84de386", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 20, + "proposerIndex": 0, + "parentRoot": "0x6e27d0c642cf77ab84c64269d22e7c46d6a65edaedeba829285ed491d1aa182c", + "stateRoot": "0x014ca3724ed53bebde61d8c72d6e7078433b51eab5130b372a368731b04d08c8", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 20 + }, + "_info": { + "hash": "0xe3c0dd9ff1e2ff3f2d4985cab62c081f4ef0a9c085058801e3421beb99fda348", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_extends_deep_chain[fork_Devnet]", + "description": "Test that blocks can extend already-deep chains.\n\nScenario\n--------\nBuild a 20-block chain to simulate a mature blockchain state,\nthen verify new blocks can still extend it correctly.\n\nExpected Behavior\n-----------------\n1. All 20 blocks process successfully\n2. Parent linkage maintained throughout\n3. State advances to slot 20\n4. Historical roots accumulate correctly\n5. No degradation in processing", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_parent_root.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_parent_root.json new file mode 100644 index 00000000..c6e65373 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_parent_root.json @@ -0,0 +1,79 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_parent_root[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "expectException": "AssertionError", + "_info": { + "hash": "0xc3b740002e57451d2fb76accef1878cdaded9a96f44056a9078478244fa1597f", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_parent_root[fork_Devnet]", + "description": "Test that blocks with wrong parent root are rejected.\n\nScenario\n--------\nAttempt to process a block where parent root doesn't match\nhash_tree_root(state.latest block header).\n\nExpected Behavior\n-----------------\nBlock processing fails with AssertionError: \"Block parent root mismatch\"\n\nWhy This Matters\n----------------\nMaintains chain integrity:\n- Blocks must reference correct parent\n- Prevents chain history forgery\n- Ensures linear chain continuity\n- Critical for fork resolution\n\nWithout this check, attackers could create invalid chain branches.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_proposer.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_proposer.json new file mode 100644 index 00000000..9c2caf8d --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_proposer.json @@ -0,0 +1,79 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_proposer[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 3, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "expectException": "AssertionError", + "_info": { + "hash": "0x403e22a020a1f9bd9277cc6cd8b57249f012a4de202f62a380f33a146a3e1e19", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_proposer[fork_Devnet]", + "description": "Test that blocks from wrong proposer are rejected.\n\nScenario\n--------\nAttempt to process a block where proposer index doesn't match\nthe expected proposer for that slot.\n\nExpected Behavior\n-----------------\nBlock processing fails with AssertionError: \"Incorrect block proposer\"\n\nWhy This Matters\n----------------\nPrevents unauthorized block production:\n- Only designated proposer can produce blocks\n- Prevents validator impersonation\n- Maintains protocol security\n- Essential for consensus integrity\n\nWithout this check, any validator could produce blocks for any slot.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_state_root.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_state_root.json new file mode 100644 index 00000000..b5fd99df --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_block_with_invalid_state_root.json @@ -0,0 +1,79 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_state_root[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaadbaad", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "expectException": "AssertionError", + "_info": { + "hash": "0xe0a9fbbf2cdec436b44ea5987027ecb5f453f1d725287884acb592aee73da28c", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_block_with_invalid_state_root[fork_Devnet]", + "description": "Test that blocks with wrong state root commitment are rejected.\n\nScenario\n--------\nCreate a block with state root that doesn't match the actual\npost-state hash.\n\nExpected Behavior\n-----------------\nBlock processing fails with AssertionError: \"Invalid block state root\"\n\nWhy This Matters\n----------------\nCryptographic state commitment is fundamental:\n- Proves correct state execution\n- Prevents state manipulation\n\nThis is a critical validation - without it, proposers could claim any arbitrary state.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_blocks_with_gaps.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_blocks_with_gaps.json new file mode 100644 index 00000000..b772f619 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_blocks_with_gaps.json @@ -0,0 +1,106 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_blocks_with_gaps[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x969f9416fab6113291a285e265854c54f0dbfbf89d2402c3cf34342377029f1c", + "stateRoot": "0x3445f62fb7b96a18d7ba7a9da2308f98e061b0ad8b60879e6579322dc152dd0c", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 8, + "proposerIndex": 0, + "parentRoot": "0x89ffcc65bd5ddc983d69b54c409b8e7aa71f044cd85f169428302abc54fa06e5", + "stateRoot": "0x602eae20e5e8395fca51c6be7d919d36d3b8917a9b9dcd6523356e54c7f51bae", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 8, + "latestBlockHeaderSlot": 8, + "latestBlockHeaderStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "historicalBlockHashesCount": 8 + }, + "_info": { + "hash": "0x9759a3021dd0fc00ddfcda5ed7300a360bd65add2b18f7e56731be41c1cf7a36", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_blocks_with_gaps[fork_Devnet]", + "description": "Test blocks separated by empty slots.\n\nScenario\n--------\nBuild chain with gaps:\n- Slot 1: Block\n- Slots 2-3: Empty\n- Slot 4: Block\n- Slots 5-7: Empty\n- Slot 8: Block\n\nExpected Behavior\n-----------------\n1. Blocks process at specified slots\n2. Empty slots handled automatically\n3. Parent linkage spans gaps correctly\n4. State advances to slot 8\n\nWhy This Matters\n----------------\nMissed proposals are common:\n- Validators offline\n- Network partitions\n- Missed attestations\n\nThis validates resilience to gaps.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks.json new file mode 100644 index 00000000..a2b5fa4a --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks.json @@ -0,0 +1,138 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_empty_blocks[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x969f9416fab6113291a285e265854c54f0dbfbf89d2402c3cf34342377029f1c", + "stateRoot": "0xa30f6c0a36b46929450b745c2916208ec2e8ed22982fcc86aea114bb84d883b1", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xd573536cd15625d5937e6280bb8f0c11586b54f70eabaa0eae73a727415fdca6", + "stateRoot": "0xf06bbd06313dbc38a469e92affa6f86295977fa168599e95a658de410724e018", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x124026a2e6205c8c225a7bbac822f8233e658a995254caee597d58f37dff3b06", + "stateRoot": "0x77bea35f01fb6de6602fd894b007b7a7f7a127033a053d2bff1cfa11bfe6bf99", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x08ea682f61849068c040fa42c55931a053e59a37e7e422ebededbcd1617dbc0c", + "stateRoot": "0x7b2fd7cdd7311dcff7c07fe4d0bc7d657c446b87a5f7102beefcdc11828db5aa", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0xe6ddae6bd83aae8173e0015bb6276a957c20f3eccbddc4c0d786bce6b116d3ee", + "stateRoot": "0xf61cb7509e3b42d6607a5902b12a24d87f850f9f2598c84f9f8be635e36f6761", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 6, + "latestBlockHeaderSlot": 6, + "historicalBlockHashesCount": 6 + }, + "_info": { + "hash": "0x491609664ae8b091ec7b7dabf1a16d21739f62596fd8ab24389deb720422561a", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_empty_blocks[fork_Devnet]", + "description": "Test processing blocks with empty body (no attestations).\n\nScenario\n--------\nBuild chain of blocks with empty body:\n- Slot 1: Block, Empty body\n- Slot 2: Block, Empty body\n- Slot 3: Block, Empty body\n- Slot 4: Block, Empty body\n- Slot 5: Block, Empty body\n- Slot 6: Block, Empty body\n\nExpected Behavior\n-----------------\n1. Blocks process as expected\n2. State advances to slot 6", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks_with_missed_slots.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks_with_missed_slots.json new file mode 100644 index 00000000..43b5453d --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_empty_blocks_with_missed_slots.json @@ -0,0 +1,127 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_empty_blocks_with_missed_slots[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x969f9416fab6113291a285e265854c54f0dbfbf89d2402c3cf34342377029f1c", + "stateRoot": "0xa30f6c0a36b46929450b745c2916208ec2e8ed22982fcc86aea114bb84d883b1", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xd573536cd15625d5937e6280bb8f0c11586b54f70eabaa0eae73a727415fdca6", + "stateRoot": "0xf06bbd06313dbc38a469e92affa6f86295977fa168599e95a658de410724e018", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x124026a2e6205c8c225a7bbac822f8233e658a995254caee597d58f37dff3b06", + "stateRoot": "0x0b33c0f098841e6287520b7abc2ae47a7f2795ca5040d32bfa168feefd5be1e2", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 6, + "proposerIndex": 2, + "parentRoot": "0x39cfdd44e7c6a6753d8a67b56430071489f8c5387aaefd7c6d2c9c5eda263ee1", + "stateRoot": "0x03bec5fc4ee05f16aff2f49e91e855df0c7d4fec0de4f3a4143cfac8b54d5d74", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 6, + "latestBlockHeaderSlot": 6, + "historicalBlockHashesCount": 6 + }, + "_info": { + "hash": "0x8250f9e096af4d83994294b60d6e1a1c9e6724a0abe7c7cfd1a2c0119f27d113", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_empty_blocks_with_missed_slots[fork_Devnet]", + "description": "Test processing blocks with empty body (no attestations) combined with missed slots.\n\nScenario\n --------\n Build chain of blocks with empty body + missed slot:\n - Slot 1: Block\n - Slot 2: Block, Empty body\n - Slot 3: BLock, Empty body\n - Slot 4: Missed\n - Slot 5: Block, Empty body\n - Slot 6: Block\n\n Expected Behavior\n -----------------\n 1. Blocks process at specified slots\n 2. Empty slots handled automatically\n 3. State advances to slot 6", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_linear_chain_multiple_blocks.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_linear_chain_multiple_blocks.json new file mode 100644 index 00000000..e1e9e904 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_linear_chain_multiple_blocks.json @@ -0,0 +1,125 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_linear_chain_multiple_blocks[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 2, + "proposerIndex": 2, + "parentRoot": "0x969f9416fab6113291a285e265854c54f0dbfbf89d2402c3cf34342377029f1c", + "stateRoot": "0xa30f6c0a36b46929450b745c2916208ec2e8ed22982fcc86aea114bb84d883b1", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 3, + "proposerIndex": 3, + "parentRoot": "0xd573536cd15625d5937e6280bb8f0c11586b54f70eabaa0eae73a727415fdca6", + "stateRoot": "0xf06bbd06313dbc38a469e92affa6f86295977fa168599e95a658de410724e018", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 4, + "proposerIndex": 0, + "parentRoot": "0x124026a2e6205c8c225a7bbac822f8233e658a995254caee597d58f37dff3b06", + "stateRoot": "0x77bea35f01fb6de6602fd894b007b7a7f7a127033a053d2bff1cfa11bfe6bf99", + "body": { + "attestations": { + "data": [] + } + } + }, + { + "slot": 5, + "proposerIndex": 1, + "parentRoot": "0x08ea682f61849068c040fa42c55931a053e59a37e7e422ebededbcd1617dbc0c", + "stateRoot": "0x7b2fd7cdd7311dcff7c07fe4d0bc7d657c446b87a5f7102beefcdc11828db5aa", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 5 + }, + "_info": { + "hash": "0xaab7a78225c1708bf33f5d782b4aea4679b93f84f4aa1a98dc7c75443bb5a326", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_linear_chain_multiple_blocks[fork_Devnet]", + "description": "Test building a linear chain of multiple blocks.\n\nScenario\n--------\nBuild a 5-block linear chain:\ngenesis \u2192 block1 \u2192 block2 \u2192 block3 \u2192 block4 \u2192 block5\n\nExpected Behavior\n-----------------\n1. Each block processes in sequence\n2. Parent linkage maintained throughout\n3. State advances monotonically\n4. Historical roots accumulate\n5. Final state at slot 5", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_process_first_block_after_genesis.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_process_first_block_after_genesis.json new file mode 100644 index 00000000..75922d64 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_block_processing/test_process_first_block_after_genesis.json @@ -0,0 +1,84 @@ +{ + "tests/consensus/devnet/state_transition/test_block_processing.py::test_process_first_block_after_genesis[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [ + { + "slot": 1, + "proposerIndex": 1, + "parentRoot": "0xe3c1f53019f7fac3d402915e5171449ab0f9aa9aa89857e87dcdcc16983781b4", + "stateRoot": "0xfd96931fa716488eefacfc4e4dbb0d0543700084f1724a2244eccab0773639a0", + "body": { + "attestations": { + "data": [] + } + } + } + ], + "post": { + "slot": 1, + "latestBlockHeaderSlot": 1, + "latestBlockHeaderStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "historicalBlockHashesCount": 1 + }, + "_info": { + "hash": "0x5342b4241bcd52b88c06155a36b52cc1218fb475cb2f674af1ca55bb87af9fbe", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_block_processing.py::test_process_first_block_after_genesis[fork_Devnet]", + "description": "Test processing the first block after genesis.\n\nScenario\n--------\nProcess a single block at slot 1 immediately after genesis.\n\nExpected Behavior\n-----------------\n1. State advances from slot 0 to slot 1\n2. Block header is validated and processed\n3. Latest block header updated to new block\n4. Historical roots updated with genesis\n5. Post-state at slot 1\n\nThis is the foundation for all subsequent blocks.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_time.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_time.json new file mode 100644 index 00000000..56d685d9 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_time.json @@ -0,0 +1,92 @@ +{ + "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_custom_time[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 1234567890 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [], + "post": { + "slot": 0, + "latestJustifiedSlot": 0, + "latestJustifiedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestFinalizedSlot": 0, + "latestFinalizedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "validatorCount": 4, + "configGenesisTime": 1234567890, + "latestBlockHeaderSlot": 0, + "latestBlockHeaderProposerIndex": 0, + "latestBlockHeaderParentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderBodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136", + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "_info": { + "hash": "0x876a6dd18a1e99478227976c6149c2f45a4918efbb2650f786d0a1b8b3cd0314", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_custom_time[fork_Devnet]", + "description": "Test genesis state with custom genesis time.\n\nScenario\n--------\nGenerate a genesis state with:\n- genesis_time = 1234567890\n- Default 4 validators\n\nExpected Behavior\n-----------------\nGenesis state should respect the custom genesis time while\nmaintaining all other genesis properties.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_validator_set.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_validator_set.json new file mode 100644 index 00000000..77befed5 --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_custom_validator_set.json @@ -0,0 +1,108 @@ +{ + "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_custom_validator_set[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101", + "index": 1 + }, + { + "pubkey": "0x02020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202", + "index": 2 + }, + { + "pubkey": "0x03030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303", + "index": 3 + }, + { + "pubkey": "0x04040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404", + "index": 4 + }, + { + "pubkey": "0x05050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505", + "index": 5 + }, + { + "pubkey": "0x06060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606", + "index": 6 + }, + { + "pubkey": "0x07070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707", + "index": 7 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [], + "post": { + "slot": 0, + "latestJustifiedSlot": 0, + "latestJustifiedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestFinalizedSlot": 0, + "latestFinalizedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "validatorCount": 8, + "configGenesisTime": 0, + "latestBlockHeaderSlot": 0, + "latestBlockHeaderProposerIndex": 0, + "latestBlockHeaderParentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderBodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136", + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "_info": { + "hash": "0xb6c4400812a4e5c70a7e165fba8cd0cf1d5b8dd38b6602dcc9a29d7351d393ac", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_custom_validator_set[fork_Devnet]", + "description": "Test genesis state with custom validator set.\n\nScenario\n--------\nGenerate a genesis state with:\n- 8 validators instead of default 4\n- Custom validator pubkeys\n\nExpected Behavior\n-----------------\nGenesis state should contain exactly 8 validators while\nmaintaining all other genesis properties.", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_default_configuration.json b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_default_configuration.json new file mode 100644 index 00000000..e4ff5e6a --- /dev/null +++ b/tests/test_vectors/fixtures/consensus/state_transition/devnet/state_transition/test_genesis/test_genesis_default_configuration.json @@ -0,0 +1,92 @@ +{ + "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_default_configuration[fork_Devnet][fork_devnet-state_transition_test]": { + "network": "Devnet", + "pre": { + "config": { + "genesisTime": 0 + }, + "slot": 0, + "latestBlockHeader": { + "slot": 0, + "proposerIndex": 0, + "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136" + }, + "latestJustified": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "latestFinalized": { + "root": "0x0000000000000000000000000000000000000000000000000000000000000000", + "slot": 0 + }, + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "validators": { + "data": [ + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 1 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 2 + }, + { + "pubkey": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "index": 3 + } + ] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "blocks": [], + "post": { + "slot": 0, + "latestJustifiedSlot": 0, + "latestJustifiedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestFinalizedSlot": 0, + "latestFinalizedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "validatorCount": 4, + "configGenesisTime": 0, + "latestBlockHeaderSlot": 0, + "latestBlockHeaderProposerIndex": 0, + "latestBlockHeaderParentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestBlockHeaderBodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136", + "historicalBlockHashes": { + "data": [] + }, + "justifiedSlots": { + "data": [] + }, + "justificationsRoots": { + "data": [] + }, + "justificationsValidators": { + "data": [] + } + }, + "_info": { + "hash": "0x256e9217484ebc59567ca40c327c7d11c7216964c1ecd69987e81d37e8844028", + "comment": "`leanSpec` generated test", + "testId": "tests/consensus/devnet/state_transition/test_genesis.py::test_genesis_default_configuration[fork_Devnet]", + "description": "Test genesis state with default configuration.\n\nScenario\n--------\nGenerate a genesis state with default parameters:\n- genesis_time = 0\n- 4 validators with zero pubkeys", + "fixtureFormat": "state_transition_test" + } + } +} \ No newline at end of file diff --git a/tests/test_vectors/test_vectors_test.cpp b/tests/test_vectors/test_vectors_test.cpp new file mode 100644 index 00000000..8878f417 --- /dev/null +++ b/tests/test_vectors/test_vectors_test.cpp @@ -0,0 +1,242 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include + +#include "blockchain/fork_choice.hpp" +#include "blockchain/state_transition_function.hpp" +#include "mock/app/validator_keys_manifest_mock.hpp" +#include "mock/blockchain/validator_registry_mock.hpp" +#include "mock/clock/manual_clock.hpp" +#include "mock/crypto/xmss_provider_mock.hpp" +#include "mock/metrics_mock.hpp" +#include "serde/json.hpp" +#include "testutil/prepare_loggers.hpp" +#include "types/fork_choice_test_json.hpp" +#include "types/state_transition_test_json.hpp" + +using testing::_; + +#define FIXTURE_INSTANTIATE(test_name, directory) \ + INSTANTIATE_TEST_SUITE_P( \ + Fixture, \ + test_name, \ + testing::ValuesIn([] { \ + std::vector params; \ + auto search_dir = std::filesystem::path{PROJECT_SOURCE_DIR} \ + / "tests/test_vectors/fixtures/consensus" / directory; \ + std::error_code ec; \ + for (auto &item : \ + std::filesystem::recursive_directory_iterator{search_dir, ec}) { \ + auto &json_path = item.path(); \ + if (json_path.extension() != ".json") { \ + continue; \ + } \ + auto json_str = qtils::readText(json_path).value(); \ + std::unordered_map \ + fixtures; \ + lean::json::decode(fixtures, json_str); \ + for (auto &[name, fixture] : fixtures) { \ + params.emplace_back(name, fixture); \ + } \ + } \ + return params; \ + }()), \ + [](auto &&info) { return escapeTestLabel(info.param.first); }) + +auto escapeTestLabel(std::string_view label) { + std::string name; + name.reserve(label.size() * 2); + for (auto c : label) { + if (c == '/') { + name.append("__"); + } else if (not isalnum(c)) { + name.push_back('_'); + } else { + name.push_back(c); + } + } + return name; +} + +template +struct FixtureTest : testing::TestWithParam> {}; + +struct StateTransitionTest : FixtureTest {}; +FIXTURE_INSTANTIATE(StateTransitionTest, "state_transition"); + +TEST_P(StateTransitionTest, StateTransition) { + auto &[name, fixture] = GetParam(); + std::println("RUN {}", name); + lean::STF stf{std::make_shared()}; + auto stf_many = [&]() -> outcome::result { + auto state = fixture.pre; + for (auto &block : fixture.blocks) { + BOOST_OUTCOME_TRY(state, stf.stateTransition(block, state, true)); + } + return state; + }; + auto state_result = stf_many(); + ASSERT_EQ(state_result.has_value(), fixture.post.has_value()); + ASSERT_EQ(state_result.has_value(), not fixture.expect_exception.has_value()); + if (state_result.has_value()) { + auto &state = state_result.value(); + auto &post = *fixture.post; + ASSERT_EQ(state.slot, post.slot); + if (post.latest_justified_slot) { + ASSERT_EQ(state.latest_justified.slot, *post.latest_justified_slot); + } + if (post.latest_justified_root) { + ASSERT_EQ(state.latest_justified.root, *post.latest_justified_root); + } + if (post.latest_finalized_slot) { + ASSERT_EQ(state.latest_finalized.slot, *post.latest_finalized_slot); + } + if (post.latest_finalized_root) { + ASSERT_EQ(state.latest_finalized.root, *post.latest_finalized_root); + } + if (post.validator_count) { + ASSERT_EQ(state.validators.size(), *post.validator_count); + } + if (post.latest_block_header_slot) { + ASSERT_EQ(state.latest_block_header.slot, *post.latest_block_header_slot); + } + if (post.latest_block_header_state_root) { + ASSERT_EQ(state.latest_block_header.state_root, + *post.latest_block_header_state_root); + } + if (post.historical_block_hashes_count) { + ASSERT_EQ(state.historical_block_hashes.size(), + *post.historical_block_hashes_count); + } + } +} + +struct ForkChoiceTest : FixtureTest {}; +FIXTURE_INSTANTIATE(ForkChoiceTest, "fork_choice"); + +TEST_P(ForkChoiceTest, ForkChoice) { + auto &[name, fixture] = GetParam(); + std::println("RUN {}", name); + auto clock = std::make_shared(); + lean::ValidatorRegistry::ValidatorIndices validator_indices; + auto validator_registry = std::make_shared(); + EXPECT_CALL(*validator_registry, currentValidatorIndices()) + .Times(testing::AnyNumber()) + .WillRepeatedly(testing::ReturnRef(validator_indices)); + auto validator_key_manifest = + std::make_shared(); + EXPECT_CALL(*validator_key_manifest, getAllXmssPubkeys()) + .Times(testing::AnyNumber()); + EXPECT_CALL(*validator_key_manifest, currentNodeXmssKeypair()) + .Times(testing::AnyNumber()); + auto xmss_provider = std::make_shared(); + EXPECT_CALL(*xmss_provider, verify(_, _, _, _)) + .Times(testing::AnyNumber()) + .WillRepeatedly(testing::Return(true)); + lean::ForkChoiceStore store{ + fixture.anchor_state, + fixture.anchor_block, + clock, + testutil::prepareLoggers(), + std::make_shared(), + validator_registry, + validator_key_manifest, + xmss_provider, + }; + auto check = [&](const lean::BaseForkChoiceStep &step, auto &&f) { + outcome::result r = f(); + ASSERT_EQ(step.valid, r.has_value()); + if (auto &checks = step.checks) { + if (checks->time) { + ASSERT_EQ(store.time(), *checks->time); + } + if (checks->head_slot) { + ASSERT_EQ(store.getHeadSlot(), *checks->head_slot); + } + if (checks->head_root) { + ASSERT_EQ(store.getHead(), *checks->head_root); + } + if (checks->latest_justified_slot) { + ASSERT_EQ(store.getLatestJustified().slot, + *checks->latest_justified_slot); + } + if (checks->latest_justified_root) { + ASSERT_EQ(store.getLatestJustified().root, + *checks->latest_justified_root); + } + if (checks->latest_finalized_slot) { + ASSERT_EQ(store.getLatestFinalized().slot, + *checks->latest_finalized_slot); + } + if (checks->latest_finalized_root) { + ASSERT_EQ(store.getLatestFinalized().root, + *checks->latest_finalized_root); + } + if (checks->safe_target) { + ASSERT_EQ(store.getSafeTarget(), *checks->safe_target); + } + if (checks->attestation_target_slot) { + auto target = store.getAttestationTarget(); + ASSERT_EQ(target.slot, *checks->attestation_target_slot); + ASSERT_EQ(store.getBlockSlot(target.root), target.slot); + } + if (checks->attestation_checks) { + for (auto &check : *checks->attestation_checks) { + auto &attestations = + check.location == lean::AttestationCheckLocation::NEW + ? store.getLatestNewAttestations() + : store.getLatestKnownAttestations(); + auto &data = attestations.at(check.validator).message.data; + ASSERT_EQ(data.slot, check.attestation_slot); + if (check.head_slot) { + ASSERT_EQ(data.head.slot, *check.head_slot); + } + if (check.source_slot) { + ASSERT_EQ(data.source.slot, *check.source_slot); + } + if (check.target_slot) { + ASSERT_EQ(data.target.slot, *check.target_slot); + } + } + } + } + }; + for (auto &step : fixture.steps) { + if (auto *tick_step = std::get_if(&step.v)) { + check(*tick_step, [&]() -> outcome::result { + store.onTick(tick_step->time); + return outcome::success(); + }); + } else if (auto *block_step = std::get_if(&step.v)) { + check(*block_step, [&] { + auto &block_with_attestation = block_step->block; + auto &block = block_with_attestation.block; + lean::SignedBlockWithAttestation signed_block_with_attestation{ + .message = block_with_attestation, + .signature = {}, + }; + signed_block_with_attestation.signature.data().resize( + block.body.attestations.size() + 1); + auto block_time = store.getConfig().genesis_time + + block.slot * lean::SECONDS_PER_SLOT; + store.onTick(block_time); + return store.onBlock(signed_block_with_attestation); + }); + } else if (auto *attestation_step = + std::get_if(&step.v)) { + check(*attestation_step, [&] { + return store.onAttestation(attestation_step->attestation, false); + }); + } + } +} diff --git a/vcpkg.json b/vcpkg.json index dc16aaaa..a23e6186 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -12,7 +12,7 @@ "prometheus-cpp", "qdrvm-crates", "qtils", - "qdrvm-crates", + "rapidjson", "rocksdb", "snappy", "soralog",