From f06a3b82e7f97f12f1f70e07f5a09b854755b8a1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 11 Mar 2019 14:38:10 -0600 Subject: [PATCH 1/5] cache current and previous justified root in state --- specs/core/0_beacon-chain.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ceca50962..0a86db3f9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -613,6 +613,8 @@ The types are defined topologically to aid in facilitating an executable version 'current_epoch_attestations': [PendingAttestation], 'previous_justified_epoch': 'uint64', 'justified_epoch': 'uint64', + 'previous_justified_root': 'bytes32', + 'justified_root': 'bytes32', 'justification_bitfield': 'uint64', 'finalized_epoch': 'uint64', @@ -1546,6 +1548,8 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], current_epoch_attestations=[], previous_justified_epoch=GENESIS_EPOCH, justified_epoch=GENESIS_EPOCH, + previous_justified_root=ZERO_HASH, + justified_root=ZERO_HASH, justification_bitfield=0, finalized_epoch=GENESIS_EPOCH, @@ -1830,7 +1834,9 @@ def update_justification_and_finalization(state: BeaconState) -> None: # Rotate justified epochs state.previous_justified_epoch = state.justified_epoch + state.previous_justified_root = state.justified_root state.justified_epoch = new_justified_epoch + state.justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) ``` #### Crosslinks @@ -2374,16 +2380,15 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: assert state.slot <= attestation.data.slot + SLOTS_PER_EPOCH # Can't submit attestations too quickly assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - # Verify that the justified epoch is correct, case 1: current epoch attestations + # Verify that the justified epoch/root is correct if slot_to_epoch(attestation.data.slot) >= get_current_epoch(state): + # Case 1: current epoch attestations assert attestation.data.justified_epoch == state.justified_epoch - # Case 2: previous epoch attestations + assert attestation.data.justified_block_root == state.justified_root else: + # Case 2: previous epoch attestations assert attestation.data.justified_epoch == state.previous_justified_epoch - # Check that the justified block root is correct - assert attestation.data.justified_block_root == get_block_root( - state, get_epoch_start_slot(attestation.data.justified_epoch) - ) + assert attestation.data.justified_block_root == state.previous_justified_root # Check that the crosslink data is valid acceptable_crosslink_data = { # Case 1: Latest crosslink matches the one in the state From 3916643ef6dc663f4c0da91efd86e351721bdf7d Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 11 Mar 2019 18:23:17 -0600 Subject: [PATCH 2/5] only update justified epoch/root if changed --- specs/core/0_beacon-chain.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0a86db3f9..47dd765af 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1835,8 +1835,9 @@ def update_justification_and_finalization(state: BeaconState) -> None: # Rotate justified epochs state.previous_justified_epoch = state.justified_epoch state.previous_justified_root = state.justified_root - state.justified_epoch = new_justified_epoch - state.justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) + if new_justified_epoch != state.justified_epoch: + state.justified_epoch = new_justified_epoch + state.justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) ``` #### Crosslinks From 578bf02b6f76339b8a4fb21249326b4c46f7b2f4 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 12 Mar 2019 10:17:34 +0000 Subject: [PATCH 3/5] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 73 +++++++++++++++++------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 47dd765af..7eb9752bb 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -335,22 +335,19 @@ The types are defined topologically to aid in facilitating an executable version ```python { - # Slot number + # LMD GHOST vote 'slot': 'uint64', - # Shard number - 'shard': 'uint64', - # Root of the signed beacon block 'beacon_block_root': 'bytes32', - # Root of the ancestor at the epoch boundary - 'epoch_boundary_root': 'bytes32', - # Data from the shard since the last attestation + + # FFG vote + 'source_epoch': 'uint64', + 'source_root': 'bytes32', + 'target_root': 'bytes32', + + # Crosslink vote + 'shard': 'uint64', + 'previous_crosslink': Crosslink, 'crosslink_data_root': 'bytes32', - # Last crosslink - 'latest_crosslink': Crosslink, - # Last justified epoch in the beacon state - 'justified_epoch': 'uint64', - # Hash of the last justified beacon block - 'justified_block_root': 'bytes32', } ``` @@ -612,9 +609,9 @@ The types are defined topologically to aid in facilitating an executable version 'previous_epoch_attestations': [PendingAttestation], 'current_epoch_attestations': [PendingAttestation], 'previous_justified_epoch': 'uint64', - 'justified_epoch': 'uint64', + 'current_justified_epoch': 'uint64', 'previous_justified_root': 'bytes32', - 'justified_root': 'bytes32', + 'current_justified_root': 'bytes32', 'justification_bitfield': 'uint64', 'finalized_epoch': 'uint64', @@ -1225,8 +1222,8 @@ def is_surround_vote(attestation_data_1: AttestationData, """ Check if ``attestation_data_1`` surrounds ``attestation_data_2``. """ - source_epoch_1 = attestation_data_1.justified_epoch - source_epoch_2 = attestation_data_2.justified_epoch + source_epoch_1 = attestation_data_1.source_epoch + source_epoch_2 = attestation_data_2.source_epoch target_epoch_1 = slot_to_epoch(attestation_data_1.slot) target_epoch_2 = slot_to_epoch(attestation_data_2.slot) @@ -1547,9 +1544,9 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], previous_epoch_attestations=[], current_epoch_attestations=[], previous_justified_epoch=GENESIS_EPOCH, - justified_epoch=GENESIS_EPOCH, + current_justified_epoch=GENESIS_EPOCH, previous_justified_root=ZERO_HASH, - justified_root=ZERO_HASH, + current_justified_root=ZERO_HASH, justification_bitfield=0, finalized_epoch=GENESIS_EPOCH, @@ -1733,7 +1730,7 @@ def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestat def get_current_epoch_boundary_attestations(state: BeaconState) -> List[PendingAttestation]: return [ a for a in state.current_epoch_attestations - if a.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(get_current_epoch(state))) + if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_current_epoch(state))) ] ``` @@ -1741,7 +1738,7 @@ def get_current_epoch_boundary_attestations(state: BeaconState) -> List[PendingA def get_previous_epoch_boundary_attestations(state: BeaconState) -> List[PendingAttestation]: return [ a for a in state.previous_epoch_attestations - if a.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))) + if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))) ] ``` @@ -1759,7 +1756,7 @@ def get_previous_epoch_matching_head_attestations(state: BeaconState) -> List[Pe def get_winning_root_and_participants(state: BeaconState, shard: Shard) -> Tuple[Bytes32, List[ValidatorIndex]]: all_attestations = state.current_epoch_attestations + state.previous_epoch_attestations valid_attestations = [ - a for a in all_attestations if a.data.latest_crosslink == state.latest_crosslinks[shard] + a for a in all_attestations if a.data.previous_crosslink == state.latest_crosslinks[shard] ] all_roots = [a.data.crosslink_data_root for a in valid_attestations] @@ -1802,7 +1799,7 @@ Run the following function: ```python def update_justification_and_finalization(state: BeaconState) -> None: - new_justified_epoch = state.justified_epoch + new_justified_epoch = state.current_justified_epoch # Rotate the justification bitfield up one epoch to make room for the current epoch state.justification_bitfield <<= 1 # If the previous epoch gets justified, fill the second last bit @@ -1826,18 +1823,18 @@ def update_justification_and_finalization(state: BeaconState) -> None: if (bitfield >> 1) % 4 == 0b11 and state.previous_justified_epoch == current_epoch - 2: state.finalized_epoch = state.previous_justified_epoch # The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 3rd as source - if (bitfield >> 0) % 8 == 0b111 and state.justified_epoch == current_epoch - 2: - state.finalized_epoch = state.justified_epoch + if (bitfield >> 0) % 8 == 0b111 and state.current_justified_epoch == current_epoch - 2: + state.finalized_epoch = state.current_justified_epoch # The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source - if (bitfield >> 0) % 4 == 0b11 and state.justified_epoch == current_epoch - 1: - state.finalized_epoch = state.justified_epoch + if (bitfield >> 0) % 4 == 0b11 and state.current_justified_epoch == current_epoch - 1: + state.finalized_epoch = state.current_justified_epoch # Rotate justified epochs - state.previous_justified_epoch = state.justified_epoch - state.previous_justified_root = state.justified_root - if new_justified_epoch != state.justified_epoch: - state.justified_epoch = new_justified_epoch - state.justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) + state.previous_justified_epoch = state.current_justified_epoch + state.previous_justified_root = state.current_justified_root + if new_justified_epoch != state.current_justified_epoch: + state.current_justified_epoch = new_justified_epoch + state.current_justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) ``` #### Crosslinks @@ -2381,19 +2378,19 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: assert state.slot <= attestation.data.slot + SLOTS_PER_EPOCH # Can't submit attestations too quickly assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - # Verify that the justified epoch/root is correct + # Verify that the justified epoch and root is correct if slot_to_epoch(attestation.data.slot) >= get_current_epoch(state): # Case 1: current epoch attestations - assert attestation.data.justified_epoch == state.justified_epoch - assert attestation.data.justified_block_root == state.justified_root + assert attestation.data.source_epoch == state.current_justified_epoch + assert attestation.data.source_root == state.current_justified_root else: # Case 2: previous epoch attestations - assert attestation.data.justified_epoch == state.previous_justified_epoch - assert attestation.data.justified_block_root == state.previous_justified_root + assert attestation.data.source_epoch == state.previous_justified_epoch + assert attestation.data.source_root == state.previous_justified_root # Check that the crosslink data is valid acceptable_crosslink_data = { # Case 1: Latest crosslink matches the one in the state - attestation.data.latest_crosslink, + attestation.data.previous_crosslink, # Case 2: State has already been updated, state's latest crosslink matches the crosslink # the attestation is trying to create Crosslink( From addf7b77ab13cfae82ae72d5a20986fb865ffd27 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 12 Mar 2019 10:26:34 +0000 Subject: [PATCH 4/5] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7eb9752bb..319f826af 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -614,6 +614,7 @@ The types are defined topologically to aid in facilitating an executable version 'current_justified_root': 'bytes32', 'justification_bitfield': 'uint64', 'finalized_epoch': 'uint64', + 'finalized_root': 'bytes32', # Recent state 'latest_crosslinks': [Crosslink, SHARD_COUNT], @@ -1828,6 +1829,7 @@ def update_justification_and_finalization(state: BeaconState) -> None: # The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source if (bitfield >> 0) % 4 == 0b11 and state.current_justified_epoch == current_epoch - 1: state.finalized_epoch = state.current_justified_epoch + state.finalized_root = get_block_root(state, get_epoch_start_slot(finalized_epoch)) # Rotate justified epochs state.previous_justified_epoch = state.current_justified_epoch From e8a5cd074766c3dfe6d424e8a08572bdae9a7445 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 12 Mar 2019 12:32:11 -0600 Subject: [PATCH 5/5] fix up for tests --- specs/core/0_beacon-chain.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 82505a220..bd0187a9f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1545,6 +1545,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], current_justified_root=ZERO_HASH, justification_bitfield=0, finalized_epoch=GENESIS_EPOCH, + finalized_root=ZERO_HASH, # Recent state latest_crosslinks=[Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH) for _ in range(SHARD_COUNT)], @@ -1796,6 +1797,8 @@ Run the following function: ```python def update_justification_and_finalization(state: BeaconState) -> None: new_justified_epoch = state.current_justified_epoch + new_finalized_epoch = state.finalized_epoch + # Rotate the justification bitfield up one epoch to make room for the current epoch state.justification_bitfield <<= 1 # If the previous epoch gets justified, fill the second last bit @@ -1814,24 +1817,26 @@ def update_justification_and_finalization(state: BeaconState) -> None: current_epoch = get_current_epoch(state) # The 2nd/3rd/4th most recent epochs are all justified, the 2nd using the 4th as source if (bitfield >> 1) % 8 == 0b111 and state.previous_justified_epoch == current_epoch - 3: - state.finalized_epoch = state.previous_justified_epoch + new_finalized_epoch = state.previous_justified_epoch # The 2nd/3rd most recent epochs are both justified, the 2nd using the 3rd as source if (bitfield >> 1) % 4 == 0b11 and state.previous_justified_epoch == current_epoch - 2: - state.finalized_epoch = state.previous_justified_epoch + new_finalized_epoch = state.previous_justified_epoch # The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 3rd as source if (bitfield >> 0) % 8 == 0b111 and state.current_justified_epoch == current_epoch - 2: - state.finalized_epoch = state.current_justified_epoch + new_finalized_epoch = state.current_justified_epoch # The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source if (bitfield >> 0) % 4 == 0b11 and state.current_justified_epoch == current_epoch - 1: - state.finalized_epoch = state.current_justified_epoch - state.finalized_root = get_block_root(state, get_epoch_start_slot(finalized_epoch)) + new_finalized_epoch = state.current_justified_epoch - # Rotate justified epochs + # Update state jusification/finality fields state.previous_justified_epoch = state.current_justified_epoch state.previous_justified_root = state.current_justified_root if new_justified_epoch != state.current_justified_epoch: state.current_justified_epoch = new_justified_epoch state.current_justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) + if new_finalized_epoch != state.finalized_epoch: + state.finalized_epoch = new_finalized_epoch + state.finalized_root = get_block_root(state, get_epoch_start_slot(new_finalized_epoch)) ``` #### Crosslinks