EIP-8333 체크포인트를 에포크 경계 블록에 맞추기 (Align Checkpoint with Epoch Boundary Block)

포함 제외 (DFI) · 합의·스테이킹 · 원문 상태 Withdrawn · 2026-07-06 작성

에포크 N의 FFG 체크포인트가 가리키는 블록을 에포크 N의 첫 블록에서 그 직전 블록(경계 블록)으로 옮깁니다. 체크포인트의 에포크 번호는 그대로이고 어느 블록을 가리키는지만 바뀝니다.

왜 필요한가

이더리움 검증자는 매 에포크마다 어느 블록까지를 확정 후보로 볼지 목표(target) 투표를 합니다. 지금 이 목표는 그 에포크의 첫 슬롯 블록이고 에포크 안의 모든 증명(attestation)이 같은 목표를 가리킵니다. 뒤 슬롯의 위원회는 투표할 때 이미 목표를 알지만 첫 슬롯 위원회는 목표 블록이 제안된 직후 증명 마감 전에 투표해야 합니다. 블록이 늦게 도착하면 일부는 새 블록에, 일부는 이전 블록에 투표합니다. 체인이 채택한 체크포인트와 맞는 쪽만 정당화에 쓰이고 나머지 표는 버려지며 그 검증자들은 목표 보상을 잃습니다. 실제 네트워크에서 목표 투표 누락은 매 에포크 첫 슬롯에 몰려 있고 매 에포크 대략 1/SLOTS_PER_EPOCH 만큼의 FFG 가중치가 노출됩니다. 지금 방식은 의도한 설계가 아니라 오래된 오프바이원 오류(consensus-specs 이슈 2174, 652)이기도 합니다. 그 결과 '에포크 N 확정'이 실제로는 에포크 N의 첫 블록 하나만 확정됐다는 뜻이 되어 나머지 블록은 여전히 되돌릴 수 있고 에포크 단위로 확정을 보여 주는 탐색기와 도구도 부정확해집니다.

무엇이 바뀌나

지금

EIP-8333 이후

누구에게 영향이 있나

심층 설명

체크포인트 슬롯 정의: get_checkpoint_slot

새 헬퍼 get_checkpoint_slot(epoch)은 에포크의 체크포인트를 고정하는 슬롯을 돌려줍니다. 활성화 에포크(EIP8333_FORK_EPOCH) 이후에는 에포크 시작 직전 슬롯, 즉 Slot(compute_start_slot_at_epoch(epoch) - 1)입니다. 활성화 이전 에포크는 이전 방식대로 compute_start_slot_at_epoch(epoch)을 돌려줍니다. 앞에 슬롯이 없는 GENESIS_EPOCH은 GENESIS_SLOT에 고정됩니다. 이 헬퍼는 에포크만 받습니다. 상태 접근자 get_checkpoint_root와 포크 초이스의 get_checkpoint_block이 모두 이 헬퍼를 거치므로, 같은 체크포인트를 두 곳에서 다르게 해석할 수 없습니다.

체크포인트 루트 정의: get_checkpoint_root

get_checkpoint_root(state, epoch)은 get_checkpoint_slot(epoch) 이하에서 가장 최근 블록의 루트를 돌려줍니다. 구현은 get_block_root_at_slot(state, get_checkpoint_slot(epoch)) 한 줄입니다. 활성화 이후 이 값은 경계 블록입니다. 네트워크가 정상이면 직전 에포크의 마지막 블록이고 직전 에포크 끝 슬롯들이 비어 있으면 그보다 앞선 블록입니다. 제네시스 에포크는 직전 에포크가 없으므로 제네시스 블록으로 풀립니다. 에포크 N의 첫 슬롯이 비어 있을 때는 기존 get_block_root(state, N)도 이미 경계 블록을 돌려주므로, 그런 에포크에서는 이 제안으로 동작이 바뀌지 않습니다. 빠진 슬롯의 대체 규칙을 예외가 아닌 기본으로 만드는 셈이고 첫 슬롯에 블록이 있을 때만 동작이 달라집니다.

상태 전이 함수 수정

두 함수가 get_block_root(state, epoch) 대신 get_checkpoint_root(state, epoch)으로 체크포인트 루트를 구합니다. get_attestation_participation_flag_indices에서는 목표 일치 검사가 data.target.root를 get_checkpoint_root(state, data.target.epoch)과 비교합니다. 소스·헤드 일치와 적시성(timeliness) 조건은 그대로입니다. weigh_justification_and_finalization에서는 새로 기록되는 정당화 체크포인트의 root를 get_checkpoint_root에서 가져옵니다. 정당화 비트와 확정 규칙은 바뀌지 않습니다. 컨테이너가 하나도 바뀌지 않으므로 직렬화, 가십 포맷, 슬래싱 보호 데이터베이스도 영향을 받지 않습니다.

포크 초이스와 정직한 검증자

포크 초이스의 get_checkpoint_block(store, root, epoch)은 root 체인에서 get_checkpoint_slot(epoch) 위치의 조상을 찾아 돌려줍니다. 이를 쓰는 on_attestation 검증, filter_block_tree, 목표 블록에 대한 가십 조건은 추가 수정이 필요 없습니다. 검증자 가이드에서는 FFG 목표를 Checkpoint(epoch=get_current_epoch(head_state), root=get_checkpoint_root(head_state, get_current_epoch(head_state)))로 정합니다. 소스 투표는 그대로입니다. 에포크 첫 슬롯에서 헤드 블록 자체를 목표로 삼던 특례는 삭제됩니다. 실행 레이어는 바꿀 것이 없습니다.

포크 전환 규칙

get_checkpoint_slot은 활성화 에포크 이전 에포크를 반드시(MUST) 이전 방식인 compute_start_slot_at_epoch(epoch)으로 풀어야 합니다. 첫째, 활성화 전에 기록된 체크포인트는 이전 방식을 따릅니다. on_block과 filter_block_tree는 각각 들어오는 블록의 부모와 모든 유효 분기에서 확정 체크포인트 루트가 get_checkpoint_block 결과와 일치하기를 요구하는데, 확정 에포크를 새 규칙으로 다시 풀면 이 일치가 깨져 블록 임포트와 헤드 계산이 망가집니다. 둘째, 활성화 이전 목표 에포크를 가진 증명은 활성화 뒤에도 한 에포크 동안 포함될 수 있습니다. 이전 방식으로 평가해야 유효성과 보상이 유지됩니다. 이 변경은 합의 레이어와 하위 호환되지 않으므로 하드포크가 필요합니다.

셔플링 의존 루트와의 일치

경계 블록을 상태 전이 함수에 넣으면 에포크 시작 시점의 체인 상태가 결정적으로 나옵니다. 에포크가 시작되기 전까지 그 뒤에 오는 블록이 없기 때문입니다. 경계 블록은 에포크가 시작되기 전에 이미 고정되며 그보다 뒤의 블록을 고르면 그 에포크의 블록 생산에 의존하게 됩니다. 또 에포크 N의 체크포인트 루트는 룩어헤드가 N을 가리키는 임무 에포크의 셔플링 의존 루트, 즉 get_block_root_at_slot(state, compute_start_slot_at_epoch(N) - 1)과 같습니다. 포크 초이스 관점에서는 같은 체인 뷰에 대해 get_shuffling_dependent_root(store, root, N + MIN_SEED_LOOKAHEAD)가 고르는 루트입니다. FFG 체크포인트가 셔플링 의존 임무 검사와 같은 경계 앵커를 쓰게 됩니다.

보안 고려와 테스트 케이스

FFG 안전성은 영향받지 않습니다. 정당화, 확정, 슬래싱은 체크포인트 에포크 위에서 동작하고 에포크는 바뀌지 않기 때문입니다. 남는 공격면은 일부러 늦게 내보내는 경계 블록입니다. 이것은 다음 에포크 첫 슬롯의 목표 투표를 가를 수 있지만 지금 늦은 첫 슬롯 블록으로 가능한 것과 같은 공격이면서 더 어려워집니다. 전파 여유가 증명 마감까지의 시간에서 한 슬롯 이상으로 늘어나기 때문입니다. 경계 블록을 아예 숨기면 목표가 이미 전파된 이전 블록으로 떨어지므로 얻는 것이 없습니다. 테스트 케이스로는 경계 블록과 첫 슬롯 블록이 둘 다 있을 때 get_checkpoint_root가 get_block_root와 다른지, 첫 슬롯이 비면 둘이 같은지, 직전 에포크 끝이 비면 더 앞선 블록을 찾는지, GENESIS_EPOCH이 제네시스 블록 루트를 돌려주는지, 경계 블록 목표만 참여 플래그를 받는지, on_attestation이 경계 블록 목표는 받고 첫 블록 목표는 거부하는지, 경계에서 갈라진 분기마다 다른 경계 블록을 찾는지, 포크 전환 벡터가 열거돼 있습니다.

진행 상태: 철회

원문 상태는 Withdrawn(철회)입니다. 콜 기록을 보면 08.06 ACDC #184에서 이 EIP는 다음 ACDC로 보류됐고 08.20 ACDC #185에서 헤고타(Hegota) 포함 제안(PFI)으로 접수됐습니다. 10.01 ACDC #188에서 로드스타 팀이 철회(DFI)했습니다. 디커플드 합의(decoupled consensus)를 살펴본 결과 지금 다룰 가치가 없다고 판단했기 때문입니다. 따라서 이 명세는 현재 포크에 포함될 예정이 없습니다.

EIP 원문 · ← EIPs