Merge branch 'dev' into mypy

This commit is contained in:
Hsiao-Wei Wang 2019-06-17 17:51:00 -04:00
commit 9af9bbf42b
No known key found for this signature in database
GPG Key ID: 95B070122902DEA4
41 changed files with 526 additions and 659 deletions

View File

@ -48,7 +48,7 @@ GENESIS_FORK_VERSION: 0x00000000
GENESIS_SLOT: 0
# 2**64 - 1
FAR_FUTURE_EPOCH: 18446744073709551615
BLS_WITHDRAWAL_PREFIX_BYTE: 0x00
BLS_WITHDRAWAL_PREFIX: 0
# Time parameters
@ -80,17 +80,17 @@ MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4
# State list lengths
# ---------------------------------------------------------------
# 2**13 (= 8,192) epochs ~36 days
LATEST_RANDAO_MIXES_LENGTH: 8192
RANDAO_MIXES_LENGTH: 8192
# 2**13 (= 8,192) epochs ~36 days
LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 8192
ACTIVE_INDEX_ROOTS_LENGTH: 8192
# 2**13 (= 8,192) epochs ~36 days
LATEST_SLASHED_EXIT_LENGTH: 8192
SLASHED_EXIT_LENGTH: 8192
# Reward and penalty quotients
# ---------------------------------------------------------------
# 2**5 (= 32)
BASE_REWARD_QUOTIENT: 32
BASE_REWARD_FACTOR: 32
# 2**9 (= 512)
WHISTLEBLOWING_REWARD_QUOTIENT: 512
# 2**3 (= 8)

View File

@ -47,7 +47,7 @@ GENESIS_FORK_VERSION: 0x00000000
GENESIS_SLOT: 0
# 2**64 - 1
FAR_FUTURE_EPOCH: 18446744073709551615
BLS_WITHDRAWAL_PREFIX_BYTE: 0x00
BLS_WITHDRAWAL_PREFIX: 0
# Time parameters
@ -58,40 +58,40 @@ SECONDS_PER_SLOT: 6
MIN_ATTESTATION_INCLUSION_DELAY: 2
# [customized] fast epochs
SLOTS_PER_EPOCH: 8
# 2**0 (= 1) epochs 6.4 minutes
# 2**0 (= 1) epochs
MIN_SEED_LOOKAHEAD: 1
# 2**2 (= 4) epochs 25.6 minutes
# 2**2 (= 4) epochs
ACTIVATION_EXIT_DELAY: 4
# [customized] higher frequency new deposits from eth1 for testing
SLOTS_PER_ETH1_VOTING_PERIOD: 16
# [customized] smaller state
SLOTS_PER_HISTORICAL_ROOT: 64
# 2**8 (= 256) epochs ~27 hours
# 2**8 (= 256) epochs
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
# 2**11 (= 2,048) epochs 9 days
# 2**11 (= 2,048) epochs
PERSISTENT_COMMITTEE_PERIOD: 2048
# 2**6 (= 64) epochs ~7 hours
# 2**6 (= 64) epochs
MAX_EPOCHS_PER_CROSSLINK: 64
# 2**2 (= 4) epochs 25.6 minutes
# 2**2 (= 4) epochs
MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4
# [customized] 2**12 (= 4,096) epochs 18 days
# [customized] 2**12 (= 4,096) epochs
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096
# State list lengths
# ---------------------------------------------------------------
# [customized] smaller state
LATEST_RANDAO_MIXES_LENGTH: 64
RANDAO_MIXES_LENGTH: 64
# [customized] smaller state
LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 64
ACTIVE_INDEX_ROOTS_LENGTH: 64
# [customized] smaller state
LATEST_SLASHED_EXIT_LENGTH: 64
SLASHED_EXIT_LENGTH: 64
# Reward and penalty quotients
# ---------------------------------------------------------------
# 2**5 (= 32)
BASE_REWARD_QUOTIENT: 32
BASE_REWARD_FACTOR: 32
# 2**9 (= 512)
WHISTLEBLOWING_REWARD_QUOTIENT: 512
# 2**3 (= 8)

File diff suppressed because one or more lines are too long

View File

@ -1,140 +1,103 @@
MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei
FULL_DEPOSIT_AMOUNT: constant(uint256) = 32000000000 # Gwei
CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = 65536 # 2**16
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
SECONDS_PER_DAY: constant(uint256) = 86400
MAX_64_BIT_VALUE: constant(uint256) = 18446744073709551615 # 2**64 - 1
MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1
PUBKEY_LENGTH: constant(uint256) = 48 # bytes
WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes
AMOUNT_LENGTH: constant(uint256) = 8 # bytes
SIGNATURE_LENGTH: constant(uint256) = 96 # bytes
MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1
Deposit: event({
pubkey: bytes[48],
withdrawal_credentials: bytes[32],
amount: bytes[8],
signature: bytes[96],
merkle_tree_index: bytes[8],
index: bytes[8],
})
Eth2Genesis: event({deposit_root: bytes32, deposit_count: bytes[8], time: bytes[8]})
zerohashes: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
branch: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
deposit_count: uint256
full_deposit_count: uint256
chainStarted: public(bool)
# Compute hashes in empty sparse Merkle tree
zero_hashes: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
@public
def __init__():
for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1):
self.zerohashes[i+1] = sha256(concat(self.zerohashes[i], self.zerohashes[i]))
self.zero_hashes[i + 1] = sha256(concat(self.zero_hashes[i], self.zero_hashes[i]))
@public
@private
@constant
def to_little_endian_64(value: uint256) -> bytes[8]:
assert value <= MAX_64_BIT_VALUE
# array access for bytes[] not currently supported in vyper so
# reversing bytes using bitwise uint256 manipulations
# Reversing bytes using bitwise uint256 manipulations
# Note: array accesses of bytes[] are not currently supported in Vyper
# Note: this function is only called when `value < 2**64`
y: uint256 = 0
x: uint256 = value
for i in range(8):
for _ in range(8):
y = shift(y, 8)
y = y + bitwise_and(x, 255)
x = shift(x, -8)
return slice(convert(y, bytes32), start=24, len=8)
@public
@constant
def get_deposit_root() -> bytes32:
root: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
node: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
size: uint256 = self.deposit_count
for h in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if bitwise_and(size, 1) == 1:
root = sha256(concat(self.branch[h], root))
for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1`
node = sha256(concat(self.branch[height], node))
else:
root = sha256(concat(root, self.zerohashes[h]))
node = sha256(concat(node, self.zero_hashes[height]))
size /= 2
return root
return node
@public
@constant
def get_deposit_count() -> bytes[8]:
return self.to_little_endian_64(self.deposit_count)
@payable
@public
def deposit(pubkey: bytes[PUBKEY_LENGTH],
withdrawal_credentials: bytes[WITHDRAWAL_CREDENTIALS_LENGTH],
signature: bytes[SIGNATURE_LENGTH]):
# Prevent edge case in computing `self.branch` when `self.deposit_count == MAX_DEPOSIT_COUNT`
# NOTE: reaching this point with the constants as currently defined is impossible due to the
# uni-directional nature of transfers from eth1 to eth2 and the total ether supply (< 130M).
# Avoid overflowing the Merkle tree (and prevent edge case in computing `self.branch`)
assert self.deposit_count < MAX_DEPOSIT_COUNT
# Validate deposit data
deposit_amount: uint256 = msg.value / as_wei_value(1, "gwei")
assert deposit_amount >= MIN_DEPOSIT_AMOUNT
assert len(pubkey) == PUBKEY_LENGTH
assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH
assert len(signature) == SIGNATURE_LENGTH
deposit_amount: uint256 = msg.value / as_wei_value(1, "gwei")
assert deposit_amount >= MIN_DEPOSIT_AMOUNT
# Emit `Deposit` log
amount: bytes[8] = self.to_little_endian_64(deposit_amount)
log.Deposit(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count))
index: uint256 = self.deposit_count
# add deposit to merkle tree
i: int128 = 0
size: uint256 = index + 1
for _ in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if bitwise_and(size, 1) == 1:
break
i += 1
size /= 2
zero_bytes_32: bytes32
pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes_32, start=0, len=16)))
# Compute `DepositData` root
zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes32, start=0, len=64 - PUBKEY_LENGTH)))
signature_root: bytes32 = sha256(concat(
sha256(slice(signature, start=0, len=64)),
sha256(concat(slice(signature, start=64, len=32), zero_bytes_32))
sha256(concat(slice(signature, start=64, len=SIGNATURE_LENGTH - 64), zero_bytes32)),
))
value: bytes32 = sha256(concat(
node: bytes32 = sha256(concat(
sha256(concat(pubkey_root, withdrawal_credentials)),
sha256(concat(
amount,
slice(zero_bytes_32, start=0, len=24),
signature_root,
))
sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)),
))
for j in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if j < i:
value = sha256(concat(self.branch[j], value))
else:
break
self.branch[i] = value
# Add `DepositData` root to Merkle tree (update a single `branch` node)
self.deposit_count += 1
log.Deposit(
pubkey,
withdrawal_credentials,
amount,
signature,
self.to_little_endian_64(index),
)
size: uint256 = self.deposit_count
for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1`
self.branch[height] = node
break
node = sha256(concat(self.branch[height], node))
size /= 2
if deposit_amount >= FULL_DEPOSIT_AMOUNT:
self.full_deposit_count += 1
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
timestamp_day_boundary: uint256 = (
as_unitless_number(block.timestamp) -
as_unitless_number(block.timestamp) % SECONDS_PER_DAY +
2 * SECONDS_PER_DAY
)
new_deposit_root: bytes32 = self.get_deposit_root()
log.Eth2Genesis(new_deposit_root,
self.to_little_endian_64(self.deposit_count),
self.to_little_endian_64(timestamp_day_boundary))
self.chainStarted = True

View File

@ -26,7 +26,6 @@ from .utils import (
# Constants
MIN_DEPOSIT_AMOUNT = 1000000000 # Gwei
FULL_DEPOSIT_AMOUNT = 32000000000 # Gwei
CHAIN_START_FULL_DEPOSIT_THRESHOLD = 65536 # 2**16
DEPOSIT_CONTRACT_TREE_DEPTH = 32
TWO_TO_POWER_OF_TREE_DEPTH = 2**DEPOSIT_CONTRACT_TREE_DEPTH
@ -63,45 +62,6 @@ def registration_contract(w3, tester):
return registration_deployed
@pytest.fixture(scope="session")
def chain_start_full_deposit_thresholds():
return [randint(1, 5), randint(6, 10), randint(11, 15)]
@pytest.fixture(params=[0, 1, 2])
def modified_registration_contract(
request,
w3,
tester,
chain_start_full_deposit_thresholds):
# Set CHAIN_START_FULL_DEPOSIT_THRESHOLD to different threshold t
registration_code = get_deposit_contract_code()
t = str(chain_start_full_deposit_thresholds[request.param])
modified_registration_code = re.sub(
r'CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant\(uint256\) = [0-9]+',
'CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = ' + t,
registration_code,
)
assert modified_registration_code != registration_code
contract_bytecode = compiler.compile_code(modified_registration_code)['bytecode']
contract_abi = compiler.mk_full_signature(modified_registration_code)
registration = w3.eth.contract(
abi=contract_abi,
bytecode=contract_bytecode)
tx_hash = registration.constructor().transact()
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
registration_deployed = w3.eth.contract(
address=tx_receipt.contractAddress,
abi=contract_abi
)
setattr(
registration_deployed,
'chain_start_full_deposit_threshold',
chain_start_full_deposit_thresholds[request.param]
)
return registration_deployed
@pytest.fixture
def assert_tx_failed(tester):
def assert_tx_failed(function_to_test, exception=eth_tester.exceptions.TransactionFailed):

View File

@ -49,28 +49,6 @@ def deposit_input():
)
@pytest.mark.parametrize(
'value,success',
[
(0, True),
(10, True),
(55555, True),
(2**64 - 1, True),
(2**64, False),
]
)
def test_to_little_endian_64(registration_contract, value, success, assert_tx_failed):
call = registration_contract.functions.to_little_endian_64(value)
if success:
little_endian_64 = call.call()
assert little_endian_64 == (value).to_bytes(8, 'little')
else:
assert_tx_failed(
lambda: call.call()
)
@pytest.mark.parametrize(
'success,deposit_amount',
[
@ -151,8 +129,7 @@ def test_deposit_log(registration_contract, a0, w3, deposit_input):
assert log['withdrawal_credentials'] == deposit_input[1]
assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little')
assert log['signature'] == deposit_input[2]
assert log['merkle_tree_index'] == i.to_bytes(8, 'little')
assert log['index'] == i.to_bytes(8, 'little')
def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input):
log_filter = registration_contract.events.Deposit.createFilter(
@ -172,7 +149,7 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input
assert len(logs) == 1
log = logs[0]['args']
assert log["merkle_tree_index"] == i.to_bytes(8, 'little')
assert log["index"] == i.to_bytes(8, 'little')
deposit_data = DepositData(
pubkey=deposit_input[0],
@ -184,53 +161,3 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input
leaf_nodes.append(hash_tree_root_result)
root = compute_merkle_root(leaf_nodes)
assert root == registration_contract.functions.get_deposit_root().call()
def test_chain_start(modified_registration_contract, w3, assert_tx_failed, deposit_input):
t = getattr(modified_registration_contract, 'chain_start_full_deposit_threshold')
# CHAIN_START_FULL_DEPOSIT_THRESHOLD is set to t
min_deposit_amount = MIN_DEPOSIT_AMOUNT * eth_utils.denoms.gwei # in wei
full_deposit_amount = FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei
log_filter = modified_registration_contract.events.Eth2Genesis.createFilter(
fromBlock='latest',
)
index_not_full_deposit = randint(0, t - 1)
for i in range(t):
if i == index_not_full_deposit:
# Deposit with value below FULL_DEPOSIT_AMOUNT
modified_registration_contract.functions.deposit(
*deposit_input,
).transact({"value": min_deposit_amount})
logs = log_filter.get_new_entries()
# Eth2Genesis event should not be triggered
assert len(logs) == 0
else:
# Deposit with value FULL_DEPOSIT_AMOUNT
modified_registration_contract.functions.deposit(
*deposit_input,
).transact({"value": full_deposit_amount})
logs = log_filter.get_new_entries()
# Eth2Genesis event should not be triggered
assert len(logs) == 0
# Make 1 more deposit with value FULL_DEPOSIT_AMOUNT to trigger Eth2Genesis event
modified_registration_contract.functions.deposit(
*deposit_input,
).transact({"value": full_deposit_amount})
logs = log_filter.get_new_entries()
assert len(logs) == 1
timestamp = int(w3.eth.getBlock(w3.eth.blockNumber)['timestamp'])
timestamp_day_boundary = timestamp + (86400 - timestamp % 86400) + 86400
log = logs[0]['args']
assert log['deposit_root'] == modified_registration_contract.functions.get_deposit_root().call()
assert int.from_bytes(log['time'], byteorder='little') == timestamp_day_boundary
assert modified_registration_contract.functions.chainStarted().call() is True
# Make 1 deposit with value FULL_DEPOSIT_AMOUNT and
# check that Eth2Genesis event is not triggered
modified_registration_contract.functions.deposit(
*deposit_input,
).transact({"value": full_deposit_amount})
logs = log_filter.get_new_entries()
assert len(logs) == 0

View File

@ -134,11 +134,17 @@ def objects_to_spec(functions: Dict[str, str],
f" def __init__(self, _x: {value}) -> None:\n"
f" ...\n"
if value.startswith("uint")
# else ""
# else f"{key} = {value}\n"
else f"class {key}({value}):\n pass\n"
for key, value in custom_types.items()
]
)
)
# new_type_definitions += '\n'.join(['Bytes%s = BytesN[%s]' % (n, n) for n in byte_types])
# new_type_definitions += '\n' + '\n'.join(['Hash = Bytes32', 'BLSPubkey = Bytes48', 'BLSSignature = Bytes96'])
# new_type_definitions += \
# '\n' + '\n'.join(['''%s = NewType('%s', %s)''' % (key, key, value) for key, value in new_types.items()])
functions_spec = '\n\n'.join(functions.values())
constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants))
ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values())
@ -183,7 +189,7 @@ def dependency_order_ssz_objects(objects: Dict[str, str], custom_types: Dict[str
items = list(objects.items())
for key, value in items:
dependencies = re.findall(r'(: [A-Z][\w[]*)', value)
dependencies = map(lambda x: re.sub(r'\W|Vector|List|Container|uint\d+|Bytes\d+|bytes', '', x), dependencies)
dependencies = map(lambda x: re.sub(r'\W|Vector|List|Container|Hash|BLSPubkey|BLSSignature|uint\d+|Bytes\d+|bytes', '', x), dependencies)
for dep in dependencies:
if dep in custom_types or len(dep) == 0:
continue

View File

@ -21,7 +21,8 @@
- [Rewards and penalties](#rewards-and-penalties)
- [Max operations per block](#max-operations-per-block)
- [Signature domains](#signature-domains)
- [Data structures](#data-structures)
- [Custom types](#custom-types-1)
- [Containers](#containers)
- [Misc dependencies](#misc-dependencies)
- [`Fork`](#fork)
- [`Validator`](#validator)
@ -95,7 +96,7 @@
- [`initiate_validator_exit`](#initiate_validator_exit)
- [`slash_validator`](#slash_validator)
- [Genesis](#genesis)
- [`Eth2Genesis`](#eth2genesis)
- [Genesis trigger](#genesis-trigger)
- [Genesis state](#genesis-state)
- [Genesis block](#genesis-block)
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
@ -232,9 +233,9 @@ These configurations are updated for releases, but may be out of sync during `de
| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
### Rewards and penalties
@ -271,11 +272,25 @@ These configurations are updated for releases, but may be out of sync during `de
| `DOMAIN_VOLUNTARY_EXIT` | `4` |
| `DOMAIN_TRANSFER` | `5` |
## Data structures
## Custom types
The following data structures are defined as [SimpleSerialize (SSZ)](../simple-serialize.md) objects.
We define the following Python custom types for type hinting and readability:
The types are defined topologically to aid in facilitating an executable version of the spec.
| Name | SSZ equivalent | Description |
| - | - | - |
| `Slot` | `uint64` | a slot number |
| `Epoch` | `uint64` | an epoch number |
| `Shard` | `uint64` | a shard number |
| `ValidatorIndex` | `uint64` | a validator registry index |
| `Gwei` | `uint64` | an amount in Gwei |
| `BLSPubkey` | `Bytes48` | a BLS12-381 public key |
| `BLSSignature` | `Bytes96` | a BLS12-381 signature |
## Containers
The following types are [SimpleSerialize (SSZ)](../simple-serialize.md) containers.
*Note*: The definitions are ordered topologically to facilitate execution of the spec.
### Misc dependencies
@ -283,48 +298,35 @@ The types are defined topologically to aid in facilitating an executable version
```python
class Fork(Container):
# Previous fork version
previous_version: Version
# Current fork version
current_version: Version
# Fork epoch number
epoch: Epoch
epoch: Epoch # Epoch of latest fork
```
#### `Validator`
```python
class Validator(Container):
# BLS public key
pubkey: BLSPubkey
# Withdrawal credentials
withdrawal_credentials: Hash
# Epoch when became eligible for activation
activation_eligibility_epoch: Epoch
# Epoch when validator activated
activation_epoch: Epoch
# Epoch when validator exited
exit_epoch: Epoch
# Epoch when validator is eligible to withdraw
withdrawable_epoch: Epoch
# Was the validator slashed
withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers
effective_balance: Gwei # Balance at stake
slashed: bool
# Effective balance
effective_balance: Gwei
# Status epochs
activation_eligibility_epoch: Epoch # When criteria for activation were met
activation_epoch: Epoch
exit_epoch: Epoch
withdrawable_epoch: Epoch # When validator can withdraw or transfer funds
```
#### `Crosslink`
```python
class Crosslink(Container):
# Shard number
shard: Shard
# Crosslinking data from epochs [start....end-1]
parent_root: Hash
# Crosslinking data
start_epoch: Epoch
end_epoch: Epoch
# Root of the previous crosslink
parent_root: Hash
# Root of the crosslinked shard data since the previous crosslink
data_root: Hash
```
@ -334,13 +336,11 @@ class Crosslink(Container):
class AttestationData(Container):
# LMD GHOST vote
beacon_block_root: Hash
# FFG vote
source_epoch: Epoch
source_root: Hash
target_epoch: Epoch
target_root: Hash
# Crosslink vote
crosslink: Crosslink
```
@ -349,22 +349,17 @@ class AttestationData(Container):
```python
class AttestationDataAndCustodyBit(Container):
# Attestation data
data: AttestationData
# Custody bit
custody_bit: bool
custody_bit: bool # Challengeable bit for the custody of crosslink data
```
#### `IndexedAttestation`
```python
class IndexedAttestation(Container):
# Validator indices
custody_bit_0_indices: List[ValidatorIndex]
custody_bit_1_indices: List[ValidatorIndex]
# Attestation data
custody_bit_0_indices: List[ValidatorIndex] # Indices with custody bit equal to 0
custody_bit_1_indices: List[ValidatorIndex] # Indices with custody bit equal to 1
data: AttestationData
# Aggregate signature
signature: BLSSignature
```
@ -372,13 +367,9 @@ class IndexedAttestation(Container):
```python
class PendingAttestation(Container):
# Attester aggregation bitfield
aggregation_bitfield: bytes
# Attestation data
aggregation_bitfield: bytes # Bit set for every attesting participant within a committee
data: AttestationData
# Inclusion delay
inclusion_delay: uint64
# Proposer index
inclusion_delay: Slot
proposer_index: ValidatorIndex
```
@ -386,11 +377,8 @@ class PendingAttestation(Container):
```python
class Eth1Data(Container):
# Root of the deposit tree
deposit_root: Hash
# Total number of deposits
deposit_count: uint64
# Block hash
block_hash: Hash
```
@ -398,9 +386,7 @@ class Eth1Data(Container):
```python
class HistoricalBatch(Container):
# Block roots
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
# State roots
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
```
@ -408,13 +394,9 @@ class HistoricalBatch(Container):
```python
class DepositData(Container):
# BLS pubkey
pubkey: BLSPubkey
# Withdrawal credentials
withdrawal_credentials: Hash
# Amount in Gwei
amount: Gwei
# Container self-signature
signature: BLSSignature
```
@ -435,11 +417,8 @@ class BeaconBlockHeader(Container):
```python
class ProposerSlashing(Container):
# Proposer index
proposer_index: ValidatorIndex
# First block header
header_1: BeaconBlockHeader
# Second block header
header_2: BeaconBlockHeader
```
@ -447,9 +426,7 @@ class ProposerSlashing(Container):
```python
class AttesterSlashing(Container):
# First attestation
attestation_1: IndexedAttestation
# Second attestation
attestation_2: IndexedAttestation
```
@ -457,13 +434,9 @@ class AttesterSlashing(Container):
```python
class Attestation(Container):
# Attester aggregation bitfield
aggregation_bitfield: bytes
# Attestation data
data: AttestationData
# Custody bitfield
custody_bitfield: bytes
# BLS aggregate signature
signature: BLSSignature
```
@ -471,9 +444,7 @@ class Attestation(Container):
```python
class Deposit(Container):
# Branch in the deposit tree
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH]
# Data
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root
data: DepositData
```
@ -481,11 +452,8 @@ class Deposit(Container):
```python
class VoluntaryExit(Container):
# Minimum epoch for processing exit
epoch: Epoch
# Index of the exiting validator
epoch: Epoch # Earliest epoch when voluntary exit can be processed
validator_index: ValidatorIndex
# Validator signature
signature: BLSSignature
```
@ -493,20 +461,13 @@ class VoluntaryExit(Container):
```python
class Transfer(Container):
# Sender index
sender: ValidatorIndex
# Recipient index
recipient: ValidatorIndex
# Amount in Gwei
amount: Gwei
# Fee in Gwei for block proposer
fee: Gwei
# Inclusion slot
slot: Slot
# Sender withdrawal pubkey
pubkey: BLSPubkey
# Sender signature
signature: BLSSignature
slot: Slot # Slot at which transfer must be processed
pubkey: BLSPubkey # Withdrawal pubkey
signature: BLSSignature # Signature checked against withdrawal pubkey
```
### Beacon blocks
@ -516,8 +477,9 @@ class Transfer(Container):
```python
class BeaconBlockBody(Container):
randao_reveal: BLSSignature
eth1_data: Eth1Data
graffiti: Bytes32
eth1_data: Eth1Data # Eth1 data vote
graffiti: Bytes32 # Arbitrary data
# Operations
proposer_slashings: List[ProposerSlashing]
attester_slashings: List[AttesterSlashing]
attestations: List[Attestation]
@ -530,7 +492,6 @@ class BeaconBlockBody(Container):
```python
class BeaconBlock(Container):
# Header
slot: Slot
parent_root: Hash
state_root: Hash
@ -544,39 +505,43 @@ class BeaconBlock(Container):
```python
class BeaconState(Container):
# Misc
slot: Slot
# Versioning
genesis_time: uint64
fork: Fork # For versioning hard forks
# Validator registry
validator_registry: List[Validator]
slot: Slot
fork: Fork
# History
latest_block_header: BeaconBlockHeader
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
historical_roots: List[Hash]
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data]
eth1_deposit_index: uint64
# Registry
validators: List[Validator]
balances: List[Gwei]
# Randomness and committees
latest_randao_mixes: Vector[Hash, LATEST_RANDAO_MIXES_LENGTH]
latest_start_shard: Shard
# Finality
# Shuffling
start_shard: Shard
randao_mixes: Vector[Hash, RANDAO_MIXES_LENGTH]
active_index_roots: Vector[Hash, ACTIVE_INDEX_ROOTS_LENGTH] # Digests of the active registry, for light clients
# Slashings
slashed_balances: Vector[Gwei, SLASHED_EXIT_LENGTH] # Sums of the effective balances of slashed validators
# Attestations
previous_epoch_attestations: List[PendingAttestation]
current_epoch_attestations: List[PendingAttestation]
previous_justified_epoch: Epoch
# Crosslinks
previous_crosslinks: Vector[Crosslink, SHARD_COUNT] # Previous epoch snapshot
current_crosslinks: Vector[Crosslink, SHARD_COUNT]
# Justification
previous_justified_epoch: Epoch # Previous epoch snapshot
previous_justified_root: Hash # Previous epoch snapshot
current_justified_epoch: Epoch
previous_justified_root: Hash
current_justified_root: Hash
justification_bitfield: uint64
justification_bitfield: uint64 # Bit set for every recent justified epoch
# Finality
finalized_epoch: Epoch
finalized_root: Hash
# Recent state
current_crosslinks: Vector[Crosslink, SHARD_COUNT]
previous_crosslinks: Vector[Crosslink, SHARD_COUNT]
latest_block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
latest_state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
latest_active_index_roots: Vector[Hash, LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
latest_slashed_balances: Vector[Gwei, LATEST_SLASHED_EXIT_LENGTH]
latest_block_header: BeaconBlockHeader
historical_roots: List[Hash]
# Ethereum 1.0 chain data
latest_eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data]
deposit_index: uint64
```
## Helper functions
@ -683,7 +648,7 @@ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[Valid
"""
Get active validator indices at ``epoch``.
"""
return [ValidatorIndex(i) for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)]
return [ValidatorIndex(i) for i, v in enumerate(state.validators) if is_active_validator(v, epoch)]
```
### `increase_balance`
@ -728,7 +693,7 @@ def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int:
```python
def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
"""
Return the number of shards to increment ``state.latest_start_shard`` during ``epoch``.
Return the number of shards to increment ``state.start_shard`` during ``epoch``.
"""
return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
```
@ -739,7 +704,7 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
assert epoch <= get_current_epoch(state) + 1
check_epoch = get_current_epoch(state) + 1
shard = Shard((state.latest_start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT)
shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT)
while check_epoch > epoch:
check_epoch -= 1
shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, Epoch(check_epoch))) % SHARD_COUNT)
@ -764,7 +729,7 @@ def get_block_root_at_slot(state: BeaconState,
Return the block root at a recent ``slot``.
"""
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
```
### `get_block_root`
@ -785,9 +750,9 @@ def get_randao_mix(state: BeaconState,
epoch: Epoch) -> Hash:
"""
Return the randao mix at a recent ``epoch``.
``epoch`` expected to be between (current_epoch - LATEST_RANDAO_MIXES_LENGTH, current_epoch].
``epoch`` expected to be between (current_epoch - RANDAO_MIXES_LENGTH, current_epoch].
"""
return state.latest_randao_mixes[epoch % LATEST_RANDAO_MIXES_LENGTH]
return state.randao_mixes[epoch % RANDAO_MIXES_LENGTH]
```
### `get_active_index_root`
@ -798,9 +763,9 @@ def get_active_index_root(state: BeaconState,
"""
Return the index root at a recent ``epoch``.
``epoch`` expected to be between
(current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
(current_epoch - ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY].
"""
return state.latest_active_index_roots[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
return state.active_index_roots[epoch % ACTIVE_INDEX_ROOTS_LENGTH]
```
### `generate_seed`
@ -812,7 +777,7 @@ def generate_seed(state: BeaconState,
Generate a seed for the given ``epoch``.
"""
return hash(
get_randao_mix(state, Epoch(epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD)) +
get_randao_mix(state, Epoch(epoch + RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD)) +
get_active_index_root(state, epoch) +
int_to_bytes(epoch, length=32)
)
@ -836,7 +801,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
while True:
candidate_index = first_committee[(epoch + i) % len(first_committee)]
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
effective_balance = state.validator_registry[candidate_index].effective_balance
effective_balance = state.validators[candidate_index].effective_balance
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
return ValidatorIndex(candidate_index)
i += 1
@ -862,7 +827,7 @@ def verify_merkle_branch(leaf: Hash, proof: List[Hash], depth: int, index: int,
### `get_shuffled_index`
```python
def get_shuffled_index(index: int, index_count: int, seed: Hash) -> ValidatorIndex:
def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Hash) -> ValidatorIndex:
"""
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
"""
@ -873,9 +838,12 @@ def get_shuffled_index(index: int, index_count: int, seed: Hash) -> ValidatorInd
# See the 'generalized domain' algorithm on page 3
for current_round in range(SHUFFLE_ROUND_COUNT):
pivot = bytes_to_int(hash(seed + int_to_bytes(current_round, length=1))[0:8]) % index_count
flip = (pivot + index_count - index) % index_count
flip = ValidatorIndex((pivot + index_count - index) % index_count)
position = max(index, flip)
source = hash(seed + int_to_bytes(current_round, length=1) + int_to_bytes(position // 256, length=4))
source = hash(
seed + int_to_bytes(current_round, length=1) +
int_to_bytes(ValidatorIndex(position // 256), length=4)
)
byte = source[(position % 256) // 8]
bit = (byte >> (position % 8)) % 2
index = flip if bit else index
@ -939,7 +907,7 @@ def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei
"""
Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
"""
return Gwei(max(sum([state.validator_registry[index].effective_balance for index in indices]), 1))
return Gwei(max(sum([state.validators[index].effective_balance for index in indices]), 1))
```
### `get_domain`
@ -993,6 +961,7 @@ def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedA
"""
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield)
custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bitfield)
assert set(custody_bit_1_indices).issubset(attesting_indices)
custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices]
return IndexedAttestation(
@ -1024,8 +993,8 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
# Verify aggregate signature
assert bls_verify_multiple(
pubkeys=[
bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_0_indices]),
bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_1_indices]),
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_0_indices]),
bls_aggregate_pubkeys([state.validators[i].pubkey for i in bit_1_indices]),
],
message_hashes=[
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
@ -1114,14 +1083,14 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
Initiate the exit of the validator of the given ``index``.
"""
# Return if validator already initiated exit
validator = state.validator_registry[index]
validator = state.validators[index]
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
# Compute exit queue epoch
exit_epochs = [v.exit_epoch for v in state.validator_registry if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_queue_epoch = max(exit_epochs + [get_delayed_activation_exit_epoch(get_current_epoch(state))])
exit_queue_churn = len([v for v in state.validator_registry if v.exit_epoch == exit_queue_epoch])
exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
if exit_queue_churn >= get_churn_limit(state):
exit_queue_epoch += Epoch(1)
@ -1141,10 +1110,10 @@ def slash_validator(state: BeaconState,
"""
current_epoch = get_current_epoch(state)
initiate_validator_exit(state, slashed_index)
state.validator_registry[slashed_index].slashed = True
state.validator_registry[slashed_index].withdrawable_epoch = Epoch(current_epoch + LATEST_SLASHED_EXIT_LENGTH)
slashed_balance = state.validator_registry[slashed_index].effective_balance
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance
state.validators[slashed_index].slashed = True
state.validators[slashed_index].withdrawable_epoch = Epoch(current_epoch + SLASHED_EXIT_LENGTH)
slashed_balance = state.validators[slashed_index].effective_balance
state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH] += slashed_balance
proposer_index = get_beacon_proposer_index(state)
if whistleblower_index is None:
@ -1158,26 +1127,51 @@ def slash_validator(state: BeaconState,
## Genesis
### `Eth2Genesis`
### Genesis trigger
When enough deposits of size `MAX_EFFECTIVE_BALANCE` have been made to the deposit contract an `Eth2Genesis` log is emitted triggering the genesis of the beacon chain. Let:
Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool` where:
* `eth2genesis` be the object corresponding to `Eth2Genesis`
* `genesis_eth1_data` be object of type `Eth1Data` where
* `genesis_eth1_data.deposit_root = eth2genesis.deposit_root`
* `genesis_eth1_data.deposit_count = eth2genesis.deposit_count`
* `genesis_eth1_data.block_hash` is the hash of the Ethereum 1.0 block that emitted the `Eth2Genesis` log
* `genesis_deposits` be the object of type `List[Deposit]` with deposits ordered chronologically up to and including the deposit that triggered the `Eth2Genesis` log
* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log
* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log
When `is_genesis_trigger(deposits, timestamp) is True` for the first time let:
* `genesis_deposits = deposits`
* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400`
* `genesis_eth1_data` be the object of type `Eth1Data` where:
* `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits`
* `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits`
* `genesis_eth1_data.deposit_count = len(genesis_deposits)`
*Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder:
```python
def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool:
# Process deposits
state = BeaconState()
for deposit in deposits:
process_deposit(state, deposit)
# Count active validators at genesis
active_validator_count = 0
for validator in state.validator_registry:
if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
active_validator_count += 1
# Check effective balance to trigger genesis
GENESIS_ACTIVE_VALIDATOR_COUNT = 2**16
return active_validator_count == GENESIS_ACTIVE_VALIDATOR_COUNT
```
### Genesis state
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, eth2genesis.genesis_time, genesis_eth1_data)`.
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)`.
```python
def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState:
state = BeaconState(
genesis_time=genesis_time,
latest_eth1_data=genesis_eth1_data,
eth1_data=genesis_eth1_data,
latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
)
@ -1186,15 +1180,15 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis
process_deposit(state, deposit)
# Process genesis activations
for validator in state.validator_registry:
for validator in state.validators:
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = GENESIS_EPOCH
validator.activation_epoch = GENESIS_EPOCH
# Populate latest_active_index_roots
# Populate active_index_roots
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH))
for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
state.latest_active_index_roots[index] = genesis_active_index_root
for index in range(ACTIVE_INDEX_ROOTS_LENGTH):
state.active_index_roots[index] = genesis_active_index_root
return state
```
@ -1235,7 +1229,7 @@ def process_slots(state: BeaconState, slot: Slot) -> None:
def process_slot(state: BeaconState) -> None:
# Cache state root
previous_state_root = hash_tree_root(state)
state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
# Cache latest block header state root
if state.latest_block_header.state_root == ZERO_HASH:
@ -1243,12 +1237,12 @@ def process_slot(state: BeaconState) -> None:
# Cache block root
previous_block_root = signing_root(state.latest_block_header)
state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
```
### Epoch processing
Note: the `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
*Note*: the `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
```python
def process_epoch(state: BeaconState) -> None:
@ -1298,7 +1292,7 @@ def get_unslashed_attesting_indices(state: BeaconState,
output = set() # type: Set[ValidatorIndex]
for a in attestations:
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield))
return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output)))
return sorted(filter(lambda index: not state.validators[index].slashed, list(output)))
```
```python
@ -1393,7 +1387,7 @@ def process_crosslinks(state: BeaconState) -> None:
```python
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
total_balance = get_total_active_balance(state)
effective_balance = state.validator_registry[index].effective_balance
effective_balance = state.validators[index].effective_balance
return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH)
```
@ -1401,10 +1395,10 @@ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
previous_epoch = get_previous_epoch(state)
total_balance = get_total_active_balance(state)
rewards = [Gwei(0) for index in range(len(state.validator_registry))]
penalties = [Gwei(0) for index in range(len(state.validator_registry))]
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
eligible_validator_indices = [
ValidatorIndex(index) for index, v in enumerate(state.validator_registry)
ValidatorIndex(index) for index, v in enumerate(state.validators)
if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch)
]
@ -1442,7 +1436,7 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
if index not in matching_target_attesting_indices:
penalties[index] += Gwei(
state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT
)
return rewards, penalties
@ -1450,8 +1444,8 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
```python
def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
rewards = [Gwei(0) for index in range(len(state.validator_registry))]
penalties = [Gwei(0) for index in range(len(state.validator_registry))]
rewards = [Gwei(0) for index in range(len(state.validators))]
penalties = [Gwei(0) for index in range(len(state.validators))]
epoch = get_previous_epoch(state)
for offset in range(get_epoch_committee_count(state, epoch)):
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
@ -1475,7 +1469,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
rewards1, penalties1 = get_attestation_deltas(state)
rewards2, penalties2 = get_crosslink_deltas(state)
for index in range(len(state.validator_registry)):
for index in range(len(state.validators)):
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index])
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index])
```
@ -1485,7 +1479,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
```python
def process_registry_updates(state: BeaconState) -> None:
# Process activation eligibility and ejections
for index, validator in enumerate(state.validator_registry):
for index, validator in enumerate(state.validators):
if (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
validator.effective_balance >= MAX_EFFECTIVE_BALANCE
@ -1497,13 +1491,13 @@ def process_registry_updates(state: BeaconState) -> None:
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
activation_queue = sorted([
index for index, validator in enumerate(state.validator_registry) if
index for index, validator in enumerate(state.validators) if
validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and
validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch)
], key=lambda index: state.validator_registry[index].activation_eligibility_epoch)
], key=lambda index: state.validators[index].activation_eligibility_epoch)
# Dequeued validators for activation up to churn limit (without resetting activation epoch)
for index in activation_queue[:get_churn_limit(state)]:
validator = state.validator_registry[index]
validator = state.validators[index]
if validator.activation_epoch == FAR_FUTURE_EPOCH:
validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
```
@ -1516,12 +1510,12 @@ def process_slashings(state: BeaconState) -> None:
total_balance = get_total_active_balance(state)
# Compute slashed balances in the current epoch
total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH]
total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
total_at_start = state.slashed_balances[(current_epoch + 1) % SLASHED_EXIT_LENGTH]
total_at_end = state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH]
total_penalties = total_at_end - total_at_start
for index, validator in enumerate(state.validator_registry):
if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2:
for index, validator in enumerate(state.validators):
if validator.slashed and current_epoch == validator.withdrawable_epoch - SLASHED_EXIT_LENGTH // 2:
penalty = max(
validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance,
validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT
@ -1539,29 +1533,29 @@ def process_final_updates(state: BeaconState) -> None:
if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
state.eth1_data_votes = []
# Update effective balances with hysteresis
for index, validator in enumerate(state.validator_registry):
for index, validator in enumerate(state.validators):
balance = state.balances[index]
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
# Update start shard
state.latest_start_shard = Shard((state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
# Set active index root
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH
state.latest_active_index_roots[index_root_position] = hash_tree_root(
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % ACTIVE_INDEX_ROOTS_LENGTH
state.active_index_roots[index_root_position] = hash_tree_root(
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
)
# Set total slashed balances
state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = (
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
state.slashed_balances[next_epoch % SLASHED_EXIT_LENGTH] = (
state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH]
)
# Set randao mix
state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch)
state.randao_mixes[next_epoch % RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch)
# Set historical root accumulator
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
historical_batch = HistoricalBatch(
block_roots=state.latest_block_roots,
state_roots=state.latest_state_roots,
block_roots=state.block_roots,
state_roots=state.state_roots,
)
state.historical_roots.append(hash_tree_root(historical_batch))
# Rotate current/previous epoch attestations
@ -1594,7 +1588,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
body_root=hash_tree_root(block.body),
)
# Verify proposer is not slashed
proposer = state.validator_registry[get_beacon_proposer_index(state)]
proposer = state.validators[get_beacon_proposer_index(state)]
assert not proposer.slashed
# Verify proposer signature
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
@ -1604,7 +1598,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
```python
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
proposer = state.validator_registry[get_beacon_proposer_index(state)]
proposer = state.validators[get_beacon_proposer_index(state)]
# Verify that the provided randao value is valid
assert bls_verify(
proposer.pubkey,
@ -1613,7 +1607,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
get_domain(state, DOMAIN_RANDAO),
)
# Mix it in
state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = (
state.randao_mixes[get_current_epoch(state) % RANDAO_MIXES_LENGTH] = (
xor(get_randao_mix(state, get_current_epoch(state)),
hash(body.randao_reveal))
)
@ -1625,7 +1619,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
state.eth1_data_votes.append(body.eth1_data)
if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
state.latest_eth1_data = body.eth1_data
state.eth1_data = body.eth1_data
```
#### Operations
@ -1633,7 +1627,7 @@ def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
```python
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
# Verify that outstanding deposits are processed up to the maximum number of deposits
assert len(body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index)
assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
# Verify that there are no duplicate transfers
assert len(body.transfers) == len(set(body.transfers))
all_operations = [
@ -1657,7 +1651,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla
"""
Process ``ProposerSlashing`` operation.
"""
proposer = state.validator_registry[proposer_slashing.proposer_index]
proposer = state.validators[proposer_slashing.proposer_index]
# Verify that the epoch is the same
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
# But the headers are different
@ -1689,7 +1683,7 @@ def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSla
attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices
for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)):
if is_slashable_validator(state.validator_registry[index], get_current_epoch(state)):
if is_slashable_validator(state.validators[index], get_current_epoch(state)):
slash_validator(state, index)
slashed_any = True
assert slashed_any
@ -1703,6 +1697,10 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
Process ``Attestation`` operation.
"""
data = attestation.data
assert data.crosslink.shard < SHARD_COUNT
assert data.target_epoch in (get_previous_epoch(state), get_current_epoch(state))
attestation_slot = get_attestation_data_slot(state, data)
assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
@ -1713,7 +1711,6 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
proposer_index=get_beacon_proposer_index(state),
)
assert data.target_epoch in (get_previous_epoch(state), get_current_epoch(state))
if data.target_epoch == get_current_epoch(state):
ffg_data = (state.current_justified_epoch, state.current_justified_root, get_current_epoch(state))
parent_crosslink = state.current_crosslinks[data.crosslink.shard]
@ -1744,16 +1741,16 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
leaf=hash_tree_root(deposit.data),
proof=deposit.proof,
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
index=state.deposit_index,
root=state.latest_eth1_data.deposit_root,
index=state.eth1_deposit_index,
root=state.eth1_data.deposit_root,
)
# Deposits must be processed in order
state.deposit_index += 1
state.eth1_deposit_index += 1
pubkey = deposit.data.pubkey
amount = deposit.data.amount
validator_pubkeys = [v.pubkey for v in state.validator_registry]
validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession).
# Invalid signatures are allowed by the deposit contract,
@ -1765,7 +1762,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
return
# Add validator and balance entries
state.validator_registry.append(Validator(
state.validators.append(Validator(
pubkey=pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
@ -1788,7 +1785,7 @@ def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
"""
Process ``VoluntaryExit`` operation.
"""
validator = state.validator_registry[exit.validator_index]
validator = state.validators[exit.validator_index]
# Verify the validator is active
assert is_active_validator(validator, get_current_epoch(state))
# Verify the validator has not yet exited
@ -1817,13 +1814,13 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
assert state.slot == transfer.slot
# Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE
assert (
state.validator_registry[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or
state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or
transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender]
)
# Verify that the pubkey is valid
assert (
state.validator_registry[transfer.sender].withdrawal_credentials ==
state.validators[transfer.sender].withdrawal_credentials ==
int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:]
)
# Verify that the signature is valid

View File

@ -9,15 +9,12 @@
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Constants](#constants)
- [Gwei values](#gwei-values)
- [Contract](#contract)
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
- [Arguments](#arguments)
- [`deposit` function](#deposit-function)
- [Deposit amount](#deposit-amount)
- [Withdrawal credentials](#withdrawal-credentials)
- [Amount](#amount)
- [Event logs](#event-logs)
- [`Deposit` logs](#deposit-logs)
- [`Eth2Genesis` log](#eth2genesis-log)
- [`Deposit` log](#deposit-log)
- [Vyper code](#vyper-code)
<!-- /TOC -->
@ -28,66 +25,40 @@ This document represents the specification for the beacon chain deposit contract
## Constants
### Gwei values
| Name | Value | Unit |
| - | - | - |
| `FULL_DEPOSIT_AMOUNT` | `32 * 10**9` | Gwei |
### Contract
| Name | Value |
| - | - |
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
| `CHAIN_START_FULL_DEPOSIT_THRESHOLD` | `2**16` (= 65,536) |
## Ethereum 1.0 deposit contract
The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards in Phase 2 (i.e. when the EVM 2.0 is deployed and the shards have state).
### Arguments
### `deposit` function
The deposit contract has a `deposit` function which takes the amount in Ethereum 1.0 transaction, and arguments `pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96]` corresponding to `DepositData`.
The deposit contract has a public `deposit` function to make deposits. It takes as arguments `pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96]` corresponding to a `DepositData` object.
#### Deposit amount
The amount of ETH (rounded down to the closest Gwei) sent to the deposit contract is the deposit amount, which must be of size at least `MIN_DEPOSIT_AMOUNT` Gwei. Note that ETH consumed by the deposit contract is no longer usable on Ethereum 1.0.
#### Withdrawal credentials
One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment to credentials for withdrawals to shards. The first byte of `withdrawal_credentials` is a version number. As of now, the only expected format is as follows:
One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). The first byte of `withdrawal_credentials` is a version number. As of now, the only expected format is as follows:
* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE`
* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey
The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage.
#### Amount
#### `Deposit` log
* A valid deposit amount should be at least `MIN_DEPOSIT_AMOUNT` in Gwei.
* A deposit with an amount greater than or equal to `FULL_DEPOSIT_AMOUNT` in Gwei is considered as a full deposit.
## Event logs
### `Deposit` logs
Every Ethereum 1.0 deposit, of size at least `MIN_DEPOSIT_AMOUNT`, emits a `Deposit` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract.
### `Eth2Genesis` log
When `CHAIN_START_FULL_DEPOSIT_THRESHOLD` of full deposits have been made, the deposit contract emits the `Eth2Genesis` log. The beacon chain state may then be initialized by calling the `get_genesis_beacon_state` function (defined [here](./0_beacon-chain.md#genesis-state)) where:
* `genesis_time` equals `time` in the `Eth2Genesis` log
* `latest_eth1_data.deposit_root` equals `deposit_root` in the `Eth2Genesis` log
* `latest_eth1_data.deposit_count` equals `deposit_count` in the `Eth2Genesis` log
* `latest_eth1_data.block_hash` equals the hash of the block that included the log
* `genesis_validator_deposits` is a list of `Deposit` objects built according to the `Deposit` logs up to the deposit that triggered the `Eth2Genesis` log, processed in the order in which they were emitted (oldest to newest)
Every Ethereum 1.0 deposit emits a `Deposit` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract.
## Vyper code
The source for the Vyper contract lives [here](./../../deposit_contract/contracts/validator_registration.v.py).
The deposit contract source code, written in Vyper, is available [here](https://github.com/ethereum/eth2.0-specs/blob/dev/deposit_contract/contracts/validator_registration.v.py).
*Note*: To save ~10x on gas, this contract uses a somewhat unintuitive progressive Merkle root calculation algo that requires only O(log(n)) storage. See https://github.com/ethereum/research/blob/master/beacon_chain_impl/progressive_merkle_tree.py for an implementation of the same algo in Python tested for correctness.
For convenience, we provide the interface to the contract here:
* `__init__()`: initializes the contract
* `get_deposit_root() -> bytes32`: returns the current root of the deposit tree
* `deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])`: adds a deposit instance to the deposit tree, incorporating the input arguments and the value transferred in the given call. *Note*: The amount of value transferred *must* be at least `MIN_DEPOSIT_AMOUNT`. Each of these constants are specified in units of Gwei.
*Note*: To save on gas the deposit contract uses a progressive Merkle root calculation algorithm that requires only O(log(n)) storage. See [here](https://github.com/ethereum/research/blob/master/beacon_chain_impl/progressive_merkle_tree.py) for a Python implementation, and [here](https://github.com/runtimeverification/verified-smart-contracts/blob/master/deposit/formal-incremental-merkle-tree-algorithm.pdf) for a formal correctness proof.

View File

@ -39,7 +39,7 @@ All terminology, constants, functions, and protocol mechanics defined in the [Ph
Processing the beacon chain is similar to processing the Ethereum 1.0 chain. Clients download and process blocks and maintain a view of what is the current "canonical chain", terminating at the current "head". For a beacon block, `block`, to be processed by a node, the following conditions must be met:
* The parent block with root `block.parent_root` has been processed and accepted.
* An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted.
* An Ethereum 1.0 block pointed to by the `state.eth1_data.block_hash` has been processed and accepted.
* The node's Unix time is greater than or equal to `state.genesis_time + block.slot * SECONDS_PER_SLOT`.
*Note*: Leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.
@ -69,7 +69,7 @@ def get_ancestor(store: Store, block: BeaconBlock, slot: Slot) -> BeaconBlock:
```
* Let `get_latest_attestation(store: Store, index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `index`. If several such attestations exist, use the one the validator `v` observed first.
* Let `get_latest_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, index)`.
* Let `get_attestation_target(store: Store, index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, index)`.
* Let `get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]` return the child blocks of the given `block`.
* Let `justified_head_state` be the resulting `BeaconState` object from processing the chain up to the `justified_head`.
* The `head` is `lmd_ghost(store, justified_head_state, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count.
@ -79,16 +79,16 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock)
"""
Execute the LMD-GHOST algorithm to find the head ``BeaconBlock``.
"""
validators = start_state.validator_registry
validators = start_state.validators
active_validator_indices = get_active_validator_indices(validators, slot_to_epoch(start_state.slot))
attestation_targets = [(i, get_latest_attestation_target(store, i)) for i in active_validator_indices]
attestation_targets = [(i, get_attestation_target(store, i)) for i in active_validator_indices]
# Use the rounded-balance-with-hysteresis supplied by the protocol for fork
# choice voting. This reduces the number of recomputations that need to be
# made for optimized implementations that precompute and save data
def get_vote_count(block: BeaconBlock) -> int:
return sum(
start_state.validator_registry[validator_index].effective_balance
start_state.validators[validator_index].effective_balance
for validator_index, target in attestation_targets
if get_ancestor(store, target, block.slot) == block
)

View File

@ -339,7 +339,7 @@ def process_custody_key_reveal(state: BeaconState,
Note that this function mutates ``state``.
"""
revealer = state.validator_registry[reveal.revealer_index]
revealer = state.validators[reveal.revealer_index]
epoch_to_sign = get_randao_epoch_for_custody_period(revealer.next_custody_reveal_period, reveal.revealed_index)
assert revealer.next_custody_reveal_period < get_validators_custody_reveal_period(state, reveal.revealed_index)
@ -393,8 +393,8 @@ def process_early_derived_secret_reveal(state: BeaconState,
Note that this function mutates ``state``.
"""
revealed_validator = state.validator_registry[reveal.revealed_index]
masker = state.validator_registry[reveal.masker_index]
revealed_validator = state.validators[reveal.revealed_index]
masker = state.validators[reveal.masker_index]
derived_secret_location = reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS
assert reveal.epoch >= get_current_epoch(state) + RANDAO_PENALTY_EPOCHS
@ -403,7 +403,7 @@ def process_early_derived_secret_reveal(state: BeaconState,
assert reveal.revealed_index not in state.exposed_derived_secrets[derived_secret_location]
# Verify signature correctness
masker = state.validator_registry[reveal.masker_index]
masker = state.validators[reveal.masker_index]
pubkeys = [revealed_validator.pubkey, masker.pubkey]
message_hashes = [
hash_tree_root(reveal.epoch),
@ -469,7 +469,7 @@ def process_chunk_challenge(state: BeaconState,
validate_indexed_attestation(state, convert_to_indexed(state, challenge.attestation))
# Verify it is not too late to challenge
assert slot_to_epoch(challenge.attestation.data.slot) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
responder = state.validator_registry[challenge.responder_index]
responder = state.validators[challenge.responder_index]
assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
# Verify the responder participated in the attestation
attesters = get_attesting_indices(state, challenge.attestation.data, challenge.attestation.aggregation_bitfield)
@ -511,7 +511,7 @@ def process_bit_challenge(state: BeaconState,
challenge: CustodyBitChallenge) -> None:
# Verify challenge signature
challenger = state.validator_registry[challenge.challenger_index]
challenger = state.validators[challenge.challenger_index]
assert bls_verify(
pubkey=challenger.pubkey,
message_hash=signing_root(challenge),
@ -524,7 +524,7 @@ def process_bit_challenge(state: BeaconState,
attestation = challenge.attestation
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
# Verify the attestation is eligible for challenging
responder = state.validator_registry[challenge.responder_index]
responder = state.validators[challenge.responder_index]
assert (slot_to_epoch(attestation.data.slot) + responder.max_reveal_lateness <=
get_validators_custody_reveal_period(state, challenge.responder_index))
@ -634,7 +634,7 @@ def process_bit_challenge_response(state: BeaconState,
# Verify chunk index
assert response.chunk_index < challenge.chunk_count
# Verify responder has not been slashed
responder = state.validator_registry[challenge.responder_index]
responder = state.validators[challenge.responder_index]
assert not responder.slashed
# Verify the chunk matches the crosslink data root
assert verify_merkle_branch(
@ -673,7 +673,7 @@ Run `process_reveal_deadlines(state)` immediately after `process_registry_update
process_reveal_deadlines(state)
# end insert @process_reveal_deadlines
def process_reveal_deadlines(state: BeaconState) -> None:
for index, validator in enumerate(state.validator_registry):
for index, validator in enumerate(state.validators):
deadline = validator.next_custody_reveal_period + (CUSTODY_RESPONSE_DEADLINE // EPOCHS_PER_CUSTODY_PERIOD)
if get_validators_custody_reveal_period(state, ValidatorIndex(index)) > deadline:
slash_validator(state, ValidatorIndex(index))
@ -714,7 +714,7 @@ def after_process_final_updates(state: BeaconState) -> None:
validator_indices_in_records = set(
[record.challenger_index for record in records] + [record.responder_index for record in records]
)
for index, validator in enumerate(state.validator_registry):
for index, validator in enumerate(state.validators):
if index not in validator_indices_in_records:
if validator.exit_epoch != FAR_FUTURE_EPOCH and validator.withdrawable_epoch == FAR_FUTURE_EPOCH:
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)

View File

@ -190,7 +190,7 @@ def get_shard_proposer_index(state: BeaconState,
# Search for an active proposer
for index in persistent_committee:
if is_active_validator(state.validator_registry[index], get_current_epoch(state)):
if is_active_validator(state.validators[index], get_current_epoch(state)):
return index
# No block can be proposed if no validator is active
@ -224,7 +224,7 @@ def verify_shard_attestation_signature(state: BeaconState,
pubkeys = []
for i, index in enumerate(persistent_committee):
if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b1:
validator = state.validator_registry[index]
validator = state.validators[index]
assert is_active_validator(validator, get_current_epoch(state))
pubkeys.append(validator.pubkey)
assert bls_verify(
@ -325,7 +325,7 @@ def is_valid_shard_block(beacon_blocks: List[BeaconBlock],
proposer_index = get_shard_proposer_index(beacon_state, candidate.shard, candidate.slot)
assert proposer_index is not None
assert bls_verify(
pubkey=beacon_state.validator_registry[proposer_index].pubkey,
pubkey=beacon_state.validators[proposer_index].pubkey,
message_hash=signing_root(block),
signature=candidate.signature,
domain=get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, slot_to_epoch(candidate.slot)),
@ -395,7 +395,7 @@ def is_valid_beacon_attestation(shard: Shard,
assert candidate.data.previous_attestation.epoch < slot_to_epoch(candidate.data.slot)
# Check crosslink data root
start_epoch = beacon_state.latest_crosslinks[shard].epoch
start_epoch = beacon_state.crosslinks[shard].epoch
end_epoch = min(slot_to_epoch(candidate.data.slot) - CROSSLINK_LOOKBACK, start_epoch + MAX_EPOCHS_PER_CROSSLINK)
blocks = []
for slot in range(start_epoch * SLOTS_PER_EPOCH, end_epoch * SLOTS_PER_EPOCH):

View File

@ -31,7 +31,7 @@ We define an "expansion" of an object as an object where a field in an object th
We define two expansions:
* `ExtendedBeaconState`, which is identical to a `BeaconState` except `latest_active_index_roots: List[Bytes32]` is replaced by `latest_active_indices: List[List[ValidatorIndex]]`, where `BeaconState.latest_active_index_roots[i] = hash_tree_root(ExtendedBeaconState.latest_active_indices[i])`.
* `ExtendedBeaconState`, which is identical to a `BeaconState` except `active_index_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.active_index_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`.
* `ExtendedBeaconBlock`, which is identical to a `BeaconBlock` except `state_root` is replaced with the corresponding `state: ExtendedBeaconState`.
### `get_active_validator_indices`
@ -40,10 +40,10 @@ Note that there is now a new way to compute `get_active_validator_indices`:
```python
def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]:
return state.latest_active_indices[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
return state.active_indices[epoch % ACTIVE_INDEX_ROOTS_LENGTH]
```
Note that it takes `state` instead of `state.validator_registry` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments.
Note that it takes `state` instead of `state.validators` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments.
### `MerklePartial`
@ -85,7 +85,7 @@ def get_period_data(block: ExtendedBeaconBlock, shard_id: Shard, later: bool) ->
return PeriodData(
validator_count,
generate_seed(block.state, period_start),
[block.state.validator_registry[i] for i in indices],
[block.state.validators[i] for i in indices],
)
```

View File

@ -95,8 +95,8 @@ Since some clients are waiting for `libp2p` implementations in their respective
(
network_id: uint8
chain_id: uint64
latest_finalized_root: bytes32
latest_finalized_epoch: uint64
finalized_root: bytes32
finalized_epoch: uint64
best_root: bytes32
best_slot: uint64
)
@ -107,7 +107,7 @@ Clients exchange `hello` messages upon connection, forming a two-phase handshake
Clients SHOULD immediately disconnect from one another following the handshake above under the following conditions:
1. If `network_id` belongs to a different chain, since the client definitionally cannot sync with this client.
2. If the `latest_finalized_root` shared by the peer is not in the client's chain at the expected epoch. For example, if Peer 1 in the diagram below has `(root, epoch)` of `(A, 5)` and Peer 2 has `(B, 3)`, Peer 1 would disconnect because it knows that `B` is not the root in their chain at epoch 3:
2. If the `finalized_root` shared by the peer is not in the client's chain at the expected epoch. For example, if Peer 1 in the diagram below has `(root, epoch)` of `(A, 5)` and Peer 2 has `(B, 3)`, Peer 1 would disconnect because it knows that `B` is not the root in their chain at epoch 3:
```
Root A
@ -136,7 +136,7 @@ Root B ^
+---+
```
Once the handshake completes, the client with the higher `latest_finalized_epoch` or `best_slot` (if the clients have equal `latest_finalized_epoch`s) SHOULD request beacon block roots from its counterparty via `beacon_block_roots` (i.e. RPC method `10`).
Once the handshake completes, the client with the higher `finalized_epoch` or `best_slot` (if the clients have equal `finalized_epoch`s) SHOULD request beacon block roots from its counterparty via `beacon_block_roots` (i.e. RPC method `10`).
### Goodbye

View File

@ -14,7 +14,7 @@ post: BeaconState -- state after applying the operation. No
## Condition
A handler of the `operations` test-runner should process these cases,
A handler of the `operations` test-runner should process these cases,
calling the corresponding processing implementation.
Operations:
@ -29,7 +29,7 @@ Operations:
| `transfer` | `Transfer` | `transfer` | `process_transfer(state, transfer)` |
| `voluntary_exit` | `VoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` |
Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here.
Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here.
The resulting state should match the expected `post` state, or if the `post` state is left blank,
the handler should reject the input operation as invalid.

View File

@ -101,15 +101,15 @@ To submit a deposit:
* Let `signature` be the result of `bls_sign` of the `signing_root(deposit_data)` with `domain=bls_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `bls_domain` will default to zeroes there).
* Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])` along with a deposit of `amount` Gwei.
*Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validator_registry` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`.
*Note*: Deposits made for the same `pubkey` are treated as for the same validator. A singular `Validator` will be added to `state.validators` with each additional deposit amount added to the validator's balance. A validator can only be activated when total deposits for the validator pubkey meet or exceed `MAX_EFFECTIVE_BALANCE`.
### Process deposit
Deposits cannot be processed into the beacon chain until the Eth 1.0 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth 1.0 blocks (~4 hours) plus `ETH1_DATA_VOTING_PERIOD` epochs (~1.7 hours). Once the requisite Eth 1.0 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validator_registry` within an epoch or two. The validator is then in a queue to be activated.
Deposits cannot be processed into the beacon chain until the Eth 1.0 block in which they were deposited or any of its descendants is added to the beacon chain `state.eth1_data`. This takes _a minimum_ of `ETH1_FOLLOW_DISTANCE` Eth 1.0 blocks (~4 hours) plus `ETH1_DATA_VOTING_PERIOD` epochs (~1.7 hours). Once the requisite Eth 1.0 data is added, the deposit will normally be added to a beacon chain block and processed into the `state.validators` within an epoch or two. The validator is then in a queue to be activated.
### Validator index
Once a validator has been processed and added to the beacon state's `validator_registry`, the validator's `validator_index` is defined by the index into the registry at which the [`ValidatorRecord`](../core/0_beacon-chain.md#validator) contains the `pubkey` specified in the validator's deposit. A validator's `validator_index` is guaranteed to not change from the time of initial deposit until the validator exits and fully withdraws. This `validator_index` is used throughout the specification to dictate validator roles and responsibilities at any point and should be stored locally.
Once a validator has been processed and added to the beacon state's `validators`, the validator's `validator_index` is defined by the index into the registry at which the [`ValidatorRecord`](../core/0_beacon-chain.md#validator) contains the `pubkey` specified in the validator's deposit. A validator's `validator_index` is guaranteed to not change from the time of initial deposit until the validator exits and fully withdraws. This `validator_index` is used throughout the specification to dictate validator roles and responsibilities at any point and should be stored locally.
### Activation
@ -118,7 +118,7 @@ In normal operation, the validator is quickly activated at which point the valid
The function [`is_active_validator`](../core/0_beacon-chain.md#is_active_validator) can be used to check if a validator is active during a given epoch. Usage is as follows:
```python
validator = state.validator_registry[validator_index]
validator = state.validators[validator_index]
is_active = is_active_validator(validator, get_current_epoch(state))
```
@ -147,7 +147,7 @@ def get_committee_assignment(
committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH
epoch_start_slot = get_epoch_start_slot(epoch)
for slot in range(epoch_start_slot, epoch_start_slot + SLOTS_PER_EPOCH)
for slot in range(epoch_start_slot, epoch_start_slot + SLOTS_PER_EPOCH):
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
slot_start_shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT
for i in range(committees_per_slot):
@ -221,10 +221,10 @@ epoch_signature = bls_sign(
##### Eth1 Data
`block.eth1_data` is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed, `state.latest_eth1_data` is updated, and validator deposits up to this root can be processed. The deposit root can be calculated by calling the `get_deposit_root()` function of the deposit contract using the post-state of the block hash.
`block.eth1_data` is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed, `state.eth1_data` is updated, and validator deposits up to this root can be processed. The deposit root can be calculated by calling the `get_deposit_root()` function of the deposit contract using the post-state of the block hash.
* Let `D` be the list of `Eth1DataVote` objects `vote` in `state.eth1_data_votes` where:
* `vote.eth1_data.block_hash` is the hash of an Eth 1.0 block that is (i) part of the canonical chain, (ii) >= `ETH1_FOLLOW_DISTANCE` blocks behind the head, and (iii) newer than `state.latest_eth1_data.block_hash`.
* `vote.eth1_data.block_hash` is the hash of an Eth 1.0 block that is (i) part of the canonical chain, (ii) >= `ETH1_FOLLOW_DISTANCE` blocks behind the head, and (iii) newer than `state.eth1_data.block_hash`.
* `vote.eth1_data.deposit_count` is the deposit count of the Eth 1.0 deposit contract at the block defined by `vote.eth1_data.block_hash`.
* `vote.eth1_data.deposit_root` is the deposit root of the Eth 1.0 deposit contract at the block defined by `vote.eth1_data.block_hash`.
* If `D` is empty:
@ -267,9 +267,9 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`.
##### Deposits
If there are any unprocessed deposits for the existing `state.latest_eth1_data` (i.e. `state.latest_eth1_data.deposit_count > state.deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth 1.0 deposit contract](../core/0_deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits).
If there are any unprocessed deposits for the existing `state.eth1_data` (i.e. `state.eth1_data.deposit_count > state.eth1_deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, eth1_data.deposit_count - state.eth1_deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth 1.0 deposit contract](../core/0_deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits).
The `proof` for each deposit must be constructed against the deposit root contained in `state.latest_eth1_data` rather than the deposit root at the time the deposit was initially logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `latest_eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation.
The `proof` for each deposit must be constructed against the deposit root contained in `state.eth1_data` rather than the deposit root at the time the deposit was initially logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation.
##### Voluntary exits
@ -297,11 +297,11 @@ Set `attestation_data.beacon_block_root = signing_root(head_block)`.
* Set `attestation_data.source_epoch = head_state.current_justified_epoch`.
* Set `attestation_data.source_root = head_state.current_justified_root`.
* Set `attestation_data.target_epoch = get_current_epoch(head_state)`
* Set `attestation_data.target_root = signing_root(epoch_boundary_block)` where `epoch_boundary_block` is the block at the most recent epoch boundary.
* Set `attestation_data.target_root = epoch_boundary_block_root` where `epoch_boundary_block_root` is the root of block at the most recent epoch boundary.
*Note*: `epoch_boundary_block` can be looked up in the state using:
*Note*: `epoch_boundary_block_root` can be looked up in the state using:
* Let `epoch_start_slot = get_epoch_start_slot(get_current_epoch(head_state))`.
* Let `epoch_boundary_block = head if epoch_start_slot == head_state.slot else get_block_root(state, epoch_start_slot)`.
* Let `epoch_boundary_block_root = signing_root(head_block) if epoch_start_slot == head_state.slot else get_block_root(state, epoch_start_slot)`.
##### Crosslink vote

View File

@ -2,7 +2,7 @@ from typing import Callable, Iterable
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.epoch_processing import (
from eth2spec.test.phase_0.epoch_processing import (
test_process_crosslinks,
test_process_registry_updates
)
@ -33,8 +33,10 @@ def create_suite(transition_name: str, config_name: str, get_cases: Callable[[],
if __name__ == "__main__":
gen_runner.run_generator("epoch_processing", [
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks)),
create_suite('crosslinks', 'mainnet', lambda: generate_from_tests(test_process_crosslinks)),
create_suite('registry_updates', 'minimal', lambda: generate_from_tests(test_process_registry_updates)),
create_suite('registry_updates', 'mainnet', lambda: generate_from_tests(test_process_registry_updates)),
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks, 'phase0')),
create_suite('crosslinks', 'mainnet', lambda: generate_from_tests(test_process_crosslinks, 'phase0')),
create_suite('registry_updates', 'minimal',
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
create_suite('registry_updates', 'mainnet',
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
])

View File

@ -1,13 +1,13 @@
from typing import Callable, Iterable
from eth2spec.test.block_processing import (
from eth2spec.test.phase_0.block_processing import (
test_process_attestation,
test_process_attester_slashing,
test_process_block_header,
test_process_deposit,
test_process_proposer_slashing,
test_process_transfer,
test_process_voluntary_exit
test_process_voluntary_exit,
)
from gen_base import gen_runner, gen_suite, gen_typing
@ -38,18 +38,18 @@ def create_suite(operation_name: str, config_name: str, get_cases: Callable[[],
if __name__ == "__main__":
gen_runner.run_generator("operations", [
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation)),
create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation)),
create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing)),
create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing)),
create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)),
create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)),
create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit)),
create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit)),
create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing)),
create_suite('proposer_slashing', 'mainnet', lambda: generate_from_tests(test_process_proposer_slashing)),
create_suite('transfer', 'minimal', lambda: generate_from_tests(test_process_transfer)),
create_suite('transfer', 'mainnet', lambda: generate_from_tests(test_process_transfer)),
create_suite('voluntary_exit', 'minimal', lambda: generate_from_tests(test_process_voluntary_exit)),
create_suite('voluntary_exit', 'mainnet', lambda: generate_from_tests(test_process_voluntary_exit)),
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation, 'phase0')),
create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation, 'phase0')),
create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing, 'phase0')),
create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing, 'phase0')),
create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header, 'phase0')),
create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header, 'phase0')),
create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit, 'phase0')),
create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit, 'phase0')),
create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing, 'phase0')),
create_suite('proposer_slashing', 'mainnet', lambda: generate_from_tests(test_process_proposer_slashing, 'phase0')),
create_suite('transfer', 'minimal', lambda: generate_from_tests(test_process_transfer, 'phase0')),
create_suite('transfer', 'mainnet', lambda: generate_from_tests(test_process_transfer, 'phase0')),
create_suite('voluntary_exit', 'minimal', lambda: generate_from_tests(test_process_voluntary_exit, 'phase0')),
create_suite('voluntary_exit', 'mainnet', lambda: generate_from_tests(test_process_voluntary_exit, 'phase0')),
])

View File

@ -16,7 +16,7 @@ def create_suite(handler_name: str, config_name: str, get_cases: Callable[[], It
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)
return ("%sanity_s_%s" % (handler_name, config_name), handler_name, gen_suite.render_suite(
return ("sanity_%s_%s" % (handler_name, config_name), handler_name, gen_suite.render_suite(
title="sanity testing",
summary="Sanity test suite, %s type, generated from pytests" % handler_name,
forks_timeline="testing",
@ -30,8 +30,8 @@ def create_suite(handler_name: str, config_name: str, get_cases: Callable[[], It
if __name__ == "__main__":
gen_runner.run_generator("sanity", [
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks)),
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks)),
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots)),
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots)),
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks, 'phase0')),
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks, 'phase0')),
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots, 'phase0')),
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots, 'phase0')),
])

View File

@ -1,5 +1,4 @@
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.phase0 import spec as spec
from eth_utils import (
to_dict, to_tuple
)
@ -8,7 +7,7 @@ from preset_loader import loader
@to_dict
def shuffling_case(seed: spec.Bytes32, count: int):
def shuffling_case(seed, count):
yield 'seed', '0x' + seed.hex()
yield 'count', count
yield 'shuffled', [spec.get_shuffled_index(i, count, seed) for i in range(count)]
@ -23,8 +22,7 @@ def shuffling_test_cases():
def mini_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'minimal')
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)
spec.apply_constants_preset(presets)
return ("shuffling_minimal", "core", gen_suite.render_suite(
title="Swap-or-Not Shuffling tests with minimal config",
@ -39,8 +37,7 @@ def mini_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
def full_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'mainnet')
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)
spec.apply_constants_preset(presets)
return ("shuffling_full", "core", gen_suite.render_suite(
title="Swap-or-Not Shuffling tests with mainnet config",

View File

@ -1,7 +1,10 @@
from random import Random
from inspect import getmembers, isclass
from eth2spec.debug import random_value, encode
from eth2spec.phase0 import spec
from eth2spec.utils.ssz.ssz_typing import Container
from eth2spec.utils.ssz.ssz_impl import (
hash_tree_root,
signing_root,
@ -27,17 +30,23 @@ def create_test_case_contents(value, typ):
@to_dict
def create_test_case(rng: Random, name: str, mode: random_value.RandomizationMode, chaos: bool):
typ = spec.get_ssz_type_by_name(name)
def create_test_case(rng: Random, name: str, typ, mode: random_value.RandomizationMode, chaos: bool):
value = random_value.get_random_ssz_object(rng, typ, MAX_BYTES_LENGTH, MAX_LIST_LENGTH, mode, chaos)
yield name, create_test_case_contents(value, typ)
def get_spec_ssz_types():
return [
(name, value) for (name, value) in getmembers(spec, isclass)
if issubclass(value, Container) and value != Container # only the subclasses, not the imported base class
]
@to_tuple
def ssz_static_cases(rng: Random, mode: random_value.RandomizationMode, chaos: bool, count: int):
for type_name in spec.ssz_types:
for (name, ssz_type) in get_spec_ssz_types():
for i in range(count):
yield create_test_case(rng, type_name, mode, chaos)
yield create_test_case(rng, name, ssz_type, mode, chaos)
def get_ssz_suite(seed: int, config_name: str, mode: random_value.RandomizationMode, chaos: bool, cases_if_random: int):
@ -81,8 +90,6 @@ if __name__ == "__main__":
settings.append((seed, "mainnet", random_value.RandomizationMode.mode_random, False, 5))
seed += 1
print("Settings: %d, SSZ-types: %d" % (len(settings), len(spec.ssz_types)))
gen_runner.run_generator("ssz_static", [
get_ssz_suite(seed, config_name, mode, chaos, cases_if_random)
for (seed, config_name, mode, chaos, cases_if_random) in settings

View File

@ -1,9 +1,10 @@
from inspect import getmembers, isfunction
def generate_from_tests(src, bls_active=True):
def generate_from_tests(src, phase, bls_active=True):
"""
Generate a list of test cases by running tests from the given src in generator-mode.
:param src: to retrieve tests from (discovered using inspect.getmembers)
:param src: to retrieve tests from (discovered using inspect.getmembers).
:param phase: to run tests against particular phase.
:param bls_active: optional, to override BLS switch preference. Defaults to True.
:return: the list of test cases.
"""
@ -16,7 +17,7 @@ def generate_from_tests(src, bls_active=True):
for name in fn_names:
tfn = getattr(src, name)
try:
test_case = tfn(generator_mode=True, bls_active=bls_active)
test_case = tfn(generator_mode=True, phase=phase, bls_active=bls_active)
# If no test case data is returned, the test is ignored.
if test_case is not None:
out.append(test_case)

View File

@ -116,12 +116,22 @@ def with_phases(phases):
def decorator(fn):
def run_with_spec_version(spec, *args, **kw):
kw['spec'] = spec
fn(*args, **kw)
return fn(*args, **kw)
def wrapper(*args, **kw):
if 'phase0' in phases:
run_with_spec_version(spec_phase0, *args, **kw)
if 'phase1' in phases:
run_with_spec_version(spec_phase1, *args, **kw)
run_phases = phases
# limit phases if one explicitly specified
if 'phase' in kw:
phase = kw.pop('phase')
if phase not in phases:
return
run_phases = [phase]
if 'phase0' in run_phases:
ret = run_with_spec_version(spec_phase0, *args, **kw)
if 'phase1' in run_phases:
ret = run_with_spec_version(spec_phase1, *args, **kw)
return ret
return wrapper
return decorator

View File

@ -57,7 +57,7 @@ def build_empty_block(spec, state, slot=None, signed=False):
slot = state.slot
empty_block = spec.BeaconBlock()
empty_block.slot = slot
empty_block.body.eth1_data.deposit_count = state.deposit_index
empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index
previous_block_header = deepcopy(state.latest_block_header)
if previous_block_header.state_root == spec.ZERO_HASH:
previous_block_header.state_root = state.hash_tree_root()

View File

@ -58,7 +58,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c
"""
Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount.
"""
pre_validator_count = len(state.validator_registry)
pre_validator_count = len(state.validators)
# fill previous deposits with zero-hash
deposit_data_leaves = [spec.ZERO_HASH] * pre_validator_count
@ -67,7 +67,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c
# insecurely use pubkey as withdrawal key if no credentials provided
if withdrawal_credentials is None:
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:]
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:]
deposit, root, deposit_data_leaves = build_deposit(
spec,
@ -77,9 +77,9 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c
privkey,
amount,
withdrawal_credentials,
signed
signed,
)
state.latest_eth1_data.deposit_root = root
state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
state.eth1_data.deposit_root = root
state.eth1_data.deposit_count = len(deposit_data_leaves)
return deposit

View File

@ -5,7 +5,7 @@ from eth2spec.utils.ssz.ssz_impl import hash_tree_root
def build_mock_validator(spec, i: int, balance: int):
pubkey = pubkeys[i]
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:]
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:]
return spec.Validator(
pubkey=pubkeys[i],
withdrawal_credentials=withdrawal_credentials,
@ -22,8 +22,8 @@ def create_genesis_state(spec, num_validators):
state = spec.BeaconState(
genesis_time=0,
deposit_index=num_validators,
latest_eth1_data=spec.Eth1Data(
eth1_deposit_index=num_validators,
eth1_data=spec.Eth1Data(
deposit_root=deposit_root,
deposit_count=num_validators,
block_hash=spec.ZERO_HASH,
@ -32,16 +32,16 @@ def create_genesis_state(spec, num_validators):
# We "hack" in the initial validators,
# as it is much faster than creating and processing genesis deposits for every single test case.
state.balances = [spec.MAX_EFFECTIVE_BALANCE] * num_validators
state.validator_registry = [build_mock_validator(spec, i, state.balances[i]) for i in range(num_validators)]
state.validators = [build_mock_validator(spec, i, state.balances[i]) for i in range(num_validators)]
# Process genesis activations
for validator in state.validator_registry:
for validator in state.validators:
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
validator.activation_epoch = spec.GENESIS_EPOCH
genesis_active_index_root = hash_tree_root(spec.get_active_validator_indices(state, spec.GENESIS_EPOCH))
for index in range(spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
state.latest_active_index_roots[index] = genesis_active_index_root
for index in range(spec.ACTIVE_INDEX_ROOTS_LENGTH):
state.active_index_roots[index] = genesis_active_index_root
return state

View File

@ -7,7 +7,7 @@ from eth2spec.test.helpers.keys import pubkey_to_privkey
def get_valid_proposer_slashing(spec, state, signed_1=False, signed_2=False):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
slot = state.slot
header_1 = spec.BeaconBlockHeader(

View File

@ -22,4 +22,4 @@ def get_state_root(spec, state, slot) -> bytes:
Return the state root at a recent ``slot``.
"""
assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT
return state.latest_state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT]
return state.state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT]

View File

@ -31,8 +31,8 @@ def get_valid_transfer(spec, state, slot=None, sender_index=None, amount=None, f
sign_transfer(spec, state, transfer, transfer_privkey)
# ensure withdrawal_credentials reproducible
state.validator_registry[transfer.sender].withdrawal_credentials = (
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
state.validators[transfer.sender].withdrawal_credentials = (
spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(transfer.pubkey)[1:]
)
return transfer

View File

@ -34,7 +34,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
# Process slashing
spec.process_attester_slashing(state, attester_slashing)
slashed_validator = state.validator_registry[slashed_index]
slashed_validator = state.validators[slashed_index]
# Check slashing
assert slashed_validator.slashed
@ -135,7 +135,7 @@ def test_participants_already_slashed(spec, state):
attestation_1 = attester_slashing.attestation_1
validator_indices = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
for index in validator_indices:
state.validator_registry[index].slashed = True
state.validators[index].slashed = True
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)

View File

@ -78,7 +78,7 @@ def test_proposer_slashed(spec, state):
proposer_index = spec.get_beacon_proposer_index(stub_state)
# set proposer to slashed
state.validator_registry[proposer_index].slashed = True
state.validators[proposer_index].slashed = True
block = build_empty_block_for_next_slot(spec, state, signed=True)

View File

@ -16,7 +16,7 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
pre_validator_count = len(state.validator_registry)
pre_validator_count = len(state.validators)
pre_balance = 0
if validator_index < pre_validator_count:
pre_balance = get_balance(state, validator_index)
@ -34,29 +34,29 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
yield 'post', state
if not effective:
assert len(state.validator_registry) == pre_validator_count
assert len(state.validators) == pre_validator_count
assert len(state.balances) == pre_validator_count
if validator_index < pre_validator_count:
assert get_balance(state, validator_index) == pre_balance
else:
if validator_index < pre_validator_count:
# top-up
assert len(state.validator_registry) == pre_validator_count
assert len(state.validators) == pre_validator_count
assert len(state.balances) == pre_validator_count
else:
# new validator
assert len(state.validator_registry) == pre_validator_count + 1
assert len(state.validators) == pre_validator_count + 1
assert len(state.balances) == pre_validator_count + 1
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
assert state.deposit_index == state.latest_eth1_data.deposit_count
assert state.eth1_deposit_index == state.eth1_data.deposit_count
@with_all_phases
@spec_state_test
def test_new_deposit(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validator_registry)
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
@ -68,7 +68,7 @@ def test_new_deposit(spec, state):
@spec_state_test
def test_invalid_sig_new_deposit(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validator_registry)
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
yield from run_deposit_processing(spec, state, deposit, validator_index, valid=True, effective=False)
@ -101,7 +101,7 @@ def test_invalid_sig_top_up(spec, state):
def test_invalid_withdrawal_credentials_top_up(spec, state):
validator_index = 0
amount = spec.MAX_EFFECTIVE_BALANCE // 4
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(b"junk")[1:]
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(b"junk")[1:]
deposit = prepare_state_and_deposit(
spec,
state,
@ -117,12 +117,12 @@ def test_invalid_withdrawal_credentials_top_up(spec, state):
@with_all_phases
@spec_state_test
def test_wrong_index(spec, state):
validator_index = len(state.validator_registry)
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
# mess up deposit_index
deposit.index = state.deposit_index + 1
# mess up eth1_deposit_index
deposit.index = state.eth1_deposit_index + 1
sign_deposit_data(spec, state, deposit.data, privkeys[validator_index])
@ -132,7 +132,7 @@ def test_wrong_index(spec, state):
@with_all_phases
@spec_state_test
def test_wrong_deposit_for_deposit_count(spec, state):
deposit_data_leaves = [spec.ZERO_HASH] * len(state.validator_registry)
deposit_data_leaves = [spec.ZERO_HASH] * len(state.validators)
# build root for deposit_1
index_1 = len(deposit_data_leaves)
@ -166,8 +166,8 @@ def test_wrong_deposit_for_deposit_count(spec, state):
)
# state has root for deposit_2 but is at deposit_count for deposit_1
state.latest_eth1_data.deposit_root = root_2
state.latest_eth1_data.deposit_count = deposit_count_1
state.eth1_data.deposit_root = root_2
state.eth1_data.deposit_count = deposit_count_1
yield from run_deposit_processing(spec, state, deposit_2, index_2, valid=False)
@ -178,7 +178,7 @@ def test_wrong_deposit_for_deposit_count(spec, state):
@with_all_phases
@spec_state_test
def test_bad_merkle_proof(spec, state):
validator_index = len(state.validator_registry)
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)

View File

@ -28,7 +28,7 @@ def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True)
yield 'post', state
# check if slashed
slashed_validator = state.validator_registry[proposer_slashing.proposer_index]
slashed_validator = state.validators[proposer_slashing.proposer_index]
assert slashed_validator.slashed
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
@ -77,7 +77,7 @@ def test_invalid_sig_1_and_2(spec, state):
def test_invalid_proposer_index(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
# Index just too high (by 1)
proposer_slashing.proposer_index = len(state.validator_registry)
proposer_slashing.proposer_index = len(state.validators)
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@ -111,7 +111,7 @@ def test_proposer_is_not_activated(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
# set proposer to be not active yet
state.validator_registry[proposer_slashing.proposer_index].activation_epoch = spec.get_current_epoch(state) + 1
state.validators[proposer_slashing.proposer_index].activation_epoch = spec.get_current_epoch(state) + 1
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@ -122,7 +122,7 @@ def test_proposer_is_slashed(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
# set proposer to slashed
state.validator_registry[proposer_slashing.proposer_index].slashed = True
state.validators[proposer_slashing.proposer_index].slashed = True
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
@ -137,6 +137,6 @@ def test_proposer_is_withdrawn(spec, state):
# set proposer withdrawable_epoch in past
current_epoch = spec.get_current_epoch(state)
proposer_index = proposer_slashing.proposer_index
state.validator_registry[proposer_index].withdrawable_epoch = current_epoch - 1
state.validators[proposer_index].withdrawable_epoch = current_epoch - 1
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)

View File

@ -41,7 +41,7 @@ def run_transfer_processing(spec, state, transfer, valid=True):
def test_success_non_activated(spec, state):
transfer = get_valid_transfer(spec, state, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer)
@ -55,7 +55,7 @@ def test_success_withdrawable(spec, state):
transfer = get_valid_transfer(spec, state, signed=True)
# withdrawable_epoch in past so can transfer
state.validator_registry[transfer.sender].withdrawable_epoch = spec.get_current_epoch(state) - 1
state.validators[transfer.sender].withdrawable_epoch = spec.get_current_epoch(state) - 1
yield from run_transfer_processing(spec, state, transfer)
@ -86,7 +86,7 @@ def test_success_active_above_max_effective_fee(spec, state):
def test_invalid_signature(spec, state):
transfer = get_valid_transfer(spec, state)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -107,7 +107,7 @@ def test_active_but_transfer_past_effective_balance(spec, state):
def test_incorrect_slot(spec, state):
transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -120,7 +120,7 @@ def test_insufficient_balance_for_fee(spec, state):
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -133,7 +133,7 @@ def test_insufficient_balance(spec, state):
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -153,7 +153,7 @@ def test_no_dust_sender(spec, state):
)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -167,7 +167,7 @@ def test_no_dust_recipient(spec, state):
state.balances[transfer.recipient] = 0
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@ -176,9 +176,9 @@ def test_no_dust_recipient(spec, state):
@spec_state_test
def test_invalid_pubkey(spec, state):
transfer = get_valid_transfer(spec, state, signed=True)
state.validator_registry[transfer.sender].withdrawal_credentials = spec.ZERO_HASH
state.validators[transfer.sender].withdrawal_credentials = spec.ZERO_HASH
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)

View File

@ -21,14 +21,14 @@ def run_voluntary_exit_processing(spec, state, voluntary_exit, valid=True):
yield 'post', None
return
pre_exit_epoch = state.validator_registry[validator_index].exit_epoch
pre_exit_epoch = state.validators[validator_index].exit_epoch
spec.process_voluntary_exit(state, voluntary_exit)
yield 'post', state
assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases
@ -39,7 +39,7 @@ def test_success(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(spec, state, current_epoch, validator_index, privkey, signed=True)
@ -55,7 +55,7 @@ def test_invalid_signature(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(spec, state, current_epoch, validator_index, privkey)
@ -76,7 +76,7 @@ def test_success_exit_queue(spec, state):
# Prepare a bunch of exits, based on the current state
exit_queue = []
for index in initial_indices:
privkey = pubkey_to_privkey[state.validator_registry[index].pubkey]
privkey = pubkey_to_privkey[state.validators[index].pubkey]
exit_queue.append(build_voluntary_exit(
spec,
state,
@ -94,7 +94,7 @@ def test_success_exit_queue(spec, state):
# exit an additional validator
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
spec,
state,
@ -109,8 +109,8 @@ def test_success_exit_queue(spec, state):
yield from run_voluntary_exit_processing(spec, state, voluntary_exit)
assert (
state.validator_registry[validator_index].exit_epoch ==
state.validator_registry[initial_indices[0]].exit_epoch + 1
state.validators[validator_index].exit_epoch ==
state.validators[initial_indices[0]].exit_epoch + 1
)
@ -122,7 +122,7 @@ def test_validator_exit_in_future(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
spec,
@ -146,7 +146,7 @@ def test_validator_invalid_validator_index(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
spec,
@ -156,7 +156,7 @@ def test_validator_invalid_validator_index(spec, state):
privkey,
signed=False,
)
voluntary_exit.validator_index = len(state.validator_registry)
voluntary_exit.validator_index = len(state.validators)
sign_voluntary_exit(spec, state, voluntary_exit, privkey)
yield from run_voluntary_exit_processing(spec, state, voluntary_exit, False)
@ -167,9 +167,9 @@ def test_validator_invalid_validator_index(spec, state):
def test_validator_not_active(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
# build and test voluntary exit
voluntary_exit = build_voluntary_exit(
@ -192,10 +192,10 @@ def test_validator_already_exited(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
# but validator already has exited
state.validator_registry[validator_index].exit_epoch = current_epoch + 2
state.validators[validator_index].exit_epoch = current_epoch + 2
voluntary_exit = build_voluntary_exit(
spec,
@ -214,7 +214,7 @@ def test_validator_already_exited(spec, state):
def test_validator_not_active_long_enough(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
spec,
@ -226,7 +226,7 @@ def test_validator_not_active_long_enough(spec, state):
)
assert (
current_epoch - state.validator_registry[validator_index].activation_epoch <
current_epoch - state.validators[validator_index].activation_epoch <
spec.PERSISTENT_COMMITTEE_PERIOD
)

View File

@ -35,23 +35,23 @@ def run_process_registry_updates(spec, state, valid=True):
@spec_state_test
def test_activation(spec, state):
index = 0
assert spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state))
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
# Mock a new deposit
state.validator_registry[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validator_registry[index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validator_registry[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
assert not spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state))
state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
next_epoch(spec, state)
yield from run_process_registry_updates(spec, state)
assert state.validator_registry[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validator_registry[index].activation_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(
state.validator_registry[index],
state.validators[index],
spec.get_current_epoch(state),
)
@ -60,19 +60,19 @@ def test_activation(spec, state):
@spec_state_test
def test_ejection(spec, state):
index = 0
assert spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state))
assert state.validator_registry[index].exit_epoch == spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
assert state.validators[index].exit_epoch == spec.FAR_FUTURE_EPOCH
# Mock an ejection
state.validator_registry[index].effective_balance = spec.EJECTION_BALANCE
state.validators[index].effective_balance = spec.EJECTION_BALANCE
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
next_epoch(spec, state)
yield from run_process_registry_updates(spec, state)
assert state.validator_registry[index].exit_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].exit_epoch != spec.FAR_FUTURE_EPOCH
assert not spec.is_active_validator(
state.validator_registry[index],
state.validators[index],
spec.get_current_epoch(state),
)

View File

@ -24,7 +24,7 @@ def run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, v
spec.process_early_derived_secret_reveal(state, randao_key_reveal)
slashed_validator = state.validator_registry[randao_key_reveal.revealed_index]
slashed_validator = state.validators[randao_key_reveal.revealed_index]
if randao_key_reveal.epoch >= spec.get_current_epoch(state) + spec.CUSTODY_PERIOD_TO_RANDAO_PADDING:
assert slashed_validator.slashed
@ -111,7 +111,7 @@ def test_double_reveal(spec, state):
@spec_state_test
def test_revealer_is_slashed(spec, state):
randao_key_reveal = get_valid_early_derived_secret_reveal(spec, state, spec.get_current_epoch(state))
state.validator_registry[randao_key_reveal.revealed_index].slashed = True
state.validators[randao_key_reveal.revealed_index].slashed = True
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)

View File

@ -5,7 +5,7 @@ from eth2spec.utils.ssz.ssz_impl import signing_root
from eth2spec.utils.bls import bls_sign
from eth2spec.test.helpers.state import get_balance
from eth2spec.test.helpers.transfers import get_valid_transfer
# from eth2spec.test.helpers.transfers import get_valid_transfer
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing
@ -91,7 +91,7 @@ def test_empty_epoch_transition(spec, state):
# assert state.slot == block.slot
# assert state.finalized_epoch < spec.get_current_epoch(state) - 4
# for index in range(len(state.validator_registry)):
# for index in range(len(state.validators)):
# assert get_balance(state, index) < get_balance(pre_state, index)
@ -103,7 +103,7 @@ def test_proposer_slashing(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
validator_index = proposer_slashing.proposer_index
assert not state.validator_registry[validator_index].slashed
assert not state.validators[validator_index].slashed
yield 'pre', state
@ -119,7 +119,7 @@ def test_proposer_slashing(spec, state):
yield 'post', state
# check if slashed
slashed_validator = state.validator_registry[validator_index]
slashed_validator = state.validators[validator_index]
assert slashed_validator.slashed
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
@ -137,7 +137,7 @@ def test_attester_slashing(spec, state):
validator_index = (attester_slashing.attestation_1.custody_bit_0_indices +
attester_slashing.attestation_1.custody_bit_1_indices)[0]
assert not state.validator_registry[validator_index].slashed
assert not state.validators[validator_index].slashed
yield 'pre', state
@ -152,7 +152,7 @@ def test_attester_slashing(spec, state):
spec.state_transition(state, block)
yield 'post', state
slashed_validator = state.validator_registry[validator_index]
slashed_validator = state.validators[validator_index]
assert slashed_validator.slashed
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
@ -172,10 +172,10 @@ def test_attester_slashing(spec, state):
@with_all_phases
@spec_state_test
def test_deposit_in_block(spec, state):
initial_registry_len = len(state.validator_registry)
initial_registry_len = len(state.validators)
initial_balances_len = len(state.balances)
validator_index = len(state.validator_registry)
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
@ -190,10 +190,10 @@ def test_deposit_in_block(spec, state):
spec.state_transition(state, block)
yield 'post', state
assert len(state.validator_registry) == initial_registry_len + 1
assert len(state.validators) == initial_registry_len + 1
assert len(state.balances) == initial_balances_len + 1
assert get_balance(state, validator_index) == spec.MAX_EFFECTIVE_BALANCE
assert state.validator_registry[validator_index].pubkey == pubkeys[validator_index]
assert state.validators[validator_index].pubkey == pubkeys[validator_index]
@with_all_phases
@ -203,7 +203,7 @@ def test_deposit_top_up(spec, state):
amount = spec.MAX_EFFECTIVE_BALANCE // 4
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
initial_registry_len = len(state.validator_registry)
initial_registry_len = len(state.validators)
initial_balances_len = len(state.balances)
validator_pre_balance = get_balance(state, validator_index)
@ -218,7 +218,7 @@ def test_deposit_top_up(spec, state):
spec.state_transition(state, block)
yield 'post', state
assert len(state.validator_registry) == initial_registry_len
assert len(state.validators) == initial_registry_len
assert len(state.balances) == initial_balances_len
assert get_balance(state, validator_index) == validator_pre_balance + amount
@ -289,7 +289,7 @@ def test_voluntary_exit(spec, state):
sign_block(spec, state, initiate_exit_block)
spec.state_transition(state, initiate_exit_block)
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
# Process within epoch transition
exit_block = build_empty_block_for_next_slot(spec, state)
@ -300,41 +300,41 @@ def test_voluntary_exit(spec, state):
yield 'blocks', [initiate_exit_block, exit_block], List[spec.BeaconBlock]
yield 'post', state
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases
@spec_state_test
def test_transfer(spec, state):
# @with_all_phases
# @spec_state_test
# def test_transfer(spec, state):
# overwrite default 0 to test
spec.MAX_TRANSFERS = 1
# spec.MAX_TRANSFERS = 1
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
amount = get_balance(state, sender_index)
# sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
# amount = get_balance(state, sender_index)
transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
recipient_index = transfer.recipient
pre_transfer_recipient_balance = get_balance(state, recipient_index)
# transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
# recipient_index = transfer.recipient
# pre_transfer_recipient_balance = get_balance(state, recipient_index)
# un-activate so validator can transfer
state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
# state.validators[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield 'pre', state
# yield 'pre', state
# Add to state via block transition
block = build_empty_block_for_next_slot(spec, state)
block.body.transfers.append(transfer)
sign_block(spec, state, block)
# block = build_empty_block_for_next_slot(spec, state)
# block.body.transfers.append(transfer)
# sign_block(spec, state, block)
yield 'blocks', [block], List[spec.BeaconBlock]
# yield 'blocks', [block], List[spec.BeaconBlock]
spec.state_transition(state, block)
yield 'post', state
# spec.state_transition(state, block)
# yield 'post', state
sender_balance = get_balance(state, sender_index)
recipient_balance = get_balance(state, recipient_index)
assert sender_balance == 0
assert recipient_balance == pre_transfer_recipient_balance + amount
# sender_balance = get_balance(state, sender_index)
# recipient_balance = get_balance(state, recipient_index)
# assert sender_balance == 0
# assert recipient_balance == pre_transfer_recipient_balance + amount
@with_all_phases
@ -343,10 +343,10 @@ def test_balance_driven_status_transitions(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
assert state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
# set validator balance to below ejection threshold
state.validator_registry[validator_index].effective_balance = spec.EJECTION_BALANCE
state.validators[validator_index].effective_balance = spec.EJECTION_BALANCE
yield 'pre', state
@ -359,7 +359,7 @@ def test_balance_driven_status_transitions(spec, state):
yield 'blocks', [block], List[spec.BeaconBlock]
yield 'post', state
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases

View File

@ -1,5 +1,6 @@
from typing import Dict, Any, Callable, Iterable
from eth2spec.debug.encode import encode
from eth2spec.utils.ssz.ssz_typing import Container
def spectest(description: str = None):
@ -30,9 +31,13 @@ def spectest(description: str = None):
else:
# Otherwise, try to infer the type, but keep it as-is if it's not a SSZ container.
(key, value) = data
if hasattr(value.__class__, 'fields'):
if isinstance(value, Container):
out[key] = encode(value, value.__class__)
else:
# not a ssz value.
# It could be vector or bytes still, but it is a rare case,
# and lists can't be inferred fully (generics lose element type).
# In such cases, explicitly state the type of the yielded value as a third yielded object.
out[key] = value
if has_contents:
return out

View File

@ -1,5 +1,28 @@
from hashlib import sha256
ZERO_BYTES32 = b'\x00' * 32
def _hash(x):
return sha256(x).digest()
# Minimal collection of (key, value) pairs, for fast hash-retrieval, to save on repetitive computation cost.
# Key = the hash input
# Value = the hash output
hash_cache = []
def add_zero_hashes_to_cache():
zerohashes = [(None, ZERO_BYTES32)]
for layer in range(1, 32):
k = zerohashes[layer - 1][1] + zerohashes[layer - 1][1]
zerohashes.append((k, _hash(k)))
hash_cache.extend(zerohashes[1:])
def hash(x):
return sha256(x).digest()
for (k, h) in hash_cache:
if x == k:
return h
return _hash(x)

View File

@ -534,13 +534,11 @@ def read_vector_elem_type(vector_typ: Type[Vector[T, L]]) -> T:
def read_elem_type(typ):
if typ == bytes:
if typ == bytes or (isinstance(typ, type) and issubclass(typ, bytes)): # bytes or bytesN
return byte
elif is_list_type(typ):
return read_list_elem_type(typ)
elif is_vector_type(typ):
return read_vector_elem_type(typ)
elif issubclass(typ, bytes): # bytes or bytesN
return byte
else:
raise TypeError("Unexpected type: {}".format(typ))