From 3fc24f3d415280484ff1c99813d060d39b242983 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 31 Mar 2019 21:20:43 -0500 Subject: [PATCH 1/3] Replace with empty instead of popping finished challenges --- specs/core/1_custody-game.md | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index fd754634e..41ba9d953 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -31,6 +31,7 @@ - [`get_crosslink_chunk_count`](#get_crosslink_chunk_count) - [`get_custody_chunk_bit`](#get_custody_chunk_bit) - [`epoch_to_custody_period`](#epoch_to_custody_period) + - [`replace_empty_or_append`](#replace_empty_or_append) - [`verify_custody_key`](#verify_custody_key) - [Per-block processing](#per-block-processing) - [Transactions](#transactions) @@ -229,6 +230,18 @@ def epoch_to_custody_period(epoch: Epoch) -> int: return epoch // EPOCHS_PER_CUSTODY_PERIOD ``` +### `replace_empty_or_append` + +```python +def replace_empty_or_append(list: List[Any], empty_element: Any, new_element: Any) -> int: + for i in range(len(list)): + if list[i] == empty_element: + list[i] = new_element + return i + list.append(new_element) + return len(list) - 1 +``` + ### `verify_custody_key` ```python @@ -321,7 +334,7 @@ def process_chunk_challenge(state: BeaconState, depth = math.log2(next_power_of_two(get_custody_chunk_count(challenge.attestation))) assert challenge.chunk_index < 2**depth # Add new chunk challenge record - state.custody_chunk_challenge_records.append(CustodyChunkChallengeRecord( + new_record = CustodyChunkChallengeRecord( challenge_index=state.custody_challenge_index, challenger_index=get_beacon_proposer_index(state, state.slot), responder_index=challenge.responder_index @@ -329,7 +342,13 @@ def process_chunk_challenge(state: BeaconState, crosslink_data_root=challenge.attestation.data.crosslink_data_root, depth=depth, chunk_index=challenge.chunk_index, - )) + ) + replace_empty_or_append( + list=state.custody_chunk_challenge_records, + empty_element=CustodyChunkChallengeRecord(), + new_element=new_record + ) + state.custody_challenge_index += 1 # Postpone responder withdrawability responder.withdrawable_epoch = FAR_FUTURE_EPOCH @@ -385,7 +404,7 @@ def process_bit_challenge(state: BeaconState, custody_bit = get_bitfield_bit(attestation.custody_bitfield, attesters.index(responder_index)) assert custody_bit != chunk_bits_xor # Add new bit challenge record - state.custody_bit_challenge_records.append(CustodyBitChallengeRecord( + new_record = CustodyBitChallengeRecord( challenge_index=state.custody_challenge_index, challenger_index=challenge.challenger_index, responder_index=challenge.responder_index, @@ -393,7 +412,12 @@ def process_bit_challenge(state: BeaconState, crosslink_data_root=challenge.attestation.crosslink_data_root, chunk_bits=challenge.chunk_bits, responder_key=challenge.responder_key, - )) + ) + replace_empty_or_append( + list=state.custody_bit_challenge_records, + empty_element=CustodyBitChallengeRecord(), + new_element=new_record + ) state.custody_challenge_index += 1 # Postpone responder withdrawability responder.withdrawable_epoch = FAR_FUTURE_EPOCH @@ -434,7 +458,8 @@ def process_chunk_challenge_response(state: BeaconState, root=challenge.crosslink_data_root, ) # Clear the challenge - state.custody_chunk_challenge_records.remove(challenge) + records = state.custody_chunk_challenge_records + records[records.index(challenge)] = CustodyChunkChallengeRecord() # Reward the proposer proposer_index = get_beacon_proposer_index(state, state.slot) increase_balance(state, proposer_index, base_reward(state, index) // MINOR_REWARD_QUOTIENT) @@ -457,7 +482,8 @@ def process_bit_challenge_response(state: BeaconState, # Verify the chunk bit does not match the challenge chunk bit assert get_custody_chunk_bit(challenge.responder_key, response.chunk) != get_bitfield_bit(challenge.chunk_bits, response.chunk_index) # Clear the challenge - state.custody_bit_challenge_records.remove(challenge) + records = state.custody_bit_challenge_records + records[records.index(challenge)] = CustodyBitChallengeRecord() # Slash challenger slash_validator(state, challenge.challenger_index, challenge.responder_index) ``` @@ -471,12 +497,14 @@ def process_challenge_deadlines(state: BeaconState) -> None: for challenge in state.custody_chunk_challenge_records: if get_current_epoch(state) > challenge.deadline: slash_validator(state, challenge.responder_index, challenge.challenger_index) - state.custody_chunk_challenge_records.remove(challenge) + records = state.custody_chunk_challenge_records + records[records.index(challenge)] = CustodyChunkChallengeRecord() for challenge in state.custody_bit_challenge_records: if get_current_epoch(state) > challenge.deadline: slash_validator(state, challenge.responder_index, challenge.challenger_index) - state.custody_bit_challenge_records.remove(challenge) + records = state.custody_bit_challenge_records + records[records.index(challenge)] = CustodyBitChallengeRecord() ``` In `process_penalties_and_exits`, change the definition of `eligible` to the following (note that it is not a pure function because `state` is declared in the surrounding scope): From 9dde3a26612cbe1636529ec0d85f8462c8271f9b Mon Sep 17 00:00:00 2001 From: vbuterin Date: Tue, 9 Apr 2019 05:59:00 -0500 Subject: [PATCH 2/3] Update replace_empty_or_append Requires adding definitions of `empty` and `typeof` to the function puller. --- specs/core/1_custody-game.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 41ba9d953..88341ae98 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -233,9 +233,9 @@ def epoch_to_custody_period(epoch: Epoch) -> int: ### `replace_empty_or_append` ```python -def replace_empty_or_append(list: List[Any], empty_element: Any, new_element: Any) -> int: +def replace_empty_or_append(list: List[Any], new_element: Any) -> int: for i in range(len(list)): - if list[i] == empty_element: + if list[i] == empty(typeof(new_element)): list[i] = new_element return i list.append(new_element) @@ -343,11 +343,7 @@ def process_chunk_challenge(state: BeaconState, depth=depth, chunk_index=challenge.chunk_index, ) - replace_empty_or_append( - list=state.custody_chunk_challenge_records, - empty_element=CustodyChunkChallengeRecord(), - new_element=new_record - ) + replace_empty_or_append(state.custody_chunk_challenge_records, new_record) state.custody_challenge_index += 1 # Postpone responder withdrawability @@ -413,11 +409,7 @@ def process_bit_challenge(state: BeaconState, chunk_bits=challenge.chunk_bits, responder_key=challenge.responder_key, ) - replace_empty_or_append( - list=state.custody_bit_challenge_records, - empty_element=CustodyBitChallengeRecord(), - new_element=new_record - ) + replace_empty_or_append(state.custody_bit_challenge_records, new_record) state.custody_challenge_index += 1 # Postpone responder withdrawability responder.withdrawable_epoch = FAR_FUTURE_EPOCH From d4a33dbcaa093588c9cca1479bb1487ccd630c63 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 22 Apr 2019 15:29:47 -0600 Subject: [PATCH 3/3] add descriptions of typeof and default functions --- specs/core/1_custody-game.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index 88341ae98..c8625af5b 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -28,6 +28,8 @@ - [`BeaconState`](#beaconstate) - [`BeaconBlockBody`](#beaconblockbody) - [Helpers](#helpers) + - [`typeof`](#typeof) + - [`empty`](#empty) - [`get_crosslink_chunk_count`](#get_crosslink_chunk_count) - [`get_custody_chunk_bit`](#get_custody_chunk_bit) - [`epoch_to_custody_period`](#epoch_to_custody_period) @@ -204,6 +206,14 @@ Add the following fields to the end of the specified container objects. Fields w ## Helpers +### `typeof` + +The `typeof` function accepts and SSZ object as a single input and returns the corresponding SSZ type. + +### `empty` + +The `empty` function accepts and SSZ type as input and returns an object of that type with all fields initialized to default values. + ### `get_crosslink_chunk_count` ```python