Skip to content

Latest commit

 

History

History
170 lines (132 loc) · 7.29 KB

weak-subjectivity.md

File metadata and controls

170 lines (132 loc) · 7.29 KB

Ethereum 2.0 Phase 0 -- Weak Subjectivity Guide

Table of contents

Introduction

This document is a guide for implementing the Weak Subjectivity protections in Phase 0 of Ethereum 2.0. This document is still a work-in-progress, and is subject to large changes. For more information about weak subjectivity and why it is required, please refer to:

Prerequisites

This document uses data structures, constants, functions, and terminology from Phase 0 -- The Beacon Chain and Phase 0 -- Beacon Chain Fork Choice.

Constants

Name Value
SAFETY_DECAY uint64(10)

Weak Subjectivity Checkpoint

Any Checkpoint object can be used as a Weak Subjectivity Checkpoint. These Weak Subjectivity Checkpoints are distributed by providers, downloaded by users and/or distributed as a part of clients, and used as input while syncing a client.

Weak Subjectivity Period

The Weak Subjectivity Period is the number of recent epochs within which there must be a Weak Subjectivity Checkpoint to ensure that an attacker who takes control of the validator set at the beginning of the period is slashed at least a minimum threshold in the event that a conflicting Checkpoint is finalized.

SAFETY_DECAY is defined as the maximum percentage tolerable loss in the one-third safety margin of FFG finality. Thus, any attack exploiting the Weak Subjectivity Period has a safety margin of at least 1/3 - SAFETY_DECAY/100.

Calculating the Weak Subjectivity Period

A detailed analysis of the calculation of the weak subjectivity period is made in this report. The expressions in the report use fractions, whereas we only use uint64 arithmetic in eth2.0-specs. The expressions have been simplified to avoid computing fractions, and more details can be found here.

def get_active_validator_count(state: BeaconState) -> uint64:
    active_validator_count = len(get_active_validator_indices(state, get_current_epoch(state)))
    return active_validator_count

def compute_avg_active_validator_balance(state: BeaconState) -> Gwei:
    total_active_balance = get_total_active_balance(state)
    active_validator_count = get_active_validator_count(state)
    avg_active_validator_balance = total_active_balance // active_validator_count
    return avg_active_validator_balance//10**9

def compute_weak_subjectivity_period(state: BeaconState) -> uint64:
    ws_period = MIN_VALIDATOR_WITHDRAWABILITY_DELAY
    N = get_active_validator_count(state)
    t = compute_avg_active_validator_balance(state)
    T = MAX_EFFECTIVE_BALANCE//10**9
    delta = get_validator_churn_limit(state)
    Delta = MAX_DEPOSITS * SLOTS_PER_EPOCH
    D = SAFETY_DECAY

    case = (
      T*(200+3*D) < t*(200+12*D)
    )

    if case == 1:
      arg1 = (
        N*(t*(200+12*D) - T*(200+3*D)) // (600*delta*(2*t+T))
      )
      arg2 = (
        N*(200+3*D) // (600*Delta)
      )
      ws_period += max(arg1, arg2)
    else:
      ws_period += (
         3*N*D*t // (200*Delta*(T-t))
      )
    
    return ws_period

A brief reference for what these values look like in practice:

SAFETY_DECAY validator_count average_active_validator_balance weak_subjectivity_period
10 8192 28 318
10 8192 32 358
10 16384 28 380
10 16384 32 460
10 32768 28 504
10 32768 32 665
20 8192 28 411
20 8192 32 460
20 16384 28 566
20 16384 32 665
20 32768 28 876
20 32768 32 1075
33 8192 28 532
33 8192 32 593
33 16384 28 808
33 16384 32 931
33 32768 28 1360
33 32768 32 1607

Weak Subjectivity Sync

Clients should allow users to input a Weak Subjectivity Checkpoint at startup, and guarantee that any successful sync leads to the given Weak Subjectivity Checkpoint along the canonical chain. If such a sync is not possible, the client should treat this as a critical and irrecoverable failure.

Weak Subjectivity Sync Procedure

  1. Input a Weak Subjectivity Checkpoint as a CLI parameter in block_root:epoch_number format, where block_root (an "0x" prefixed 32-byte hex string) and epoch_number (an integer) represent a valid Checkpoint. Example of the format:
0x8584188b86a9296932785cc2827b925f9deebacce6d72ad8d53171fa046b43d9:9544
  1. Check the weak subjectivity requirements:
    • IF epoch_number > store.finalized_checkpoint.epoch, then ASSERT during block sync that block with root block_root is in the sync path at epoch epoch_number. Emit descriptive critical error if this assert fails, then exit client process.
    • IF epoch_number <= store.finalized_checkpoint.epoch, then ASSERT that the block in the canonical chain at epoch epoch_number has root block_root. Emit descriptive critical error if this assert fails, then exit client process.

Checking for Stale Weak Subjectivity Checkpoint

Clients may choose to validate that the input Weak Subjectivity Checkpoint is not stale at the time of startup. To support this mechanism, the client needs to take the state at the Weak Subjectivity Checkpoint as a CLI parameter input (or fetch the state associated with the input Weak Subjectivity Checkpoint from some source). The check can be implemented in the following way:

def is_within_weak_subjectivity_period(store: Store, ws_state: BeaconState, ws_checkpoint: Checkpoint) -> bool:
    # Clients may choose to validate the input state against the input Weak Subjectivity Checkpoint
    assert ws_state.latest_block_header.state_root == ws_checkpoint.root
    assert compute_epoch_at_slot(ws_state.slot) == ws_checkpoint.epoch

    ws_period = compute_weak_subjectivity_period(ws_state)
    ws_state_epoch = compute_epoch_at_slot(ws_state.slot)
    current_epoch = compute_epoch_at_slot(get_current_slot(store))
    return current_epoch <= ws_state_epoch + ws_period

Distributing Weak Subjectivity Checkpoints

This section will be updated soon.