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).
This commit is contained in:
parent
8df7de150e
commit
d5900836aa
|
@ -1629,59 +1629,107 @@ Below are the processing steps that happen at every `block`.
|
||||||
|
|
||||||
Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`.
|
Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`.
|
||||||
|
|
||||||
For each `proposer_slashing` in `block.body.proposer_slashings`:
|
For each `proposer_slashing` in `block.body.proposer_slashings`, run the following function:
|
||||||
|
|
||||||
* Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`.
|
```python
|
||||||
* Verify that `proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot`.
|
def process_proposer_slashing(proposer_slashing: ProposerSlashing,
|
||||||
* Verify that `proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard`.
|
state: BeaconState):
|
||||||
* Verify that `proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root`.
|
proposer = state.validator_registry[proposer_slashing.proposer_index]
|
||||||
* Verify that `proposer.slashed is False`.
|
# Verify that the slot is the same
|
||||||
* 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))`.
|
assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot
|
||||||
* 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))`.
|
# Verify that the shard is the same (or that both proposals are beacon chain proposals)
|
||||||
* Run `slash_validator(state, proposer_slashing.proposer_index)`.
|
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
|
##### Attester slashings
|
||||||
|
|
||||||
Verify that `len(block.body.attester_slashings) <= MAX_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`.
|
```python
|
||||||
* Let `slashable_attestation_2 = attester_slashing.slashable_attestation_2`.
|
def process_attester_slashing(attester_slashing: ProposerSlashing,
|
||||||
* Verify that `slashable_attestation_1.data != slashable_attestation_2.data`.
|
state: BeaconState):
|
||||||
* 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)`.
|
attestation1 = attester_slashing.slashable_attestation_1
|
||||||
* Verify that `verify_slashable_attestation(state, slashable_attestation_1)`.
|
attestation2 = attester_slashing.slashable_attestation_2
|
||||||
* Verify that `verify_slashable_attestation(state, slashable_attestation_2)`.
|
# Check that the attestations are conflicting
|
||||||
* 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]`.
|
assert attestation1.data != attestation2.data
|
||||||
* Verify that `len(slashable_indices) >= 1`.
|
assert (
|
||||||
* Run `slash_validator(state, index)` for each `index` in `slashable_indices`.
|
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
|
##### Attestations
|
||||||
|
|
||||||
Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`.
|
Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`.
|
||||||
|
|
||||||
For each `attestation` in `block.body.attestations`:
|
For each `attestation` in `block.body.attestations`, , run the following function:
|
||||||
|
|
||||||
* 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:
|
|
||||||
|
|
||||||
```python
|
```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)
|
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 = [
|
crosslink_committee = [
|
||||||
committee for committee, shard in get_crosslink_committees_at_slot(state, attestation.data.slot)
|
committee for committee, shard in get_crosslink_committees_at_slot(state, attestation.data.slot)
|
||||||
if shard == attestation.data.shard
|
if shard == attestation.data.shard
|
||||||
][0]
|
][0]
|
||||||
|
# Custody bitfield must be a subset of the attestation bitfield
|
||||||
for i in range(len(crosslink_committee)):
|
for i in range(len(crosslink_committee)):
|
||||||
if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b0:
|
if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b0:
|
||||||
assert get_bitfield_bit(attestation.custody_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)
|
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_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]
|
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,
|
signature=attestation.aggregate_signature,
|
||||||
domain=get_domain(state.fork, slot_to_epoch(attestation.data.slot), DOMAIN_ATTESTATION),
|
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
|
##### Deposits
|
||||||
|
|
||||||
Verify that `len(block.body.deposits) <= MAX_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`.
|
Verify that `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`.
|
||||||
|
|
||||||
For each `exit` in `block.body.voluntary_exits`:
|
For each `exit` in `block.body.voluntary_exits`, run the following function:
|
||||||
|
|
||||||
* Let `validator = state.validator_registry[exit.validator_index]`.
|
```python
|
||||||
* Verify that `validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state))`.
|
def process_exit(exit: VoluntaryExit, state: BeaconState):
|
||||||
* Verify that `get_current_epoch(state) >= exit.epoch`.
|
validator = state.validator_registry[exit.validator_index]
|
||||||
* 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))`.
|
# Verify the validator has not yet exited
|
||||||
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
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
|
##### 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.
|
Verify that `len(block.body.transfers) <= MAX_TRANSFERS` and that all transfers are distinct.
|
||||||
|
|
||||||
For each `transfer` in `block.body.transfers`:
|
For each `transfer` in `block.body.transfers`, run the following function:
|
||||||
|
|
||||||
* Verify that `state.validator_balances[transfer.from] >= transfer.amount`.
|
```python
|
||||||
* Verify that `state.validator_balances[transfer.from] >= transfer.fee`.
|
def process_exit(transfer: Transfer, state: BeaconState):
|
||||||
* 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 we have enough ETH to send, and that after the transfer the balance will be either
|
||||||
* Verify that `state.slot == transfer.slot`.
|
# exactly zero or at least MIN_DEPOSIT_AMOUNT
|
||||||
* Verify that `get_current_epoch(state) >= state.validator_registry[transfer.from].withdrawable_epoch` or `state.validator_registry[transfer.from].activation_epoch == FAR_FUTURE_EPOCH`.
|
assert (
|
||||||
* Verify that `state.validator_registry[transfer.from].withdrawal_credentials == BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:]`.
|
state.validator_balances[transfer.from] == transfer.amount + transfer.fee or
|
||||||
* 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))`.
|
state.validator_balances[transfer.from] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT
|
||||||
* Set `state.validator_balances[transfer.from] -= transfer.amount + transfer.fee`.
|
)
|
||||||
* Set `state.validator_balances[transfer.to] += transfer.amount`.
|
# A transfer is valid in only one slot
|
||||||
* Set `state.validator_balances[get_beacon_proposer_index(state, state.slot)] += transfer.fee`.
|
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
|
### Per-epoch processing
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue