EIP-7716 동시 장애 어테스테이션 벌칙 가중 (Anti-Correlation Attestation Penalties)

Hegota 포함 제외 (DFI) · 합의·스테이킹 · 원문 상태 Draft · 2024-05-25 작성

검증자가 어테스테이션을 놓쳤을 때, 같은 시각에 함께 멈춘 다른 검증자가 평소보다 얼마나 많은지에 따라 벌칙을 최대 256배까지 키웁니다. 혼자 놓친 검증자의 벌칙은 지금과 같습니다.

왜 필요한가

지금 이더리움에서 검증자가 어테스테이션(attestation, 블록에 대한 투표)을 놓치면 받는 벌칙은 다른 검증자가 어떻게 행동했는지와 무관합니다. 혼자 놓친 검증자와 네트워크의 30%와 함께 놓친 검증자가 에포크마다 똑같은 벌칙을 냅니다. 그래서 노드, 지역, 클라이언트, 인터넷 사업자, 클라우드 업체를 다양하게 나눌 경제적 이유가 거의 없습니다. 모든 검증자가 한 번에 멈출 확률을 줄이는 것 말고는 이득이 없기 때문입니다. 과거 어테스테이션 데이터를 보면 같은 운영자에 속한 검증자들은 우연보다 훨씬 자주 함께 놓치고 솔로 스테이커는 거의 독립적으로 행동합니다. 함께 실패하는 것에 벌칙을 매기면 운영 주체를 식별하지 않고도 크고 균질한 대형 스테이킹 설비의 규모의 경제를 줄일 수 있습니다. 프로토콜은 이미 동시 장애에 값을 매기지만 스테이크 3분의 1 이상이 멈춰 비활성 누출(inactivity leak)이 켜질 때만 그렇습니다. 그 아래 1%에서 33% 구간에서는 동시 장애가 사실상 공짜입니다. 이 EIP는 그 구간에 사건 크기에 비례하는 비용을 매끄럽게 붙입니다.

무엇이 바뀌나

지금

EIP-7716 이후

누구에게 영향이 있나

심층 설명

상수 세 개와 명세 관례

명세는 상수 세 개를 더합니다. MAX_PENALTY_FACTOR는 uint64(256)으로 벌칙 배수의 상한이며 유일한 강도 조절 변수입니다. PENALTY_SLOPE는 uint64(765)로 초과 오프라인 스테이크에 대한 배수의 기울기입니다. 3 * (MAX_PENALTY_FACTOR - 1)과 같게 정해서 상한이 정확히 스테이크 3분의 1에서 닿도록 했습니다. OFFLINE_BALANCE_SMOOTHING_FACTOR는 uint64(2**16)으로 오프라인 잔고 이동 평균의 평활 제수이며 반감기는 약 45,500슬롯(약 6.3일)입니다. 잔고는 모두 Gwei 단위 uint64입니다. SLOTS_PER_EPOCH, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, WEIGHT_DENOMINATOR, BeaconState, Slot은 Altair 이후 합의 명세의 정의와 값을 그대로 씁니다. 원문의 의사코드는 설명용이며 실행 가능한 정의는 합의 명세에 둔다고 밝힙니다.

비컨 상태 필드와 오프라인의 정의

BeaconState에 smoothed_offline_balance: Gwei 필드 하나를 더합니다. 슬롯별 오프라인 잔고의 지수 이동 평균입니다. 검증자가 어느 에포크에 '오프라인'이라는 것은 활성 상태이고 슬래시되지 않았으며 그 에포크에 timely source 플래그와 timely target 플래그가 둘 다 없는 경우입니다. 타깃은 틀렸지만 소스를 제때 맞게 투표한 검증자는 오프라인이 아닙니다. 살아 있음을 보였고 실패 원인이 인프라 장애가 아니라 체인 뷰 불일치이기 때문입니다. get_slot_offline_balance(state, slot)은 이전 에포크에 그 슬롯 위원회에 배정된 적격 검증자 중 두 플래그가 모두 없는 검증자의 effective_balance 합을 Gwei로 돌려줍니다.

슬롯별 벌칙 배수 계산

에포크 처리 시작 시 process_rewards_and_penalties보다 먼저 process_penalty_factors(state)를 실행해 이전 에포크의 슬롯마다 penalty_factor 하나를 구합니다. 기준 잔고 get_slot_reference_balance는 get_total_active_balance(state) // SLOTS_PER_EPOCH입니다. 슬롯마다 offline_balance를 구하고 excess = offline_balance - min(offline_balance, state.smoothed_offline_balance)를 계산한 뒤 penalty_factor = min(uint64(1) + PENALTY_SLOPE * excess // get_slot_reference_balance(state), MAX_PENALTY_FACTOR)로 정합니다. 그다음 이동 평균을 갱신합니다. offline_balance가 평균보다 크면 차이를 OFFLINE_BALANCE_SMOOTHING_FACTOR로 나눈 만큼 더하고 작으면 같은 방식으로 뺍니다. 오프라인 잔고가 이동 평균을 넘지 않으면 배수는 정확히 1이며 1 아래로 내려가는 할인 구간은 없습니다. 이동 평균은 빼는 기준선만 정하고 기울기는 슬롯당 활성 잔고로 정규화하므로 곡선 모양이 네트워크 참여율에 따라 달라지지 않습니다.

벌칙 적용 범위와 포크 전환

get_flag_index_deltas에서 오프라인 검증자의 timely target 벌칙만 그 검증자 위원회가 배정된 슬롯의 penalty_factor로 곱합니다. flag_index가 TIMELY_TARGET_FLAG_INDEX이고 is_offline(state, index)이면 penalties[index] += Gwei(penalty_factor * base_reward * weight // WEIGHT_DENOMINATOR)이고 그 외의 벌칙 분기는 기존처럼 Gwei(base_reward * weight // WEIGHT_DENOMINATOR)입니다. 플래그가 없어 벌칙을 받는 기존 분기만 바뀌며 누가 벌칙을 받는지와 모든 보상은 그대로입니다. timely source 벌칙은 가중하지 않고 timely head 누락은 지금처럼 벌칙이 없습니다. 제안자와 싱크 커미티 보상·벌칙, 비활성 누출 벌칙도 바뀌지 않습니다. 포크 에포크에서는 smoothed_offline_balance를 mean_per_slot_offline_balance_of_previous_epoch(pre_state)로 초기화해 포크 직전에 관측된 기준선을 심어 둡니다. 활성화 시점에 가짜 벌칙 배수가 생기지 않게 하기 위한 것입니다.

설계 근거: 이동 평균 기준, 선형 배수, 초안 방식 교체

배수를 현재 슬롯의 오프라인 잔고와 느리게 움직이는 이동 평균의 차이로 정한 결과는 세 가지입니다. 첫째, 동시 장애 시작 시점에 배수가 이상치 크기에 비례해 뛰고 이동 평균이 사건을 흡수하면서 하루쯤에 걸쳐 내려갑니다. 운영자는 상관되어 있다는 사실에 벌칙을 받고 복구가 느린 것에는 덜 받습니다. 둘째, 시작 배수는 1 + PENALTY_SLOPE * spike로 1% 동시 장애는 약 9배, 5%는 약 39배, 10%는 약 78배, 20%는 약 154배입니다. PENALTY_SLOPE = 3 * (MAX_PENALTY_FACTOR - 1)이므로 상한은 정확히 3분의 1에서 닿습니다. 셋째, 참여가 안정적이면 모든 슬롯의 배수가 정확히 1입니다. 개별 배수는 선형으로 둡니다. 영향받는 스테이크와 배수가 각각 선형이라 네트워크 전체 벌칙은 이미 사건 크기의 2차 함수이고 볼록한 배수는 전체를 3차로 밀면서 운영자 선택이 작용하는 1~15% 구간의 억제력을 없애기 때문입니다. 초안의 NET_EXCESS_PENALTIES 카운터는 상한이 총 벌칙에 거의 영향이 없고 메인넷 참여율에서 평형이 1 아래라 0 근처에서 진동하며 억제력 있는 규모에서 회복 창이 몇 달로 늘어나는 결함이 있어 명시적 이동 평균으로 교체했습니다.

왜 타깃 벌칙만, 왜 소스·타깃을 모두 놓친 검증자만 가중하는가

가중은 소스와 타깃을 둘 다 놓친 검증자의 timely target 벌칙에만 적용합니다. 관대함이 아니라 견고함을 위한 선택입니다. 타깃 플래그는 포함 창이 다음 에포크 전체로 가장 넓어서 블록 공간이나 타이밍 운과 무관하게 검증자의 생존을 반영합니다. 소스 적시성은 블록 없는 슬롯이 5개 지나면 실패하므로 빌더·릴레이·제안자 장애가 건강한 검증자에게 소스 누락을 만들어 낼 수 있습니다. 두 플래그 조건은 뷰 불일치를 제외합니다. 에포크 경계 블록이 늦었거나, 제안자가 뷰를 갈랐거나, 올바른 소수 클라이언트가 버그 있는 다수와 다르게 봐서 타깃만 틀린 검증자는 지금의 벌칙만 냅니다. 과거 재생에서 기준선의 살아 있지만 타깃이 틀린 스테이크 중 91~97%가 에포크 슬롯 0에 몰려 있는데, 이 조건에서는 아무것도 가중되지 않고 오프라인 잔고에도 들어가지 않습니다. EIP-8333이 체크포인트를 에포크 이전 마지막 블록에 고정해 이 현상을 근본에서 없애며 이 EIP는 그것과 결합되지만 의존하지는 않습니다. 소스 투표를 기준으로 삼는 안은 기각했습니다. 2023년 5월 사건의 정점에서 타깃은 있고 소스가 없는 스테이크가 5.3%였고 반대는 0.11%였습니다. 헤드 누락은 지금처럼 벌칙이 없습니다.

보정 수치, 과거 사건 재생, 최악의 경우 한계

보정 표는 약 4,000만 ETH 스테이크를 가정해 32 ETH당 비용을 보상 배수로 보입니다. 비상관 24시간은 지금과 같은 약 1일치 보상, 1% 동시 장애 24시간은 약 3배(약 반 주치), 10% 24시간은 약 21배(약 3.6주치, 원금의 0.22%), 20% 24시간은 약 41배(약 7주치)입니다. 10% 72시간은 약 8배로, 집단보다 이틀 늦게 복구해도 24시간 복구자보다 조금만 더 냅니다. 과거 네 사건 재생에서 초안은 모두 현상 유지의 몇 % 안이었고 이 개정안은 2023년 5월 11·12일 최종성 사건(정점 69%) 79배, 2024-01-06 Besu 정지(12.4%) 3.4배, 2024-01-21 Nethermind 합의 버그(18.8%) 14배, 2025-12-04 Prysm 장애(29.8%) 45배입니다. 상한 256은 128~512를 비교해 골랐고 512는 꼬리가 과해 기각했습니다. 보안 면에서 뷰 분할이나 타이밍 게임으로 누락을 만드는 전략은 헤드 투표에 벌칙이 없고 살아 있는 검증자는 가중되지 않아 이득이 없습니다. 최대 벌칙 흐름은 에포크당 (TIMELY_SOURCE_WEIGHT + MAX_PENALTY_FACTOR * TIMELY_TARGET_WEIGHT) / WEIGHT_DENOMINATOR 기본 보상으로 하루 원금의 약 0.75%이고, 3분의 1 장애에 끼어 영영 복구하지 않는 최악의 경우도 원금의 약 6.7%(약 2.6년치 보상)로 묶입니다. 늘어난 벌칙은 재분배하지 않고 소각합니다.

문서 상태와 코어 개발자 콜 결정

원문 상태는 Draft여서 상수, 의사코드, 적용 범위가 아직 바뀔 수 있습니다. 실제로 이 문서는 초안의 NET_EXCESS_PENALTIES 방식을 이동 평균 방식으로 교체한 개정판입니다. 코어 개발자 콜 기록을 보면 08.06 ACDC #184에서 EIP-7716의 설계 갱신안이 발표됐습니다. 벌칙 곡선을 위로 재조정하고 헤드 투표 정확도를 빼 소스와 타깃만 보는 내용입니다. 09.16 AMA #15에서 논의됐지만 결정은 없었습니다. 10.15 ACDC #189에서는 EIP-7716이 헤고타(Hegota) 후보에서 제외됐습니다. 지지가 무관심 수준이었고 비컨 상태를 건드리는 데 대한 우려가 있었기 때문입니다. 따라서 헤고타 포크에는 들어가지 않습니다.

EIP 원문 · ← EIPs