From d5900836aadcd63fb1b02cbdc21a9fcc41653fdd Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 28 Feb 2019 20:54:59 -0600 Subject: [PATCH 01/10] Convert transaction descriptions from English to python code Only a change of presentation, does not make any substantive changes. Does NOT handle Deposit transactions because that is a special case for which I recommend a deeper change (will do this in another PR soon). --- specs/core/0_beacon-chain.md | 196 +++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 54 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3ea4d4101f..e179ec43a8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1629,59 +1629,107 @@ Below are the processing steps that happen at every `block`. Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`. -For each `proposer_slashing` in `block.body.proposer_slashings`: - -* Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`. -* Verify that `proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot`. -* Verify that `proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard`. -* Verify that `proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root`. -* Verify that `proposer.slashed is False`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_1, "signature"), signature=proposer_slashing.proposal_1.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot), DOMAIN_PROPOSAL))`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_2, "signature"), signature=proposer_slashing.proposal_2.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot), DOMAIN_PROPOSAL))`. -* Run `slash_validator(state, proposer_slashing.proposer_index)`. +For each `proposer_slashing` in `block.body.proposer_slashings`, run the following function: + +```python +def process_proposer_slashing(proposer_slashing: ProposerSlashing, + state: BeaconState): + proposer = state.validator_registry[proposer_slashing.proposer_index] + # Verify that the slot is the same + assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot + # Verify that the shard is the same (or that both proposals are beacon chain proposals) + assert proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard + # But the roots are different! + assert proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root + # Proposer is not yet slashed + assert proposer.slashed is False + # Signatures are valid + for proposal in (proposer_slashing.proposal_1, proposer_slashing.proposal_2): + assert bls_verify( + pubkey=proposer.pubkey, + message_hash=signed_root(proposal, "signature"), + signature=proposal.signature, + domain=get_domain(state.fork, slot_to_epoch(proposal.slot), DOMAIN_PROPOSAL) + ) + slash_validator(state, proposer_slashing.proposer_index) +``` ##### Attester slashings Verify that `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS`. -For each `attester_slashing` in `block.body.attester_slashings`: +For each `attester_slashing` in `block.body.attester_slashings`, run the following function: -* Let `slashable_attestation_1 = attester_slashing.slashable_attestation_1`. -* Let `slashable_attestation_2 = attester_slashing.slashable_attestation_2`. -* Verify that `slashable_attestation_1.data != slashable_attestation_2.data`. -* Verify that `is_double_vote(slashable_attestation_1.data, slashable_attestation_2.data)` or `is_surround_vote(slashable_attestation_1.data, slashable_attestation_2.data)`. -* Verify that `verify_slashable_attestation(state, slashable_attestation_1)`. -* Verify that `verify_slashable_attestation(state, slashable_attestation_2)`. -* Let `slashable_indices = [index for index in slashable_attestation_1.validator_indices if index in slashable_attestation_2.validator_indices and state.validator_registry[index].slashed is False]`. -* Verify that `len(slashable_indices) >= 1`. -* Run `slash_validator(state, index)` for each `index` in `slashable_indices`. +```python +def process_attester_slashing(attester_slashing: ProposerSlashing, + state: BeaconState): + attestation1 = attester_slashing.slashable_attestation_1 + attestation2 = attester_slashing.slashable_attestation_2 + # Check that the attestations are conflicting + assert attestation1.data != attestation2.data + assert ( + is_double_vote(attestation1.data, attestation2.data) or + is_surround_vote(attestation1.data, attestation2.data) + ) + assert verify_slashable_attestation(state, attestation1) + assert verify_slashable_attestation(state, attestation2) + slashable_indices = [ + index for index in attestation1.validator_indices if + index in attestation2.validator_indices and state.validator_registry[index].slashed is False + ] + assert len(slashable_indices) >= 1 + for index in slashable_indices: + slash_validator(state, index) +``` ##### Attestations Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`. -For each `attestation` in `block.body.attestations`: - -* Verify that `attestation.data.slot >= GENESIS_SLOT`. -* Verify that `attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot`. -* Verify that `state.slot < attestation.data.slot + SLOTS_PER_EPOCH. -* Verify that `attestation.data.justified_epoch` is equal to `state.justified_epoch if slot_to_epoch(attestation.data.slot + 1) >= get_current_epoch(state) else state.previous_justified_epoch`. -* Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, get_epoch_start_slot(attestation.data.justified_epoch))`. -* Verify that either (i) `state.latest_crosslinks[attestation.data.shard] == attestation.data.latest_crosslink` or (ii) `state.latest_crosslinks[attestation.data.shard] == Crosslink(crosslink_data_root=attestation.data.crosslink_data_root, epoch=slot_to_epoch(attestation.data.slot))`. -* Verify bitfields and aggregate signature: +For each `attestation` in `block.body.attestations`, , run the following function: ```python - assert attestation.custody_bitfield == b'\x00' * len(attestation.custody_bitfield) # [TO BE REMOVED IN PHASE 1] +def process_attestation(attestation: Attestation, state: BeaconState): + # Can't submit attestations that are too far in history (or in prehistory) + assert attestation.data.slot >= GENESIS_SLOT + state.slot < attestation.data.slot + SLOTS_PER_EPOCH + # Can't submit attestations too quickly + attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot + # Verify that the justified epoch is correct, case 1: current epoch attestations + if slot_to_epoch(attestation.data.slot + 1) >= get_current_epoch(state): + assert attestation.data.justified_epoch == state.justified_epoch + # Case 2: previous epoch attestations + else: + 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) + ) + # Check that the crosslink data is valid + assert ( + # Case 1: Latest crosslink matches the one in the state + state.latest_crosslinks[attestation.data.shard] == attestation.data.latest_crosslink or + # Case 2: State has already been updated, state's latest crosslink matches the crosslink + # the attestation is trying to create + state.latest_crosslinks[attestation.data.shard] == Crosslink( + crosslink_data_root=attestation.data.crosslink_data_root, + epoch=slot_to_epoch(attestation.data.slot) + ) + ) + # Attestation must be nonempty! assert attestation.aggregation_bitfield != b'\x00' * len(attestation.aggregation_bitfield) - + # Custody must be empty (to be removed in phase 1) + assert attestation.custody_bitfield == b'\x00' * len(attestation.custody_bitfield) + # Get the committee for the specific shard that this attestation is for crosslink_committee = [ committee for committee, shard in get_crosslink_committees_at_slot(state, attestation.data.slot) if shard == attestation.data.shard ][0] + # Custody bitfield must be a subset of the attestation bitfield for i in range(len(crosslink_committee)): if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b0: assert get_bitfield_bit(attestation.custody_bitfield, i) == 0b0 - + # Verify aggregate signature participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) custody_bit_1_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) custody_bit_0_participants = [i in participants for i not in custody_bit_1_participants] @@ -1698,11 +1746,17 @@ For each `attestation` in `block.body.attestations`: signature=attestation.aggregate_signature, domain=get_domain(state.fork, slot_to_epoch(attestation.data.slot), DOMAIN_ATTESTATION), ) + # Crosslink data root is zero (to be removed in phase 1) + assert attestation.data.crosslink_data_root == ZERO_HASH + # Apply the attestation + state.latest_attestations.append(PendingAttestation( + data=attestation.data, + aggregation_bitfield=attestation.aggregation_bitfield, + custody_bitfield=attestation.custody_bitfield, + inclusion_slot=state.slot) + ) ``` -* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.crosslink_data_root == ZERO_HASH`. -* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, custody_bitfield=attestation.custody_bitfield, inclusion_slot=state.slot)` to `state.latest_attestations`. - ##### Deposits Verify that `len(block.body.deposits) <= MAX_DEPOSITS`. @@ -1741,13 +1795,25 @@ process_deposit(state, deposit) Verify that `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`. -For each `exit` in `block.body.voluntary_exits`: - -* Let `validator = state.validator_registry[exit.validator_index]`. -* Verify that `validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state))`. -* Verify that `get_current_epoch(state) >= exit.epoch`. -* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=signed_root(exit, "signature"), signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`. -* Run `initiate_validator_exit(state, exit.validator_index)`. +For each `exit` in `block.body.voluntary_exits`, run the following function: + +```python +def process_exit(exit: VoluntaryExit, state: BeaconState): + validator = state.validator_registry[exit.validator_index] + # Verify the validator has not yet exited + assert validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state)) + # Exits must specify an epoch when they become valid; they are not valid before then + assert get_current_epoch(state) >= exit.epoch + # Verify signature + assert bls_verify( + pubkey=validator.pubkey, + message_hash=signed_root(exit, "signature"), + signature=exit.signature, + domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT) + ) + # Run the exit + initiate_validator_exit(state, exit.validator_index) +``` ##### Transfers @@ -1755,18 +1821,40 @@ Note: Transfers are a temporary functionality for phases 0 and 1, to be removed Verify that `len(block.body.transfers) <= MAX_TRANSFERS` and that all transfers are distinct. -For each `transfer` in `block.body.transfers`: - -* Verify that `state.validator_balances[transfer.from] >= transfer.amount`. -* Verify that `state.validator_balances[transfer.from] >= transfer.fee`. -* Verify that `state.validator_balances[transfer.from] == transfer.amount + transfer.fee` or `state.validator_balances[transfer.from] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT`. -* Verify that `state.slot == transfer.slot`. -* Verify that `get_current_epoch(state) >= state.validator_registry[transfer.from].withdrawable_epoch` or `state.validator_registry[transfer.from].activation_epoch == FAR_FUTURE_EPOCH`. -* Verify that `state.validator_registry[transfer.from].withdrawal_credentials == BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:]`. -* Verify that `bls_verify(pubkey=transfer.pubkey, message_hash=signed_root(transfer, "signature"), signature=transfer.signature, domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER))`. -* Set `state.validator_balances[transfer.from] -= transfer.amount + transfer.fee`. -* Set `state.validator_balances[transfer.to] += transfer.amount`. -* Set `state.validator_balances[get_beacon_proposer_index(state, state.slot)] += transfer.fee`. +For each `transfer` in `block.body.transfers`, run the following function: + +```python +def process_exit(transfer: Transfer, state: BeaconState): + # Verify that we have enough ETH to send, and that after the transfer the balance will be either + # exactly zero or at least MIN_DEPOSIT_AMOUNT + assert ( + state.validator_balances[transfer.from] == transfer.amount + transfer.fee or + state.validator_balances[transfer.from] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT + ) + # A transfer is valid in only one slot + assert state.slot == transfer.slot + # Only withdrawn or not-yet-deposited accounts can transfer + assert ( + get_current_epoch(state) >= state.validator_registry[transfer.from].withdrawable_epoch or + state.validator_registry[transfer.from].activation_epoch == FAR_FUTURE_EPOCH + ) + # Verify that the pubkey is valid + assert ( + state.validator_registry[transfer.from].withdrawal_credentials == + BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:] + ) + # Verify that the signature is valid + assert bls_verify( + pubkey=transfer.pubkey, + message_hash=signed_root(transfer, "signature"), + signature=transfer.signature, + domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER) + ) + # Process the transfer + state.validator_balances[transfer.from] -= transfer.amount + transfer.fee + state.validator_balances[transfer.to] += transfer.amount + state.validator_balances[get_beacon_proposer_index(state, state.slot)] += transfer.fee +``` ### Per-epoch processing From 5ed0f276f6b183d30e8b34428cff4d59918e00a6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:13:59 -0600 Subject: [PATCH 02/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e179ec43a8..dfca7ffe81 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1686,7 +1686,7 @@ def process_attester_slashing(attester_slashing: ProposerSlashing, Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`. -For each `attestation` in `block.body.attestations`, , run the following function: +For each `attestation` in `block.body.attestations`, run the following function: ```python def process_attestation(attestation: Attestation, state: BeaconState): From 0fb4cae2d62a04920709a626a48369665594b120 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:15:49 -0600 Subject: [PATCH 03/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index dfca7ffe81..719afd0792 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1694,7 +1694,7 @@ def process_attestation(attestation: Attestation, state: BeaconState): assert attestation.data.slot >= GENESIS_SLOT state.slot < attestation.data.slot + SLOTS_PER_EPOCH # Can't submit attestations too quickly - attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot + assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # Verify that the justified epoch is correct, case 1: current epoch attestations if slot_to_epoch(attestation.data.slot + 1) >= get_current_epoch(state): assert attestation.data.justified_epoch == state.justified_epoch From 19665e4ca534fe17ba1253dc74ea903639f8164e Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:16:05 -0600 Subject: [PATCH 04/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 719afd0792..6c8acb7fb6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1692,7 +1692,7 @@ For each `attestation` in `block.body.attestations`, run the following function: def process_attestation(attestation: Attestation, state: BeaconState): # Can't submit attestations that are too far in history (or in prehistory) assert attestation.data.slot >= GENESIS_SLOT - state.slot < attestation.data.slot + SLOTS_PER_EPOCH + 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 From ff88d22f9aa210bbf58c4c264b1bd8201c1861d0 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Mar 2019 19:04:49 -0600 Subject: [PATCH 05/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6c8acb7fb6..b066bdccef 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1689,7 +1689,7 @@ Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`. For each `attestation` in `block.body.attestations`, run the following function: ```python -def process_attestation(attestation: Attestation, state: BeaconState): +def process_attestation(state: BeaconState, attestation: Attestation) -> None: # Can't submit attestations that are too far in history (or in prehistory) assert attestation.data.slot >= GENESIS_SLOT assert state.slot < attestation.data.slot + SLOTS_PER_EPOCH From 3d8e0f19207463daeb4bf7b67704be43cea07f96 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Mar 2019 19:04:55 -0600 Subject: [PATCH 06/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b066bdccef..9c2c84c8c1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1798,7 +1798,7 @@ Verify that `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`. For each `exit` in `block.body.voluntary_exits`, run the following function: ```python -def process_exit(exit: VoluntaryExit, state: BeaconState): +def process_exit(state: BeaconState, exit: VoluntaryExit) -> None: validator = state.validator_registry[exit.validator_index] # Verify the validator has not yet exited assert validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state)) From ec20edb80efbee9102de5de22d7530b3e0b546f0 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Mar 2019 19:05:02 -0600 Subject: [PATCH 07/10] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9c2c84c8c1..0435e9ee16 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1824,7 +1824,7 @@ Verify that `len(block.body.transfers) <= MAX_TRANSFERS` and that all transfers For each `transfer` in `block.body.transfers`, run the following function: ```python -def process_exit(transfer: Transfer, state: BeaconState): +def process_exit(state: BeaconState,transfer: Transfer) -> None: # Verify that we have enough ETH to send, and that after the transfer the balance will be either # exactly zero or at least MIN_DEPOSIT_AMOUNT assert ( From b8d1003c2cb9be86744f21776bc59ef0cd183536 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 1 Mar 2019 19:11:13 -0600 Subject: [PATCH 08/10] Updates to make HW and Danny happy --- specs/core/0_beacon-chain.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0435e9ee16..250cad6c76 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1632,8 +1632,8 @@ Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`. For each `proposer_slashing` in `block.body.proposer_slashings`, run the following function: ```python -def process_proposer_slashing(proposer_slashing: ProposerSlashing, - state: BeaconState): +def process_proposer_slashing(state: BeaconState, + proposer_slashing: ProposerSlashing): proposer = state.validator_registry[proposer_slashing.proposer_index] # Verify that the slot is the same assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot @@ -1661,8 +1661,8 @@ Verify that `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS`. For each `attester_slashing` in `block.body.attester_slashings`, run the following function: ```python -def process_attester_slashing(attester_slashing: ProposerSlashing, - state: BeaconState): +def process_attester_slashing(state: BeaconState, + attester_slashing: AttesterSlashing): attestation1 = attester_slashing.slashable_attestation_1 attestation2 = attester_slashing.slashable_attestation_2 # Check that the attestations are conflicting @@ -1674,8 +1674,11 @@ def process_attester_slashing(attester_slashing: ProposerSlashing, assert verify_slashable_attestation(state, attestation1) assert verify_slashable_attestation(state, attestation2) slashable_indices = [ - index for index in attestation1.validator_indices if - index in attestation2.validator_indices and state.validator_registry[index].slashed is False + index for index in attestation1.validator_indices + if ( + index in attestation2.validator_indices and + state.validator_registry[index].slashed is False + ) ] assert len(slashable_indices) >= 1 for index in slashable_indices: @@ -1706,16 +1709,17 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: state, get_epoch_start_slot(attestation.data.justified_epoch) ) # Check that the crosslink data is valid - assert ( + acceptable_crosslink_data = { # Case 1: Latest crosslink matches the one in the state - state.latest_crosslinks[attestation.data.shard] == attestation.data.latest_crosslink or + attestation.data.latest_crosslink, # Case 2: State has already been updated, state's latest crosslink matches the crosslink # the attestation is trying to create - state.latest_crosslinks[attestation.data.shard] == Crosslink( + Crosslink( crosslink_data_root=attestation.data.crosslink_data_root, epoch=slot_to_epoch(attestation.data.slot) ) - ) + } + assert state.latest_crosslinks[attestation.data.shard] in acceptable_crosslink_data # Attestation must be nonempty! assert attestation.aggregation_bitfield != b'\x00' * len(attestation.aggregation_bitfield) # Custody must be empty (to be removed in phase 1) @@ -1825,6 +1829,8 @@ For each `transfer` in `block.body.transfers`, run the following function: ```python def process_exit(state: BeaconState,transfer: Transfer) -> None: + # Verify the amount and fee aren't individually too big (for anti-overflow purposes) + assert state.validator_balances[transfer.from] >= max(transfer.amount, transfer.fee) # Verify that we have enough ETH to send, and that after the transfer the balance will be either # exactly zero or at least MIN_DEPOSIT_AMOUNT assert ( From 00804da13e7473f2ad1ea9fcebb621e15f78d041 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 2 Mar 2019 13:48:46 +0800 Subject: [PATCH 09/10] Fix type hinting --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 250cad6c76..adc7c6bcb4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1633,7 +1633,7 @@ For each `proposer_slashing` in `block.body.proposer_slashings`, run the followi ```python def process_proposer_slashing(state: BeaconState, - proposer_slashing: ProposerSlashing): + proposer_slashing: ProposerSlashing) -> None: proposer = state.validator_registry[proposer_slashing.proposer_index] # Verify that the slot is the same assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot @@ -1662,7 +1662,7 @@ For each `attester_slashing` in `block.body.attester_slashings`, run the followi ```python def process_attester_slashing(state: BeaconState, - attester_slashing: AttesterSlashing): + attester_slashing: AttesterSlashing) -> None: attestation1 = attester_slashing.slashable_attestation_1 attestation2 = attester_slashing.slashable_attestation_2 # Check that the attestations are conflicting @@ -1828,7 +1828,7 @@ Verify that `len(block.body.transfers) <= MAX_TRANSFERS` and that all transfers For each `transfer` in `block.body.transfers`, run the following function: ```python -def process_exit(state: BeaconState,transfer: Transfer) -> None: +def process_exit(state: BeaconState, transfer: Transfer) -> None: # Verify the amount and fee aren't individually too big (for anti-overflow purposes) assert state.validator_balances[transfer.from] >= max(transfer.amount, transfer.fee) # Verify that we have enough ETH to send, and that after the transfer the balance will be either From fa327a18ea7e2d1551e0df5b982a1e2b66ee8462 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 2 Mar 2019 13:51:48 +0800 Subject: [PATCH 10/10] Add docstring --- specs/core/0_beacon-chain.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index adc7c6bcb4..79d3577ed9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1634,6 +1634,10 @@ For each `proposer_slashing` in `block.body.proposer_slashings`, run the followi ```python def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: + """ + Process ``ProposerSlashing`` transaction. + Note that this function mutates ``state``. + """ proposer = state.validator_registry[proposer_slashing.proposer_index] # Verify that the slot is the same assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot @@ -1663,6 +1667,10 @@ For each `attester_slashing` in `block.body.attester_slashings`, run the followi ```python def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None: + """ + Process ``AttesterSlashing`` transaction. + Note that this function mutates ``state``. + """ attestation1 = attester_slashing.slashable_attestation_1 attestation2 = attester_slashing.slashable_attestation_2 # Check that the attestations are conflicting @@ -1693,6 +1701,10 @@ For each `attestation` in `block.body.attestations`, run the following function: ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: + """ + Process ``Attestation`` transaction. + Note that this function mutates ``state``. + """ # Can't submit attestations that are too far in history (or in prehistory) assert attestation.data.slot >= GENESIS_SLOT assert state.slot < attestation.data.slot + SLOTS_PER_EPOCH @@ -1803,6 +1815,10 @@ For each `exit` in `block.body.voluntary_exits`, run the following function: ```python def process_exit(state: BeaconState, exit: VoluntaryExit) -> None: + """ + Process ``VoluntaryExit`` transaction. + Note that this function mutates ``state``. + """ validator = state.validator_registry[exit.validator_index] # Verify the validator has not yet exited assert validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state)) @@ -1828,7 +1844,11 @@ Verify that `len(block.body.transfers) <= MAX_TRANSFERS` and that all transfers For each `transfer` in `block.body.transfers`, run the following function: ```python -def process_exit(state: BeaconState, transfer: Transfer) -> None: +def process_transfer(state: BeaconState, transfer: Transfer) -> None: + """ + Process ``Transfer`` transaction. + Note that this function mutates ``state``. + """ # Verify the amount and fee aren't individually too big (for anti-overflow purposes) assert state.validator_balances[transfer.from] >= max(transfer.amount, transfer.fee) # Verify that we have enough ETH to send, and that after the transfer the balance will be either