Merge branch 'dev' into mypy
This commit is contained in:
commit
9af9bbf42b
|
@ -48,7 +48,7 @@ GENESIS_FORK_VERSION: 0x00000000
|
||||||
GENESIS_SLOT: 0
|
GENESIS_SLOT: 0
|
||||||
# 2**64 - 1
|
# 2**64 - 1
|
||||||
FAR_FUTURE_EPOCH: 18446744073709551615
|
FAR_FUTURE_EPOCH: 18446744073709551615
|
||||||
BLS_WITHDRAWAL_PREFIX_BYTE: 0x00
|
BLS_WITHDRAWAL_PREFIX: 0
|
||||||
|
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
|
@ -80,17 +80,17 @@ MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4
|
||||||
# State list lengths
|
# State list lengths
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# 2**13 (= 8,192) epochs ~36 days
|
# 2**13 (= 8,192) epochs ~36 days
|
||||||
LATEST_RANDAO_MIXES_LENGTH: 8192
|
RANDAO_MIXES_LENGTH: 8192
|
||||||
# 2**13 (= 8,192) epochs ~36 days
|
# 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
|
# 2**13 (= 8,192) epochs ~36 days
|
||||||
LATEST_SLASHED_EXIT_LENGTH: 8192
|
SLASHED_EXIT_LENGTH: 8192
|
||||||
|
|
||||||
|
|
||||||
# Reward and penalty quotients
|
# Reward and penalty quotients
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# 2**5 (= 32)
|
# 2**5 (= 32)
|
||||||
BASE_REWARD_QUOTIENT: 32
|
BASE_REWARD_FACTOR: 32
|
||||||
# 2**9 (= 512)
|
# 2**9 (= 512)
|
||||||
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
||||||
# 2**3 (= 8)
|
# 2**3 (= 8)
|
||||||
|
|
|
@ -47,7 +47,7 @@ GENESIS_FORK_VERSION: 0x00000000
|
||||||
GENESIS_SLOT: 0
|
GENESIS_SLOT: 0
|
||||||
# 2**64 - 1
|
# 2**64 - 1
|
||||||
FAR_FUTURE_EPOCH: 18446744073709551615
|
FAR_FUTURE_EPOCH: 18446744073709551615
|
||||||
BLS_WITHDRAWAL_PREFIX_BYTE: 0x00
|
BLS_WITHDRAWAL_PREFIX: 0
|
||||||
|
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
|
@ -58,40 +58,40 @@ SECONDS_PER_SLOT: 6
|
||||||
MIN_ATTESTATION_INCLUSION_DELAY: 2
|
MIN_ATTESTATION_INCLUSION_DELAY: 2
|
||||||
# [customized] fast epochs
|
# [customized] fast epochs
|
||||||
SLOTS_PER_EPOCH: 8
|
SLOTS_PER_EPOCH: 8
|
||||||
# 2**0 (= 1) epochs 6.4 minutes
|
# 2**0 (= 1) epochs
|
||||||
MIN_SEED_LOOKAHEAD: 1
|
MIN_SEED_LOOKAHEAD: 1
|
||||||
# 2**2 (= 4) epochs 25.6 minutes
|
# 2**2 (= 4) epochs
|
||||||
ACTIVATION_EXIT_DELAY: 4
|
ACTIVATION_EXIT_DELAY: 4
|
||||||
# [customized] higher frequency new deposits from eth1 for testing
|
# [customized] higher frequency new deposits from eth1 for testing
|
||||||
SLOTS_PER_ETH1_VOTING_PERIOD: 16
|
SLOTS_PER_ETH1_VOTING_PERIOD: 16
|
||||||
# [customized] smaller state
|
# [customized] smaller state
|
||||||
SLOTS_PER_HISTORICAL_ROOT: 64
|
SLOTS_PER_HISTORICAL_ROOT: 64
|
||||||
# 2**8 (= 256) epochs ~27 hours
|
# 2**8 (= 256) epochs
|
||||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256
|
||||||
# 2**11 (= 2,048) epochs 9 days
|
# 2**11 (= 2,048) epochs
|
||||||
PERSISTENT_COMMITTEE_PERIOD: 2048
|
PERSISTENT_COMMITTEE_PERIOD: 2048
|
||||||
# 2**6 (= 64) epochs ~7 hours
|
# 2**6 (= 64) epochs
|
||||||
MAX_EPOCHS_PER_CROSSLINK: 64
|
MAX_EPOCHS_PER_CROSSLINK: 64
|
||||||
# 2**2 (= 4) epochs 25.6 minutes
|
# 2**2 (= 4) epochs
|
||||||
MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4
|
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
|
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096
|
||||||
|
|
||||||
|
|
||||||
# State list lengths
|
# State list lengths
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# [customized] smaller state
|
# [customized] smaller state
|
||||||
LATEST_RANDAO_MIXES_LENGTH: 64
|
RANDAO_MIXES_LENGTH: 64
|
||||||
# [customized] smaller state
|
# [customized] smaller state
|
||||||
LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 64
|
ACTIVE_INDEX_ROOTS_LENGTH: 64
|
||||||
# [customized] smaller state
|
# [customized] smaller state
|
||||||
LATEST_SLASHED_EXIT_LENGTH: 64
|
SLASHED_EXIT_LENGTH: 64
|
||||||
|
|
||||||
|
|
||||||
# Reward and penalty quotients
|
# Reward and penalty quotients
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# 2**5 (= 32)
|
# 2**5 (= 32)
|
||||||
BASE_REWARD_QUOTIENT: 32
|
BASE_REWARD_FACTOR: 32
|
||||||
# 2**9 (= 512)
|
# 2**9 (= 512)
|
||||||
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
WHISTLEBLOWING_REWARD_QUOTIENT: 512
|
||||||
# 2**3 (= 8)
|
# 2**3 (= 8)
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,140 +1,103 @@
|
||||||
MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei
|
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
|
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
|
||||||
SECONDS_PER_DAY: constant(uint256) = 86400
|
MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1
|
||||||
MAX_64_BIT_VALUE: constant(uint256) = 18446744073709551615 # 2**64 - 1
|
|
||||||
PUBKEY_LENGTH: constant(uint256) = 48 # bytes
|
PUBKEY_LENGTH: constant(uint256) = 48 # bytes
|
||||||
WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes
|
WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes
|
||||||
|
AMOUNT_LENGTH: constant(uint256) = 8 # bytes
|
||||||
SIGNATURE_LENGTH: constant(uint256) = 96 # bytes
|
SIGNATURE_LENGTH: constant(uint256) = 96 # bytes
|
||||||
MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1
|
|
||||||
|
|
||||||
Deposit: event({
|
Deposit: event({
|
||||||
pubkey: bytes[48],
|
pubkey: bytes[48],
|
||||||
withdrawal_credentials: bytes[32],
|
withdrawal_credentials: bytes[32],
|
||||||
amount: bytes[8],
|
amount: bytes[8],
|
||||||
signature: bytes[96],
|
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]
|
branch: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
|
||||||
deposit_count: uint256
|
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
|
@public
|
||||||
def __init__():
|
def __init__():
|
||||||
for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1):
|
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
|
@constant
|
||||||
def to_little_endian_64(value: uint256) -> bytes[8]:
|
def to_little_endian_64(value: uint256) -> bytes[8]:
|
||||||
assert value <= MAX_64_BIT_VALUE
|
# Reversing bytes using bitwise uint256 manipulations
|
||||||
|
# Note: array accesses of bytes[] are not currently supported in Vyper
|
||||||
# array access for bytes[] not currently supported in vyper so
|
# Note: this function is only called when `value < 2**64`
|
||||||
# reversing bytes using bitwise uint256 manipulations
|
|
||||||
y: uint256 = 0
|
y: uint256 = 0
|
||||||
x: uint256 = value
|
x: uint256 = value
|
||||||
for i in range(8):
|
for _ in range(8):
|
||||||
y = shift(y, 8)
|
y = shift(y, 8)
|
||||||
y = y + bitwise_and(x, 255)
|
y = y + bitwise_and(x, 255)
|
||||||
x = shift(x, -8)
|
x = shift(x, -8)
|
||||||
|
|
||||||
return slice(convert(y, bytes32), start=24, len=8)
|
return slice(convert(y, bytes32), start=24, len=8)
|
||||||
|
|
||||||
|
|
||||||
@public
|
@public
|
||||||
@constant
|
@constant
|
||||||
def get_deposit_root() -> bytes32:
|
def get_deposit_root() -> bytes32:
|
||||||
root: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
|
node: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
|
||||||
size: uint256 = self.deposit_count
|
size: uint256 = self.deposit_count
|
||||||
for h in range(DEPOSIT_CONTRACT_TREE_DEPTH):
|
for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
|
||||||
if bitwise_and(size, 1) == 1:
|
if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1`
|
||||||
root = sha256(concat(self.branch[h], root))
|
node = sha256(concat(self.branch[height], node))
|
||||||
else:
|
else:
|
||||||
root = sha256(concat(root, self.zerohashes[h]))
|
node = sha256(concat(node, self.zero_hashes[height]))
|
||||||
size /= 2
|
size /= 2
|
||||||
return root
|
return node
|
||||||
|
|
||||||
|
|
||||||
@public
|
@public
|
||||||
@constant
|
@constant
|
||||||
def get_deposit_count() -> bytes[8]:
|
def get_deposit_count() -> bytes[8]:
|
||||||
return self.to_little_endian_64(self.deposit_count)
|
return self.to_little_endian_64(self.deposit_count)
|
||||||
|
|
||||||
|
|
||||||
@payable
|
@payable
|
||||||
@public
|
@public
|
||||||
def deposit(pubkey: bytes[PUBKEY_LENGTH],
|
def deposit(pubkey: bytes[PUBKEY_LENGTH],
|
||||||
withdrawal_credentials: bytes[WITHDRAWAL_CREDENTIALS_LENGTH],
|
withdrawal_credentials: bytes[WITHDRAWAL_CREDENTIALS_LENGTH],
|
||||||
signature: bytes[SIGNATURE_LENGTH]):
|
signature: bytes[SIGNATURE_LENGTH]):
|
||||||
# Prevent edge case in computing `self.branch` when `self.deposit_count == MAX_DEPOSIT_COUNT`
|
# Avoid overflowing the Merkle tree (and prevent edge case in computing `self.branch`)
|
||||||
# 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).
|
|
||||||
assert self.deposit_count < MAX_DEPOSIT_COUNT
|
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(pubkey) == PUBKEY_LENGTH
|
||||||
assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH
|
assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH
|
||||||
assert len(signature) == SIGNATURE_LENGTH
|
assert len(signature) == SIGNATURE_LENGTH
|
||||||
|
|
||||||
deposit_amount: uint256 = msg.value / as_wei_value(1, "gwei")
|
# Emit `Deposit` log
|
||||||
assert deposit_amount >= MIN_DEPOSIT_AMOUNT
|
|
||||||
amount: bytes[8] = self.to_little_endian_64(deposit_amount)
|
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
|
# Compute `DepositData` root
|
||||||
|
zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
|
||||||
# add deposit to merkle tree
|
pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes32, start=0, len=64 - PUBKEY_LENGTH)))
|
||||||
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)))
|
|
||||||
signature_root: bytes32 = sha256(concat(
|
signature_root: bytes32 = sha256(concat(
|
||||||
sha256(slice(signature, start=0, len=64)),
|
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(pubkey_root, withdrawal_credentials)),
|
||||||
sha256(concat(
|
sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)),
|
||||||
amount,
|
|
||||||
slice(zero_bytes_32, start=0, len=24),
|
|
||||||
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
|
self.deposit_count += 1
|
||||||
log.Deposit(
|
size: uint256 = self.deposit_count
|
||||||
pubkey,
|
for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
|
||||||
withdrawal_credentials,
|
if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1`
|
||||||
amount,
|
self.branch[height] = node
|
||||||
signature,
|
break
|
||||||
self.to_little_endian_64(index),
|
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
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ from .utils import (
|
||||||
# Constants
|
# Constants
|
||||||
MIN_DEPOSIT_AMOUNT = 1000000000 # Gwei
|
MIN_DEPOSIT_AMOUNT = 1000000000 # Gwei
|
||||||
FULL_DEPOSIT_AMOUNT = 32000000000 # Gwei
|
FULL_DEPOSIT_AMOUNT = 32000000000 # Gwei
|
||||||
CHAIN_START_FULL_DEPOSIT_THRESHOLD = 65536 # 2**16
|
|
||||||
DEPOSIT_CONTRACT_TREE_DEPTH = 32
|
DEPOSIT_CONTRACT_TREE_DEPTH = 32
|
||||||
TWO_TO_POWER_OF_TREE_DEPTH = 2**DEPOSIT_CONTRACT_TREE_DEPTH
|
TWO_TO_POWER_OF_TREE_DEPTH = 2**DEPOSIT_CONTRACT_TREE_DEPTH
|
||||||
|
|
||||||
|
@ -63,45 +62,6 @@ def registration_contract(w3, tester):
|
||||||
return registration_deployed
|
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
|
@pytest.fixture
|
||||||
def assert_tx_failed(tester):
|
def assert_tx_failed(tester):
|
||||||
def assert_tx_failed(function_to_test, exception=eth_tester.exceptions.TransactionFailed):
|
def assert_tx_failed(function_to_test, exception=eth_tester.exceptions.TransactionFailed):
|
||||||
|
|
|
@ -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(
|
@pytest.mark.parametrize(
|
||||||
'success,deposit_amount',
|
'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['withdrawal_credentials'] == deposit_input[1]
|
||||||
assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little')
|
assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little')
|
||||||
assert log['signature'] == deposit_input[2]
|
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):
|
def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input):
|
||||||
log_filter = registration_contract.events.Deposit.createFilter(
|
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
|
assert len(logs) == 1
|
||||||
log = logs[0]['args']
|
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(
|
deposit_data = DepositData(
|
||||||
pubkey=deposit_input[0],
|
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)
|
leaf_nodes.append(hash_tree_root_result)
|
||||||
root = compute_merkle_root(leaf_nodes)
|
root = compute_merkle_root(leaf_nodes)
|
||||||
assert root == registration_contract.functions.get_deposit_root().call()
|
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
|
|
||||||
|
|
|
@ -134,11 +134,17 @@ def objects_to_spec(functions: Dict[str, str],
|
||||||
f" def __init__(self, _x: {value}) -> None:\n"
|
f" def __init__(self, _x: {value}) -> None:\n"
|
||||||
f" ...\n"
|
f" ...\n"
|
||||||
if value.startswith("uint")
|
if value.startswith("uint")
|
||||||
|
# else ""
|
||||||
|
# else f"{key} = {value}\n"
|
||||||
else f"class {key}({value}):\n pass\n"
|
else f"class {key}({value}):\n pass\n"
|
||||||
for key, value in custom_types.items()
|
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())
|
functions_spec = '\n\n'.join(functions.values())
|
||||||
constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants))
|
constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants))
|
||||||
ssz_objects_instantiation_spec = '\n\n'.join(ssz_objects.values())
|
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())
|
items = list(objects.items())
|
||||||
for key, value in items:
|
for key, value in items:
|
||||||
dependencies = re.findall(r'(: [A-Z][\w[]*)', value)
|
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:
|
for dep in dependencies:
|
||||||
if dep in custom_types or len(dep) == 0:
|
if dep in custom_types or len(dep) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
- [Rewards and penalties](#rewards-and-penalties)
|
- [Rewards and penalties](#rewards-and-penalties)
|
||||||
- [Max operations per block](#max-operations-per-block)
|
- [Max operations per block](#max-operations-per-block)
|
||||||
- [Signature domains](#signature-domains)
|
- [Signature domains](#signature-domains)
|
||||||
- [Data structures](#data-structures)
|
- [Custom types](#custom-types-1)
|
||||||
|
- [Containers](#containers)
|
||||||
- [Misc dependencies](#misc-dependencies)
|
- [Misc dependencies](#misc-dependencies)
|
||||||
- [`Fork`](#fork)
|
- [`Fork`](#fork)
|
||||||
- [`Validator`](#validator)
|
- [`Validator`](#validator)
|
||||||
|
@ -95,7 +96,7 @@
|
||||||
- [`initiate_validator_exit`](#initiate_validator_exit)
|
- [`initiate_validator_exit`](#initiate_validator_exit)
|
||||||
- [`slash_validator`](#slash_validator)
|
- [`slash_validator`](#slash_validator)
|
||||||
- [Genesis](#genesis)
|
- [Genesis](#genesis)
|
||||||
- [`Eth2Genesis`](#eth2genesis)
|
- [Genesis trigger](#genesis-trigger)
|
||||||
- [Genesis state](#genesis-state)
|
- [Genesis state](#genesis-state)
|
||||||
- [Genesis block](#genesis-block)
|
- [Genesis block](#genesis-block)
|
||||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
- [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 |
|
| Name | Value | Unit | Duration |
|
||||||
| - | - | :-: | :-: |
|
| - | - | :-: | :-: |
|
||||||
| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
| `RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
||||||
| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
| `ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
||||||
| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
| `SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
|
||||||
|
|
||||||
### Rewards and penalties
|
### 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_VOLUNTARY_EXIT` | `4` |
|
||||||
| `DOMAIN_TRANSFER` | `5` |
|
| `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
|
### Misc dependencies
|
||||||
|
|
||||||
|
@ -283,48 +298,35 @@ The types are defined topologically to aid in facilitating an executable version
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Fork(Container):
|
class Fork(Container):
|
||||||
# Previous fork version
|
|
||||||
previous_version: Version
|
previous_version: Version
|
||||||
# Current fork version
|
|
||||||
current_version: Version
|
current_version: Version
|
||||||
# Fork epoch number
|
epoch: Epoch # Epoch of latest fork
|
||||||
epoch: Epoch
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `Validator`
|
#### `Validator`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Validator(Container):
|
class Validator(Container):
|
||||||
# BLS public key
|
|
||||||
pubkey: BLSPubkey
|
pubkey: BLSPubkey
|
||||||
# Withdrawal credentials
|
withdrawal_credentials: Hash # Commitment to pubkey for withdrawals and transfers
|
||||||
withdrawal_credentials: Hash
|
effective_balance: Gwei # Balance at stake
|
||||||
# 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
|
|
||||||
slashed: bool
|
slashed: bool
|
||||||
# Effective balance
|
# Status epochs
|
||||||
effective_balance: Gwei
|
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`
|
#### `Crosslink`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Crosslink(Container):
|
class Crosslink(Container):
|
||||||
# Shard number
|
|
||||||
shard: Shard
|
shard: Shard
|
||||||
# Crosslinking data from epochs [start....end-1]
|
parent_root: Hash
|
||||||
|
# Crosslinking data
|
||||||
start_epoch: Epoch
|
start_epoch: Epoch
|
||||||
end_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
|
data_root: Hash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -334,13 +336,11 @@ class Crosslink(Container):
|
||||||
class AttestationData(Container):
|
class AttestationData(Container):
|
||||||
# LMD GHOST vote
|
# LMD GHOST vote
|
||||||
beacon_block_root: Hash
|
beacon_block_root: Hash
|
||||||
|
|
||||||
# FFG vote
|
# FFG vote
|
||||||
source_epoch: Epoch
|
source_epoch: Epoch
|
||||||
source_root: Hash
|
source_root: Hash
|
||||||
target_epoch: Epoch
|
target_epoch: Epoch
|
||||||
target_root: Hash
|
target_root: Hash
|
||||||
|
|
||||||
# Crosslink vote
|
# Crosslink vote
|
||||||
crosslink: Crosslink
|
crosslink: Crosslink
|
||||||
```
|
```
|
||||||
|
@ -349,22 +349,17 @@ class AttestationData(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class AttestationDataAndCustodyBit(Container):
|
class AttestationDataAndCustodyBit(Container):
|
||||||
# Attestation data
|
|
||||||
data: AttestationData
|
data: AttestationData
|
||||||
# Custody bit
|
custody_bit: bool # Challengeable bit for the custody of crosslink data
|
||||||
custody_bit: bool
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `IndexedAttestation`
|
#### `IndexedAttestation`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class IndexedAttestation(Container):
|
class IndexedAttestation(Container):
|
||||||
# Validator indices
|
custody_bit_0_indices: List[ValidatorIndex] # Indices with custody bit equal to 0
|
||||||
custody_bit_0_indices: List[ValidatorIndex]
|
custody_bit_1_indices: List[ValidatorIndex] # Indices with custody bit equal to 1
|
||||||
custody_bit_1_indices: List[ValidatorIndex]
|
|
||||||
# Attestation data
|
|
||||||
data: AttestationData
|
data: AttestationData
|
||||||
# Aggregate signature
|
|
||||||
signature: BLSSignature
|
signature: BLSSignature
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -372,13 +367,9 @@ class IndexedAttestation(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class PendingAttestation(Container):
|
class PendingAttestation(Container):
|
||||||
# Attester aggregation bitfield
|
aggregation_bitfield: bytes # Bit set for every attesting participant within a committee
|
||||||
aggregation_bitfield: bytes
|
|
||||||
# Attestation data
|
|
||||||
data: AttestationData
|
data: AttestationData
|
||||||
# Inclusion delay
|
inclusion_delay: Slot
|
||||||
inclusion_delay: uint64
|
|
||||||
# Proposer index
|
|
||||||
proposer_index: ValidatorIndex
|
proposer_index: ValidatorIndex
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -386,11 +377,8 @@ class PendingAttestation(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Eth1Data(Container):
|
class Eth1Data(Container):
|
||||||
# Root of the deposit tree
|
|
||||||
deposit_root: Hash
|
deposit_root: Hash
|
||||||
# Total number of deposits
|
|
||||||
deposit_count: uint64
|
deposit_count: uint64
|
||||||
# Block hash
|
|
||||||
block_hash: Hash
|
block_hash: Hash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -398,9 +386,7 @@ class Eth1Data(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class HistoricalBatch(Container):
|
class HistoricalBatch(Container):
|
||||||
# Block roots
|
|
||||||
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
|
block_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
|
||||||
# State roots
|
|
||||||
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
|
state_roots: Vector[Hash, SLOTS_PER_HISTORICAL_ROOT]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -408,13 +394,9 @@ class HistoricalBatch(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class DepositData(Container):
|
class DepositData(Container):
|
||||||
# BLS pubkey
|
|
||||||
pubkey: BLSPubkey
|
pubkey: BLSPubkey
|
||||||
# Withdrawal credentials
|
|
||||||
withdrawal_credentials: Hash
|
withdrawal_credentials: Hash
|
||||||
# Amount in Gwei
|
|
||||||
amount: Gwei
|
amount: Gwei
|
||||||
# Container self-signature
|
|
||||||
signature: BLSSignature
|
signature: BLSSignature
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -435,11 +417,8 @@ class BeaconBlockHeader(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ProposerSlashing(Container):
|
class ProposerSlashing(Container):
|
||||||
# Proposer index
|
|
||||||
proposer_index: ValidatorIndex
|
proposer_index: ValidatorIndex
|
||||||
# First block header
|
|
||||||
header_1: BeaconBlockHeader
|
header_1: BeaconBlockHeader
|
||||||
# Second block header
|
|
||||||
header_2: BeaconBlockHeader
|
header_2: BeaconBlockHeader
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -447,9 +426,7 @@ class ProposerSlashing(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class AttesterSlashing(Container):
|
class AttesterSlashing(Container):
|
||||||
# First attestation
|
|
||||||
attestation_1: IndexedAttestation
|
attestation_1: IndexedAttestation
|
||||||
# Second attestation
|
|
||||||
attestation_2: IndexedAttestation
|
attestation_2: IndexedAttestation
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -457,13 +434,9 @@ class AttesterSlashing(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Attestation(Container):
|
class Attestation(Container):
|
||||||
# Attester aggregation bitfield
|
|
||||||
aggregation_bitfield: bytes
|
aggregation_bitfield: bytes
|
||||||
# Attestation data
|
|
||||||
data: AttestationData
|
data: AttestationData
|
||||||
# Custody bitfield
|
|
||||||
custody_bitfield: bytes
|
custody_bitfield: bytes
|
||||||
# BLS aggregate signature
|
|
||||||
signature: BLSSignature
|
signature: BLSSignature
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -471,9 +444,7 @@ class Attestation(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Deposit(Container):
|
class Deposit(Container):
|
||||||
# Branch in the deposit tree
|
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root
|
||||||
proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH]
|
|
||||||
# Data
|
|
||||||
data: DepositData
|
data: DepositData
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -481,11 +452,8 @@ class Deposit(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class VoluntaryExit(Container):
|
class VoluntaryExit(Container):
|
||||||
# Minimum epoch for processing exit
|
epoch: Epoch # Earliest epoch when voluntary exit can be processed
|
||||||
epoch: Epoch
|
|
||||||
# Index of the exiting validator
|
|
||||||
validator_index: ValidatorIndex
|
validator_index: ValidatorIndex
|
||||||
# Validator signature
|
|
||||||
signature: BLSSignature
|
signature: BLSSignature
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -493,20 +461,13 @@ class VoluntaryExit(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Transfer(Container):
|
class Transfer(Container):
|
||||||
# Sender index
|
|
||||||
sender: ValidatorIndex
|
sender: ValidatorIndex
|
||||||
# Recipient index
|
|
||||||
recipient: ValidatorIndex
|
recipient: ValidatorIndex
|
||||||
# Amount in Gwei
|
|
||||||
amount: Gwei
|
amount: Gwei
|
||||||
# Fee in Gwei for block proposer
|
|
||||||
fee: Gwei
|
fee: Gwei
|
||||||
# Inclusion slot
|
slot: Slot # Slot at which transfer must be processed
|
||||||
slot: Slot
|
pubkey: BLSPubkey # Withdrawal pubkey
|
||||||
# Sender withdrawal pubkey
|
signature: BLSSignature # Signature checked against withdrawal pubkey
|
||||||
pubkey: BLSPubkey
|
|
||||||
# Sender signature
|
|
||||||
signature: BLSSignature
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Beacon blocks
|
### Beacon blocks
|
||||||
|
@ -516,8 +477,9 @@ class Transfer(Container):
|
||||||
```python
|
```python
|
||||||
class BeaconBlockBody(Container):
|
class BeaconBlockBody(Container):
|
||||||
randao_reveal: BLSSignature
|
randao_reveal: BLSSignature
|
||||||
eth1_data: Eth1Data
|
eth1_data: Eth1Data # Eth1 data vote
|
||||||
graffiti: Bytes32
|
graffiti: Bytes32 # Arbitrary data
|
||||||
|
# Operations
|
||||||
proposer_slashings: List[ProposerSlashing]
|
proposer_slashings: List[ProposerSlashing]
|
||||||
attester_slashings: List[AttesterSlashing]
|
attester_slashings: List[AttesterSlashing]
|
||||||
attestations: List[Attestation]
|
attestations: List[Attestation]
|
||||||
|
@ -530,7 +492,6 @@ class BeaconBlockBody(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class BeaconBlock(Container):
|
class BeaconBlock(Container):
|
||||||
# Header
|
|
||||||
slot: Slot
|
slot: Slot
|
||||||
parent_root: Hash
|
parent_root: Hash
|
||||||
state_root: Hash
|
state_root: Hash
|
||||||
|
@ -544,39 +505,43 @@ class BeaconBlock(Container):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class BeaconState(Container):
|
class BeaconState(Container):
|
||||||
# Misc
|
# Versioning
|
||||||
slot: Slot
|
|
||||||
genesis_time: uint64
|
genesis_time: uint64
|
||||||
fork: Fork # For versioning hard forks
|
slot: Slot
|
||||||
# Validator registry
|
fork: Fork
|
||||||
validator_registry: List[Validator]
|
# 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]
|
balances: List[Gwei]
|
||||||
# Randomness and committees
|
# Shuffling
|
||||||
latest_randao_mixes: Vector[Hash, LATEST_RANDAO_MIXES_LENGTH]
|
start_shard: Shard
|
||||||
latest_start_shard: Shard
|
randao_mixes: Vector[Hash, RANDAO_MIXES_LENGTH]
|
||||||
# Finality
|
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]
|
previous_epoch_attestations: List[PendingAttestation]
|
||||||
current_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
|
current_justified_epoch: Epoch
|
||||||
previous_justified_root: Hash
|
|
||||||
current_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_epoch: Epoch
|
||||||
finalized_root: Hash
|
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
|
## Helper functions
|
||||||
|
@ -683,7 +648,7 @@ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[Valid
|
||||||
"""
|
"""
|
||||||
Get active validator indices at ``epoch``.
|
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`
|
### `increase_balance`
|
||||||
|
@ -728,7 +693,7 @@ def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int:
|
||||||
```python
|
```python
|
||||||
def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
|
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)
|
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:
|
def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
|
||||||
assert epoch <= get_current_epoch(state) + 1
|
assert epoch <= get_current_epoch(state) + 1
|
||||||
check_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:
|
while check_epoch > epoch:
|
||||||
check_epoch -= 1
|
check_epoch -= 1
|
||||||
shard = Shard((shard + SHARD_COUNT - get_shard_delta(state, Epoch(check_epoch))) % SHARD_COUNT)
|
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``.
|
Return the block root at a recent ``slot``.
|
||||||
"""
|
"""
|
||||||
assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
|
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`
|
### `get_block_root`
|
||||||
|
@ -785,9 +750,9 @@ def get_randao_mix(state: BeaconState,
|
||||||
epoch: Epoch) -> Hash:
|
epoch: Epoch) -> Hash:
|
||||||
"""
|
"""
|
||||||
Return the randao mix at a recent ``epoch``.
|
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`
|
### `get_active_index_root`
|
||||||
|
@ -798,9 +763,9 @@ def get_active_index_root(state: BeaconState,
|
||||||
"""
|
"""
|
||||||
Return the index root at a recent ``epoch``.
|
Return the index root at a recent ``epoch``.
|
||||||
``epoch`` expected to be between
|
``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`
|
### `generate_seed`
|
||||||
|
@ -812,7 +777,7 @@ def generate_seed(state: BeaconState,
|
||||||
Generate a seed for the given ``epoch``.
|
Generate a seed for the given ``epoch``.
|
||||||
"""
|
"""
|
||||||
return hash(
|
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) +
|
get_active_index_root(state, epoch) +
|
||||||
int_to_bytes(epoch, length=32)
|
int_to_bytes(epoch, length=32)
|
||||||
)
|
)
|
||||||
|
@ -836,7 +801,7 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
|
||||||
while True:
|
while True:
|
||||||
candidate_index = first_committee[(epoch + i) % len(first_committee)]
|
candidate_index = first_committee[(epoch + i) % len(first_committee)]
|
||||||
random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
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:
|
if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||||
return ValidatorIndex(candidate_index)
|
return ValidatorIndex(candidate_index)
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -862,7 +827,7 @@ def verify_merkle_branch(leaf: Hash, proof: List[Hash], depth: int, index: int,
|
||||||
### `get_shuffled_index`
|
### `get_shuffled_index`
|
||||||
|
|
||||||
```python
|
```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``).
|
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
|
# See the 'generalized domain' algorithm on page 3
|
||||||
for current_round in range(SHUFFLE_ROUND_COUNT):
|
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
|
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)
|
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]
|
byte = source[(position % 256) // 8]
|
||||||
bit = (byte >> (position % 8)) % 2
|
bit = (byte >> (position % 8)) % 2
|
||||||
index = flip if bit else index
|
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 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`
|
### `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)
|
attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield)
|
||||||
custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_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]
|
custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices]
|
||||||
|
|
||||||
return IndexedAttestation(
|
return IndexedAttestation(
|
||||||
|
@ -1024,8 +993,8 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
|
||||||
# Verify aggregate signature
|
# Verify aggregate signature
|
||||||
assert bls_verify_multiple(
|
assert bls_verify_multiple(
|
||||||
pubkeys=[
|
pubkeys=[
|
||||||
bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_0_indices]),
|
bls_aggregate_pubkeys([state.validators[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_1_indices]),
|
||||||
],
|
],
|
||||||
message_hashes=[
|
message_hashes=[
|
||||||
hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)),
|
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``.
|
Initiate the exit of the validator of the given ``index``.
|
||||||
"""
|
"""
|
||||||
# Return if validator already initiated exit
|
# Return if validator already initiated exit
|
||||||
validator = state.validator_registry[index]
|
validator = state.validators[index]
|
||||||
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Compute exit queue epoch
|
# 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_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):
|
if exit_queue_churn >= get_churn_limit(state):
|
||||||
exit_queue_epoch += Epoch(1)
|
exit_queue_epoch += Epoch(1)
|
||||||
|
|
||||||
|
@ -1141,10 +1110,10 @@ def slash_validator(state: BeaconState,
|
||||||
"""
|
"""
|
||||||
current_epoch = get_current_epoch(state)
|
current_epoch = get_current_epoch(state)
|
||||||
initiate_validator_exit(state, slashed_index)
|
initiate_validator_exit(state, slashed_index)
|
||||||
state.validator_registry[slashed_index].slashed = True
|
state.validators[slashed_index].slashed = True
|
||||||
state.validator_registry[slashed_index].withdrawable_epoch = Epoch(current_epoch + LATEST_SLASHED_EXIT_LENGTH)
|
state.validators[slashed_index].withdrawable_epoch = Epoch(current_epoch + SLASHED_EXIT_LENGTH)
|
||||||
slashed_balance = state.validator_registry[slashed_index].effective_balance
|
slashed_balance = state.validators[slashed_index].effective_balance
|
||||||
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance
|
state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH] += slashed_balance
|
||||||
|
|
||||||
proposer_index = get_beacon_proposer_index(state)
|
proposer_index = get_beacon_proposer_index(state)
|
||||||
if whistleblower_index is None:
|
if whistleblower_index is None:
|
||||||
|
@ -1158,26 +1127,51 @@ def slash_validator(state: BeaconState,
|
||||||
|
|
||||||
## Genesis
|
## 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`
|
* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log
|
||||||
* `genesis_eth1_data` be object of type `Eth1Data` where
|
* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log
|
||||||
* `genesis_eth1_data.deposit_root = eth2genesis.deposit_root`
|
|
||||||
* `genesis_eth1_data.deposit_count = eth2genesis.deposit_count`
|
When `is_genesis_trigger(deposits, timestamp) is True` for the first time let:
|
||||||
* `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
|
* `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
|
### 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
|
```python
|
||||||
def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState:
|
def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState:
|
||||||
state = BeaconState(
|
state = BeaconState(
|
||||||
genesis_time=genesis_time,
|
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())),
|
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_deposit(state, deposit)
|
||||||
|
|
||||||
# Process genesis activations
|
# Process genesis activations
|
||||||
for validator in state.validator_registry:
|
for validator in state.validators:
|
||||||
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
|
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
|
||||||
validator.activation_eligibility_epoch = GENESIS_EPOCH
|
validator.activation_eligibility_epoch = GENESIS_EPOCH
|
||||||
validator.activation_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))
|
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH))
|
||||||
for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
|
for index in range(ACTIVE_INDEX_ROOTS_LENGTH):
|
||||||
state.latest_active_index_roots[index] = genesis_active_index_root
|
state.active_index_roots[index] = genesis_active_index_root
|
||||||
|
|
||||||
return state
|
return state
|
||||||
```
|
```
|
||||||
|
@ -1235,7 +1229,7 @@ def process_slots(state: BeaconState, slot: Slot) -> None:
|
||||||
def process_slot(state: BeaconState) -> None:
|
def process_slot(state: BeaconState) -> None:
|
||||||
# Cache state root
|
# Cache state root
|
||||||
previous_state_root = hash_tree_root(state)
|
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
|
# Cache latest block header state root
|
||||||
if state.latest_block_header.state_root == ZERO_HASH:
|
if state.latest_block_header.state_root == ZERO_HASH:
|
||||||
|
@ -1243,12 +1237,12 @@ def process_slot(state: BeaconState) -> None:
|
||||||
|
|
||||||
# Cache block root
|
# Cache block root
|
||||||
previous_block_root = signing_root(state.latest_block_header)
|
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
|
### 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
|
```python
|
||||||
def process_epoch(state: BeaconState) -> None:
|
def process_epoch(state: BeaconState) -> None:
|
||||||
|
@ -1298,7 +1292,7 @@ def get_unslashed_attesting_indices(state: BeaconState,
|
||||||
output = set() # type: Set[ValidatorIndex]
|
output = set() # type: Set[ValidatorIndex]
|
||||||
for a in attestations:
|
for a in attestations:
|
||||||
output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield))
|
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
|
```python
|
||||||
|
@ -1393,7 +1387,7 @@ def process_crosslinks(state: BeaconState) -> None:
|
||||||
```python
|
```python
|
||||||
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||||
total_balance = get_total_active_balance(state)
|
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)
|
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]]:
|
def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
||||||
previous_epoch = get_previous_epoch(state)
|
previous_epoch = get_previous_epoch(state)
|
||||||
total_balance = get_total_active_balance(state)
|
total_balance = get_total_active_balance(state)
|
||||||
rewards = [Gwei(0) for index in range(len(state.validator_registry))]
|
rewards = [Gwei(0) for _ in range(len(state.validators))]
|
||||||
penalties = [Gwei(0) for index in range(len(state.validator_registry))]
|
penalties = [Gwei(0) for _ in range(len(state.validators))]
|
||||||
eligible_validator_indices = [
|
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)
|
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))
|
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
|
||||||
if index not in matching_target_attesting_indices:
|
if index not in matching_target_attesting_indices:
|
||||||
penalties[index] += Gwei(
|
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
|
return rewards, penalties
|
||||||
|
@ -1450,8 +1444,8 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
|
||||||
rewards = [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.validator_registry))]
|
penalties = [Gwei(0) for index in range(len(state.validators))]
|
||||||
epoch = get_previous_epoch(state)
|
epoch = get_previous_epoch(state)
|
||||||
for offset in range(get_epoch_committee_count(state, epoch)):
|
for offset in range(get_epoch_committee_count(state, epoch)):
|
||||||
shard = Shard((get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT)
|
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)
|
rewards1, penalties1 = get_attestation_deltas(state)
|
||||||
rewards2, penalties2 = get_crosslink_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])
|
increase_balance(state, ValidatorIndex(index), rewards1[index] + rewards2[index])
|
||||||
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index])
|
decrease_balance(state, ValidatorIndex(index), penalties1[index] + penalties2[index])
|
||||||
```
|
```
|
||||||
|
@ -1485,7 +1479,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
|
||||||
```python
|
```python
|
||||||
def process_registry_updates(state: BeaconState) -> None:
|
def process_registry_updates(state: BeaconState) -> None:
|
||||||
# Process activation eligibility and ejections
|
# Process activation eligibility and ejections
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validators):
|
||||||
if (
|
if (
|
||||||
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
|
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
|
||||||
validator.effective_balance >= MAX_EFFECTIVE_BALANCE
|
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
|
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
|
||||||
activation_queue = sorted([
|
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_eligibility_epoch != FAR_FUTURE_EPOCH and
|
||||||
validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch)
|
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)
|
# Dequeued validators for activation up to churn limit (without resetting activation epoch)
|
||||||
for index in activation_queue[:get_churn_limit(state)]:
|
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:
|
if validator.activation_epoch == FAR_FUTURE_EPOCH:
|
||||||
validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
|
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)
|
total_balance = get_total_active_balance(state)
|
||||||
|
|
||||||
# Compute slashed balances in the current epoch
|
# Compute slashed balances in the current epoch
|
||||||
total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH]
|
total_at_start = state.slashed_balances[(current_epoch + 1) % SLASHED_EXIT_LENGTH]
|
||||||
total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
|
total_at_end = state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH]
|
||||||
total_penalties = total_at_end - total_at_start
|
total_penalties = total_at_end - total_at_start
|
||||||
|
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validators):
|
||||||
if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2:
|
if validator.slashed and current_epoch == validator.withdrawable_epoch - SLASHED_EXIT_LENGTH // 2:
|
||||||
penalty = max(
|
penalty = max(
|
||||||
validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance,
|
validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance,
|
||||||
validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT
|
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:
|
if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
|
||||||
state.eth1_data_votes = []
|
state.eth1_data_votes = []
|
||||||
# Update effective balances with hysteresis
|
# Update effective balances with hysteresis
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validators):
|
||||||
balance = state.balances[index]
|
balance = state.balances[index]
|
||||||
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
|
HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
|
||||||
if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
|
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)
|
validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
|
||||||
# Update start shard
|
# 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
|
# Set active index root
|
||||||
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH
|
index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % ACTIVE_INDEX_ROOTS_LENGTH
|
||||||
state.latest_active_index_roots[index_root_position] = hash_tree_root(
|
state.active_index_roots[index_root_position] = hash_tree_root(
|
||||||
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
|
get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY))
|
||||||
)
|
)
|
||||||
# Set total slashed balances
|
# Set total slashed balances
|
||||||
state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = (
|
state.slashed_balances[next_epoch % SLASHED_EXIT_LENGTH] = (
|
||||||
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
|
state.slashed_balances[current_epoch % SLASHED_EXIT_LENGTH]
|
||||||
)
|
)
|
||||||
# Set randao mix
|
# 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
|
# Set historical root accumulator
|
||||||
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
|
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
|
||||||
historical_batch = HistoricalBatch(
|
historical_batch = HistoricalBatch(
|
||||||
block_roots=state.latest_block_roots,
|
block_roots=state.block_roots,
|
||||||
state_roots=state.latest_state_roots,
|
state_roots=state.state_roots,
|
||||||
)
|
)
|
||||||
state.historical_roots.append(hash_tree_root(historical_batch))
|
state.historical_roots.append(hash_tree_root(historical_batch))
|
||||||
# Rotate current/previous epoch attestations
|
# 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),
|
body_root=hash_tree_root(block.body),
|
||||||
)
|
)
|
||||||
# Verify proposer is not slashed
|
# 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
|
assert not proposer.slashed
|
||||||
# Verify proposer signature
|
# Verify proposer signature
|
||||||
assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
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
|
```python
|
||||||
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
|
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
|
# Verify that the provided randao value is valid
|
||||||
assert bls_verify(
|
assert bls_verify(
|
||||||
proposer.pubkey,
|
proposer.pubkey,
|
||||||
|
@ -1613,7 +1607,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
get_domain(state, DOMAIN_RANDAO),
|
get_domain(state, DOMAIN_RANDAO),
|
||||||
)
|
)
|
||||||
# Mix it in
|
# 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)),
|
xor(get_randao_mix(state, get_current_epoch(state)),
|
||||||
hash(body.randao_reveal))
|
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:
|
def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
state.eth1_data_votes.append(body.eth1_data)
|
state.eth1_data_votes.append(body.eth1_data)
|
||||||
if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
|
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
|
#### Operations
|
||||||
|
@ -1633,7 +1627,7 @@ def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
```python
|
```python
|
||||||
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||||
# Verify that outstanding deposits are processed up to the maximum number of deposits
|
# 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
|
# Verify that there are no duplicate transfers
|
||||||
assert len(body.transfers) == len(set(body.transfers))
|
assert len(body.transfers) == len(set(body.transfers))
|
||||||
all_operations = [
|
all_operations = [
|
||||||
|
@ -1657,7 +1651,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla
|
||||||
"""
|
"""
|
||||||
Process ``ProposerSlashing`` operation.
|
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
|
# Verify that the epoch is the same
|
||||||
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
|
assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot)
|
||||||
# But the headers are different
|
# 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_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
|
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)):
|
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)
|
slash_validator(state, index)
|
||||||
slashed_any = True
|
slashed_any = True
|
||||||
assert slashed_any
|
assert slashed_any
|
||||||
|
@ -1703,6 +1697,10 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
Process ``Attestation`` operation.
|
Process ``Attestation`` operation.
|
||||||
"""
|
"""
|
||||||
data = attestation.data
|
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)
|
attestation_slot = get_attestation_data_slot(state, data)
|
||||||
assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
|
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),
|
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):
|
if data.target_epoch == get_current_epoch(state):
|
||||||
ffg_data = (state.current_justified_epoch, state.current_justified_root, 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]
|
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),
|
leaf=hash_tree_root(deposit.data),
|
||||||
proof=deposit.proof,
|
proof=deposit.proof,
|
||||||
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
|
depth=DEPOSIT_CONTRACT_TREE_DEPTH,
|
||||||
index=state.deposit_index,
|
index=state.eth1_deposit_index,
|
||||||
root=state.latest_eth1_data.deposit_root,
|
root=state.eth1_data.deposit_root,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deposits must be processed in order
|
# Deposits must be processed in order
|
||||||
state.deposit_index += 1
|
state.eth1_deposit_index += 1
|
||||||
|
|
||||||
pubkey = deposit.data.pubkey
|
pubkey = deposit.data.pubkey
|
||||||
amount = deposit.data.amount
|
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:
|
if pubkey not in validator_pubkeys:
|
||||||
# Verify the deposit signature (proof of possession).
|
# Verify the deposit signature (proof of possession).
|
||||||
# Invalid signatures are allowed by the deposit contract,
|
# Invalid signatures are allowed by the deposit contract,
|
||||||
|
@ -1765,7 +1762,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Add validator and balance entries
|
# Add validator and balance entries
|
||||||
state.validator_registry.append(Validator(
|
state.validators.append(Validator(
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
withdrawal_credentials=deposit.data.withdrawal_credentials,
|
withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||||
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
|
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
|
||||||
|
@ -1788,7 +1785,7 @@ def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||||
"""
|
"""
|
||||||
Process ``VoluntaryExit`` operation.
|
Process ``VoluntaryExit`` operation.
|
||||||
"""
|
"""
|
||||||
validator = state.validator_registry[exit.validator_index]
|
validator = state.validators[exit.validator_index]
|
||||||
# Verify the validator is active
|
# Verify the validator is active
|
||||||
assert is_active_validator(validator, get_current_epoch(state))
|
assert is_active_validator(validator, get_current_epoch(state))
|
||||||
# Verify the validator has not yet exited
|
# Verify the validator has not yet exited
|
||||||
|
@ -1817,13 +1814,13 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
|
||||||
assert state.slot == transfer.slot
|
assert state.slot == transfer.slot
|
||||||
# Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE
|
# Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE
|
||||||
assert (
|
assert (
|
||||||
state.validator_registry[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
|
state.validators[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or
|
||||||
get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or
|
get_current_epoch(state) >= state.validators[transfer.sender].withdrawable_epoch or
|
||||||
transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender]
|
transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender]
|
||||||
)
|
)
|
||||||
# Verify that the pubkey is valid
|
# Verify that the pubkey is valid
|
||||||
assert (
|
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:]
|
int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:]
|
||||||
)
|
)
|
||||||
# Verify that the signature is valid
|
# Verify that the signature is valid
|
||||||
|
|
|
@ -9,15 +9,12 @@
|
||||||
- [Table of contents](#table-of-contents)
|
- [Table of contents](#table-of-contents)
|
||||||
- [Introduction](#introduction)
|
- [Introduction](#introduction)
|
||||||
- [Constants](#constants)
|
- [Constants](#constants)
|
||||||
- [Gwei values](#gwei-values)
|
|
||||||
- [Contract](#contract)
|
- [Contract](#contract)
|
||||||
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
||||||
- [Arguments](#arguments)
|
- [`deposit` function](#deposit-function)
|
||||||
|
- [Deposit amount](#deposit-amount)
|
||||||
- [Withdrawal credentials](#withdrawal-credentials)
|
- [Withdrawal credentials](#withdrawal-credentials)
|
||||||
- [Amount](#amount)
|
- [`Deposit` log](#deposit-log)
|
||||||
- [Event logs](#event-logs)
|
|
||||||
- [`Deposit` logs](#deposit-logs)
|
|
||||||
- [`Eth2Genesis` log](#eth2genesis-log)
|
|
||||||
- [Vyper code](#vyper-code)
|
- [Vyper code](#vyper-code)
|
||||||
|
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
@ -28,66 +25,40 @@ This document represents the specification for the beacon chain deposit contract
|
||||||
|
|
||||||
## Constants
|
## Constants
|
||||||
|
|
||||||
### Gwei values
|
|
||||||
|
|
||||||
| Name | Value | Unit |
|
|
||||||
| - | - | - |
|
|
||||||
| `FULL_DEPOSIT_AMOUNT` | `32 * 10**9` | Gwei |
|
|
||||||
|
|
||||||
### Contract
|
### Contract
|
||||||
|
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
|
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
|
||||||
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
|
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
|
||||||
| `CHAIN_START_FULL_DEPOSIT_THRESHOLD` | `2**16` (= 65,536) |
|
|
||||||
|
|
||||||
## Ethereum 1.0 deposit contract
|
## 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).
|
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
|
#### 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] == BLS_WITHDRAWAL_PREFIX_BYTE`
|
||||||
* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey
|
* `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.
|
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.
|
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.
|
||||||
* 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)
|
|
||||||
|
|
||||||
## Vyper code
|
## 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.
|
*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.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
|
@ -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:
|
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.
|
* 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`.
|
* 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.
|
*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(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 `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`.
|
* 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.
|
* 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``.
|
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))
|
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
|
# Use the rounded-balance-with-hysteresis supplied by the protocol for fork
|
||||||
# choice voting. This reduces the number of recomputations that need to be
|
# choice voting. This reduces the number of recomputations that need to be
|
||||||
# made for optimized implementations that precompute and save data
|
# made for optimized implementations that precompute and save data
|
||||||
def get_vote_count(block: BeaconBlock) -> int:
|
def get_vote_count(block: BeaconBlock) -> int:
|
||||||
return sum(
|
return sum(
|
||||||
start_state.validator_registry[validator_index].effective_balance
|
start_state.validators[validator_index].effective_balance
|
||||||
for validator_index, target in attestation_targets
|
for validator_index, target in attestation_targets
|
||||||
if get_ancestor(store, target, block.slot) == block
|
if get_ancestor(store, target, block.slot) == block
|
||||||
)
|
)
|
||||||
|
|
|
@ -339,7 +339,7 @@ def process_custody_key_reveal(state: BeaconState,
|
||||||
Note that this function mutates ``state``.
|
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)
|
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)
|
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``.
|
Note that this function mutates ``state``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
revealed_validator = state.validator_registry[reveal.revealed_index]
|
revealed_validator = state.validators[reveal.revealed_index]
|
||||||
masker = state.validator_registry[reveal.masker_index]
|
masker = state.validators[reveal.masker_index]
|
||||||
derived_secret_location = reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS
|
derived_secret_location = reveal.epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS
|
||||||
|
|
||||||
assert reveal.epoch >= get_current_epoch(state) + RANDAO_PENALTY_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]
|
assert reveal.revealed_index not in state.exposed_derived_secrets[derived_secret_location]
|
||||||
|
|
||||||
# Verify signature correctness
|
# Verify signature correctness
|
||||||
masker = state.validator_registry[reveal.masker_index]
|
masker = state.validators[reveal.masker_index]
|
||||||
pubkeys = [revealed_validator.pubkey, masker.pubkey]
|
pubkeys = [revealed_validator.pubkey, masker.pubkey]
|
||||||
message_hashes = [
|
message_hashes = [
|
||||||
hash_tree_root(reveal.epoch),
|
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))
|
validate_indexed_attestation(state, convert_to_indexed(state, challenge.attestation))
|
||||||
# Verify it is not too late to challenge
|
# Verify it is not too late to challenge
|
||||||
assert slot_to_epoch(challenge.attestation.data.slot) >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
|
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
|
assert responder.exit_epoch >= get_current_epoch(state) - MAX_CHUNK_CHALLENGE_DELAY
|
||||||
# Verify the responder participated in the attestation
|
# Verify the responder participated in the attestation
|
||||||
attesters = get_attesting_indices(state, challenge.attestation.data, challenge.attestation.aggregation_bitfield)
|
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:
|
challenge: CustodyBitChallenge) -> None:
|
||||||
|
|
||||||
# Verify challenge signature
|
# Verify challenge signature
|
||||||
challenger = state.validator_registry[challenge.challenger_index]
|
challenger = state.validators[challenge.challenger_index]
|
||||||
assert bls_verify(
|
assert bls_verify(
|
||||||
pubkey=challenger.pubkey,
|
pubkey=challenger.pubkey,
|
||||||
message_hash=signing_root(challenge),
|
message_hash=signing_root(challenge),
|
||||||
|
@ -524,7 +524,7 @@ def process_bit_challenge(state: BeaconState,
|
||||||
attestation = challenge.attestation
|
attestation = challenge.attestation
|
||||||
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
|
validate_indexed_attestation(state, convert_to_indexed(state, attestation))
|
||||||
# Verify the attestation is eligible for challenging
|
# 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 <=
|
assert (slot_to_epoch(attestation.data.slot) + responder.max_reveal_lateness <=
|
||||||
get_validators_custody_reveal_period(state, challenge.responder_index))
|
get_validators_custody_reveal_period(state, challenge.responder_index))
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ def process_bit_challenge_response(state: BeaconState,
|
||||||
# Verify chunk index
|
# Verify chunk index
|
||||||
assert response.chunk_index < challenge.chunk_count
|
assert response.chunk_index < challenge.chunk_count
|
||||||
# Verify responder has not been slashed
|
# Verify responder has not been slashed
|
||||||
responder = state.validator_registry[challenge.responder_index]
|
responder = state.validators[challenge.responder_index]
|
||||||
assert not responder.slashed
|
assert not responder.slashed
|
||||||
# Verify the chunk matches the crosslink data root
|
# Verify the chunk matches the crosslink data root
|
||||||
assert verify_merkle_branch(
|
assert verify_merkle_branch(
|
||||||
|
@ -673,7 +673,7 @@ Run `process_reveal_deadlines(state)` immediately after `process_registry_update
|
||||||
process_reveal_deadlines(state)
|
process_reveal_deadlines(state)
|
||||||
# end insert @process_reveal_deadlines
|
# end insert @process_reveal_deadlines
|
||||||
def process_reveal_deadlines(state: BeaconState) -> None:
|
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)
|
deadline = validator.next_custody_reveal_period + (CUSTODY_RESPONSE_DEADLINE // EPOCHS_PER_CUSTODY_PERIOD)
|
||||||
if get_validators_custody_reveal_period(state, ValidatorIndex(index)) > deadline:
|
if get_validators_custody_reveal_period(state, ValidatorIndex(index)) > deadline:
|
||||||
slash_validator(state, ValidatorIndex(index))
|
slash_validator(state, ValidatorIndex(index))
|
||||||
|
@ -714,7 +714,7 @@ def after_process_final_updates(state: BeaconState) -> None:
|
||||||
validator_indices_in_records = set(
|
validator_indices_in_records = set(
|
||||||
[record.challenger_index for record in records] + [record.responder_index for record in records]
|
[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 index not in validator_indices_in_records:
|
||||||
if validator.exit_epoch != FAR_FUTURE_EPOCH and validator.withdrawable_epoch == FAR_FUTURE_EPOCH:
|
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)
|
validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
|
||||||
|
|
|
@ -190,7 +190,7 @@ def get_shard_proposer_index(state: BeaconState,
|
||||||
|
|
||||||
# Search for an active proposer
|
# Search for an active proposer
|
||||||
for index in persistent_committee:
|
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
|
return index
|
||||||
|
|
||||||
# No block can be proposed if no validator is active
|
# No block can be proposed if no validator is active
|
||||||
|
@ -224,7 +224,7 @@ def verify_shard_attestation_signature(state: BeaconState,
|
||||||
pubkeys = []
|
pubkeys = []
|
||||||
for i, index in enumerate(persistent_committee):
|
for i, index in enumerate(persistent_committee):
|
||||||
if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b1:
|
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))
|
assert is_active_validator(validator, get_current_epoch(state))
|
||||||
pubkeys.append(validator.pubkey)
|
pubkeys.append(validator.pubkey)
|
||||||
assert bls_verify(
|
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)
|
proposer_index = get_shard_proposer_index(beacon_state, candidate.shard, candidate.slot)
|
||||||
assert proposer_index is not None
|
assert proposer_index is not None
|
||||||
assert bls_verify(
|
assert bls_verify(
|
||||||
pubkey=beacon_state.validator_registry[proposer_index].pubkey,
|
pubkey=beacon_state.validators[proposer_index].pubkey,
|
||||||
message_hash=signing_root(block),
|
message_hash=signing_root(block),
|
||||||
signature=candidate.signature,
|
signature=candidate.signature,
|
||||||
domain=get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, slot_to_epoch(candidate.slot)),
|
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)
|
assert candidate.data.previous_attestation.epoch < slot_to_epoch(candidate.data.slot)
|
||||||
|
|
||||||
# Check crosslink data root
|
# 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)
|
end_epoch = min(slot_to_epoch(candidate.data.slot) - CROSSLINK_LOOKBACK, start_epoch + MAX_EPOCHS_PER_CROSSLINK)
|
||||||
blocks = []
|
blocks = []
|
||||||
for slot in range(start_epoch * SLOTS_PER_EPOCH, end_epoch * SLOTS_PER_EPOCH):
|
for slot in range(start_epoch * SLOTS_PER_EPOCH, end_epoch * SLOTS_PER_EPOCH):
|
||||||
|
|
|
@ -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:
|
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`.
|
* `ExtendedBeaconBlock`, which is identical to a `BeaconBlock` except `state_root` is replaced with the corresponding `state: ExtendedBeaconState`.
|
||||||
|
|
||||||
### `get_active_validator_indices`
|
### `get_active_validator_indices`
|
||||||
|
@ -40,10 +40,10 @@ Note that there is now a new way to compute `get_active_validator_indices`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]:
|
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`
|
### `MerklePartial`
|
||||||
|
@ -85,7 +85,7 @@ def get_period_data(block: ExtendedBeaconBlock, shard_id: Shard, later: bool) ->
|
||||||
return PeriodData(
|
return PeriodData(
|
||||||
validator_count,
|
validator_count,
|
||||||
generate_seed(block.state, period_start),
|
generate_seed(block.state, period_start),
|
||||||
[block.state.validator_registry[i] for i in indices],
|
[block.state.validators[i] for i in indices],
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,8 @@ Since some clients are waiting for `libp2p` implementations in their respective
|
||||||
(
|
(
|
||||||
network_id: uint8
|
network_id: uint8
|
||||||
chain_id: uint64
|
chain_id: uint64
|
||||||
latest_finalized_root: bytes32
|
finalized_root: bytes32
|
||||||
latest_finalized_epoch: uint64
|
finalized_epoch: uint64
|
||||||
best_root: bytes32
|
best_root: bytes32
|
||||||
best_slot: uint64
|
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:
|
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.
|
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
|
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
|
### Goodbye
|
||||||
|
|
||||||
|
|
|
@ -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).
|
* 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.
|
* 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
|
### 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
|
### 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
|
### 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:
|
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
|
```python
|
||||||
validator = state.validator_registry[validator_index]
|
validator = state.validators[validator_index]
|
||||||
is_active = is_active_validator(validator, get_current_epoch(state))
|
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
|
committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH
|
||||||
epoch_start_slot = get_epoch_start_slot(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)
|
offset = committees_per_slot * (slot % SLOTS_PER_EPOCH)
|
||||||
slot_start_shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT
|
slot_start_shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT
|
||||||
for i in range(committees_per_slot):
|
for i in range(committees_per_slot):
|
||||||
|
@ -221,10 +221,10 @@ epoch_signature = bls_sign(
|
||||||
|
|
||||||
##### Eth1 Data
|
##### 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:
|
* 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_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`.
|
* `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:
|
* If `D` is empty:
|
||||||
|
@ -267,9 +267,9 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`.
|
||||||
|
|
||||||
##### Deposits
|
##### 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
|
##### 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_epoch = head_state.current_justified_epoch`.
|
||||||
* Set `attestation_data.source_root = head_state.current_justified_root`.
|
* Set `attestation_data.source_root = head_state.current_justified_root`.
|
||||||
* Set `attestation_data.target_epoch = get_current_epoch(head_state)`
|
* 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_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
|
##### Crosslink vote
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from typing import Callable, Iterable
|
||||||
|
|
||||||
from eth2spec.phase0 import spec as spec_phase0
|
from eth2spec.phase0 import spec as spec_phase0
|
||||||
from eth2spec.phase1 import spec as spec_phase1
|
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_crosslinks,
|
||||||
test_process_registry_updates
|
test_process_registry_updates
|
||||||
)
|
)
|
||||||
|
@ -33,8 +33,10 @@ def create_suite(transition_name: str, config_name: str, get_cases: Callable[[],
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
gen_runner.run_generator("epoch_processing", [
|
gen_runner.run_generator("epoch_processing", [
|
||||||
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks)),
|
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks, 'phase0')),
|
||||||
create_suite('crosslinks', 'mainnet', lambda: generate_from_tests(test_process_crosslinks)),
|
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)),
|
create_suite('registry_updates', 'minimal',
|
||||||
create_suite('registry_updates', 'mainnet', lambda: generate_from_tests(test_process_registry_updates)),
|
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
|
||||||
|
create_suite('registry_updates', 'mainnet',
|
||||||
|
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
|
||||||
])
|
])
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from typing import Callable, Iterable
|
from typing import Callable, Iterable
|
||||||
|
|
||||||
from eth2spec.test.block_processing import (
|
from eth2spec.test.phase_0.block_processing import (
|
||||||
test_process_attestation,
|
test_process_attestation,
|
||||||
test_process_attester_slashing,
|
test_process_attester_slashing,
|
||||||
test_process_block_header,
|
test_process_block_header,
|
||||||
test_process_deposit,
|
test_process_deposit,
|
||||||
test_process_proposer_slashing,
|
test_process_proposer_slashing,
|
||||||
test_process_transfer,
|
test_process_transfer,
|
||||||
test_process_voluntary_exit
|
test_process_voluntary_exit,
|
||||||
)
|
)
|
||||||
|
|
||||||
from gen_base import gen_runner, gen_suite, gen_typing
|
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__":
|
if __name__ == "__main__":
|
||||||
gen_runner.run_generator("operations", [
|
gen_runner.run_generator("operations", [
|
||||||
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation)),
|
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation, 'phase0')),
|
||||||
create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation)),
|
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)),
|
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)),
|
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)),
|
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)),
|
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)),
|
create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit, 'phase0')),
|
||||||
create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit)),
|
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)),
|
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)),
|
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)),
|
create_suite('transfer', 'minimal', lambda: generate_from_tests(test_process_transfer, 'phase0')),
|
||||||
create_suite('transfer', 'mainnet', lambda: generate_from_tests(test_process_transfer)),
|
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)),
|
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)),
|
create_suite('voluntary_exit', 'mainnet', lambda: generate_from_tests(test_process_voluntary_exit, 'phase0')),
|
||||||
])
|
])
|
||||||
|
|
|
@ -16,7 +16,7 @@ def create_suite(handler_name: str, config_name: str, get_cases: Callable[[], It
|
||||||
spec_phase0.apply_constants_preset(presets)
|
spec_phase0.apply_constants_preset(presets)
|
||||||
spec_phase1.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",
|
title="sanity testing",
|
||||||
summary="Sanity test suite, %s type, generated from pytests" % handler_name,
|
summary="Sanity test suite, %s type, generated from pytests" % handler_name,
|
||||||
forks_timeline="testing",
|
forks_timeline="testing",
|
||||||
|
@ -30,8 +30,8 @@ def create_suite(handler_name: str, config_name: str, get_cases: Callable[[], It
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
gen_runner.run_generator("sanity", [
|
gen_runner.run_generator("sanity", [
|
||||||
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks)),
|
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks, 'phase0')),
|
||||||
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks)),
|
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks, 'phase0')),
|
||||||
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots)),
|
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots, 'phase0')),
|
||||||
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots)),
|
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots, 'phase0')),
|
||||||
])
|
])
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from eth2spec.phase0 import spec as spec_phase0
|
from eth2spec.phase0 import spec as spec
|
||||||
from eth2spec.phase1 import spec as spec_phase1
|
|
||||||
from eth_utils import (
|
from eth_utils import (
|
||||||
to_dict, to_tuple
|
to_dict, to_tuple
|
||||||
)
|
)
|
||||||
|
@ -8,7 +7,7 @@ from preset_loader import loader
|
||||||
|
|
||||||
|
|
||||||
@to_dict
|
@to_dict
|
||||||
def shuffling_case(seed: spec.Bytes32, count: int):
|
def shuffling_case(seed, count):
|
||||||
yield 'seed', '0x' + seed.hex()
|
yield 'seed', '0x' + seed.hex()
|
||||||
yield 'count', count
|
yield 'count', count
|
||||||
yield 'shuffled', [spec.get_shuffled_index(i, count, seed) for i in range(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:
|
def mini_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
|
||||||
presets = loader.load_presets(configs_path, 'minimal')
|
presets = loader.load_presets(configs_path, 'minimal')
|
||||||
spec_phase0.apply_constants_preset(presets)
|
spec.apply_constants_preset(presets)
|
||||||
spec_phase1.apply_constants_preset(presets)
|
|
||||||
|
|
||||||
return ("shuffling_minimal", "core", gen_suite.render_suite(
|
return ("shuffling_minimal", "core", gen_suite.render_suite(
|
||||||
title="Swap-or-Not Shuffling tests with minimal config",
|
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:
|
def full_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
|
||||||
presets = loader.load_presets(configs_path, 'mainnet')
|
presets = loader.load_presets(configs_path, 'mainnet')
|
||||||
spec_phase0.apply_constants_preset(presets)
|
spec.apply_constants_preset(presets)
|
||||||
spec_phase1.apply_constants_preset(presets)
|
|
||||||
|
|
||||||
return ("shuffling_full", "core", gen_suite.render_suite(
|
return ("shuffling_full", "core", gen_suite.render_suite(
|
||||||
title="Swap-or-Not Shuffling tests with mainnet config",
|
title="Swap-or-Not Shuffling tests with mainnet config",
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
from random import Random
|
from random import Random
|
||||||
|
|
||||||
|
from inspect import getmembers, isclass
|
||||||
|
|
||||||
from eth2spec.debug import random_value, encode
|
from eth2spec.debug import random_value, encode
|
||||||
from eth2spec.phase0 import spec
|
from eth2spec.phase0 import spec
|
||||||
|
from eth2spec.utils.ssz.ssz_typing import Container
|
||||||
from eth2spec.utils.ssz.ssz_impl import (
|
from eth2spec.utils.ssz.ssz_impl import (
|
||||||
hash_tree_root,
|
hash_tree_root,
|
||||||
signing_root,
|
signing_root,
|
||||||
|
@ -27,17 +30,23 @@ def create_test_case_contents(value, typ):
|
||||||
|
|
||||||
|
|
||||||
@to_dict
|
@to_dict
|
||||||
def create_test_case(rng: Random, name: str, mode: random_value.RandomizationMode, chaos: bool):
|
def create_test_case(rng: Random, name: str, typ, mode: random_value.RandomizationMode, chaos: bool):
|
||||||
typ = spec.get_ssz_type_by_name(name)
|
|
||||||
value = random_value.get_random_ssz_object(rng, typ, MAX_BYTES_LENGTH, MAX_LIST_LENGTH, mode, chaos)
|
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)
|
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
|
@to_tuple
|
||||||
def ssz_static_cases(rng: Random, mode: random_value.RandomizationMode, chaos: bool, count: int):
|
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):
|
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):
|
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))
|
settings.append((seed, "mainnet", random_value.RandomizationMode.mode_random, False, 5))
|
||||||
seed += 1
|
seed += 1
|
||||||
|
|
||||||
print("Settings: %d, SSZ-types: %d" % (len(settings), len(spec.ssz_types)))
|
|
||||||
|
|
||||||
gen_runner.run_generator("ssz_static", [
|
gen_runner.run_generator("ssz_static", [
|
||||||
get_ssz_suite(seed, config_name, mode, chaos, cases_if_random)
|
get_ssz_suite(seed, config_name, mode, chaos, cases_if_random)
|
||||||
for (seed, config_name, mode, chaos, cases_if_random) in settings
|
for (seed, config_name, mode, chaos, cases_if_random) in settings
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from inspect import getmembers, isfunction
|
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.
|
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.
|
:param bls_active: optional, to override BLS switch preference. Defaults to True.
|
||||||
:return: the list of test cases.
|
:return: the list of test cases.
|
||||||
"""
|
"""
|
||||||
|
@ -16,7 +17,7 @@ def generate_from_tests(src, bls_active=True):
|
||||||
for name in fn_names:
|
for name in fn_names:
|
||||||
tfn = getattr(src, name)
|
tfn = getattr(src, name)
|
||||||
try:
|
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 no test case data is returned, the test is ignored.
|
||||||
if test_case is not None:
|
if test_case is not None:
|
||||||
out.append(test_case)
|
out.append(test_case)
|
||||||
|
|
|
@ -116,12 +116,22 @@ def with_phases(phases):
|
||||||
def decorator(fn):
|
def decorator(fn):
|
||||||
def run_with_spec_version(spec, *args, **kw):
|
def run_with_spec_version(spec, *args, **kw):
|
||||||
kw['spec'] = spec
|
kw['spec'] = spec
|
||||||
fn(*args, **kw)
|
return fn(*args, **kw)
|
||||||
|
|
||||||
def wrapper(*args, **kw):
|
def wrapper(*args, **kw):
|
||||||
if 'phase0' in phases:
|
run_phases = phases
|
||||||
run_with_spec_version(spec_phase0, *args, **kw)
|
|
||||||
if 'phase1' in phases:
|
# limit phases if one explicitly specified
|
||||||
run_with_spec_version(spec_phase1, *args, **kw)
|
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 wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
|
@ -57,7 +57,7 @@ def build_empty_block(spec, state, slot=None, signed=False):
|
||||||
slot = state.slot
|
slot = state.slot
|
||||||
empty_block = spec.BeaconBlock()
|
empty_block = spec.BeaconBlock()
|
||||||
empty_block.slot = slot
|
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)
|
previous_block_header = deepcopy(state.latest_block_header)
|
||||||
if previous_block_header.state_root == spec.ZERO_HASH:
|
if previous_block_header.state_root == spec.ZERO_HASH:
|
||||||
previous_block_header.state_root = state.hash_tree_root()
|
previous_block_header.state_root = state.hash_tree_root()
|
||||||
|
|
|
@ -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.
|
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
|
# fill previous deposits with zero-hash
|
||||||
deposit_data_leaves = [spec.ZERO_HASH] * pre_validator_count
|
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
|
# insecurely use pubkey as withdrawal key if no credentials provided
|
||||||
if withdrawal_credentials is None:
|
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(
|
deposit, root, deposit_data_leaves = build_deposit(
|
||||||
spec,
|
spec,
|
||||||
|
@ -77,9 +77,9 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c
|
||||||
privkey,
|
privkey,
|
||||||
amount,
|
amount,
|
||||||
withdrawal_credentials,
|
withdrawal_credentials,
|
||||||
signed
|
signed,
|
||||||
)
|
)
|
||||||
|
|
||||||
state.latest_eth1_data.deposit_root = root
|
state.eth1_data.deposit_root = root
|
||||||
state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
|
state.eth1_data.deposit_count = len(deposit_data_leaves)
|
||||||
return deposit
|
return deposit
|
||||||
|
|
|
@ -5,7 +5,7 @@ from eth2spec.utils.ssz.ssz_impl import hash_tree_root
|
||||||
def build_mock_validator(spec, i: int, balance: int):
|
def build_mock_validator(spec, i: int, balance: int):
|
||||||
pubkey = pubkeys[i]
|
pubkey = pubkeys[i]
|
||||||
# insecurely use pubkey as withdrawal key as well
|
# 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(
|
return spec.Validator(
|
||||||
pubkey=pubkeys[i],
|
pubkey=pubkeys[i],
|
||||||
withdrawal_credentials=withdrawal_credentials,
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
|
@ -22,8 +22,8 @@ def create_genesis_state(spec, num_validators):
|
||||||
|
|
||||||
state = spec.BeaconState(
|
state = spec.BeaconState(
|
||||||
genesis_time=0,
|
genesis_time=0,
|
||||||
deposit_index=num_validators,
|
eth1_deposit_index=num_validators,
|
||||||
latest_eth1_data=spec.Eth1Data(
|
eth1_data=spec.Eth1Data(
|
||||||
deposit_root=deposit_root,
|
deposit_root=deposit_root,
|
||||||
deposit_count=num_validators,
|
deposit_count=num_validators,
|
||||||
block_hash=spec.ZERO_HASH,
|
block_hash=spec.ZERO_HASH,
|
||||||
|
@ -32,16 +32,16 @@ def create_genesis_state(spec, num_validators):
|
||||||
# We "hack" in the initial validators,
|
# We "hack" in the initial validators,
|
||||||
# as it is much faster than creating and processing genesis deposits for every single test case.
|
# 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.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
|
# Process genesis activations
|
||||||
for validator in state.validator_registry:
|
for validator in state.validators:
|
||||||
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
|
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
|
||||||
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
|
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
|
||||||
validator.activation_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))
|
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):
|
for index in range(spec.ACTIVE_INDEX_ROOTS_LENGTH):
|
||||||
state.latest_active_index_roots[index] = genesis_active_index_root
|
state.active_index_roots[index] = genesis_active_index_root
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -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):
|
def get_valid_proposer_slashing(spec, state, signed_1=False, signed_2=False):
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
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
|
slot = state.slot
|
||||||
|
|
||||||
header_1 = spec.BeaconBlockHeader(
|
header_1 = spec.BeaconBlockHeader(
|
||||||
|
|
|
@ -22,4 +22,4 @@ def get_state_root(spec, state, slot) -> bytes:
|
||||||
Return the state root at a recent ``slot``.
|
Return the state root at a recent ``slot``.
|
||||||
"""
|
"""
|
||||||
assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT
|
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]
|
||||||
|
|
|
@ -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)
|
sign_transfer(spec, state, transfer, transfer_privkey)
|
||||||
|
|
||||||
# ensure withdrawal_credentials reproducible
|
# ensure withdrawal_credentials reproducible
|
||||||
state.validator_registry[transfer.sender].withdrawal_credentials = (
|
state.validators[transfer.sender].withdrawal_credentials = (
|
||||||
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
|
spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(transfer.pubkey)[1:]
|
||||||
)
|
)
|
||||||
|
|
||||||
return transfer
|
return transfer
|
||||||
|
|
|
@ -34,7 +34,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
|
||||||
# Process slashing
|
# Process slashing
|
||||||
spec.process_attester_slashing(state, attester_slashing)
|
spec.process_attester_slashing(state, attester_slashing)
|
||||||
|
|
||||||
slashed_validator = state.validator_registry[slashed_index]
|
slashed_validator = state.validators[slashed_index]
|
||||||
|
|
||||||
# Check slashing
|
# Check slashing
|
||||||
assert slashed_validator.slashed
|
assert slashed_validator.slashed
|
||||||
|
@ -135,7 +135,7 @@ def test_participants_already_slashed(spec, state):
|
||||||
attestation_1 = attester_slashing.attestation_1
|
attestation_1 = attester_slashing.attestation_1
|
||||||
validator_indices = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
|
validator_indices = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices
|
||||||
for index in validator_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)
|
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ def test_proposer_slashed(spec, state):
|
||||||
proposer_index = spec.get_beacon_proposer_index(stub_state)
|
proposer_index = spec.get_beacon_proposer_index(stub_state)
|
||||||
|
|
||||||
# set proposer to slashed
|
# 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)
|
block = build_empty_block_for_next_slot(spec, state, signed=True)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
|
||||||
- post-state ('post').
|
- post-state ('post').
|
||||||
If ``valid == False``, run expecting ``AssertionError``
|
If ``valid == False``, run expecting ``AssertionError``
|
||||||
"""
|
"""
|
||||||
pre_validator_count = len(state.validator_registry)
|
pre_validator_count = len(state.validators)
|
||||||
pre_balance = 0
|
pre_balance = 0
|
||||||
if validator_index < pre_validator_count:
|
if validator_index < pre_validator_count:
|
||||||
pre_balance = get_balance(state, validator_index)
|
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
|
yield 'post', state
|
||||||
|
|
||||||
if not effective:
|
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
|
assert len(state.balances) == pre_validator_count
|
||||||
if validator_index < pre_validator_count:
|
if validator_index < pre_validator_count:
|
||||||
assert get_balance(state, validator_index) == pre_balance
|
assert get_balance(state, validator_index) == pre_balance
|
||||||
else:
|
else:
|
||||||
if validator_index < pre_validator_count:
|
if validator_index < pre_validator_count:
|
||||||
# top-up
|
# top-up
|
||||||
assert len(state.validator_registry) == pre_validator_count
|
assert len(state.validators) == pre_validator_count
|
||||||
assert len(state.balances) == pre_validator_count
|
assert len(state.balances) == pre_validator_count
|
||||||
else:
|
else:
|
||||||
# new validator
|
# 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 len(state.balances) == pre_validator_count + 1
|
||||||
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
|
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
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_new_deposit(spec, state):
|
def test_new_deposit(spec, state):
|
||||||
# fresh deposit = next validator index = validator appended to registry
|
# 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
|
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
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
|
@spec_state_test
|
||||||
def test_invalid_sig_new_deposit(spec, state):
|
def test_invalid_sig_new_deposit(spec, state):
|
||||||
# fresh deposit = next validator index = validator appended to registry
|
# 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
|
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||||
yield from run_deposit_processing(spec, state, deposit, validator_index, valid=True, effective=False)
|
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):
|
def test_invalid_withdrawal_credentials_top_up(spec, state):
|
||||||
validator_index = 0
|
validator_index = 0
|
||||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
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(
|
deposit = prepare_state_and_deposit(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
|
@ -117,12 +117,12 @@ def test_invalid_withdrawal_credentials_top_up(spec, state):
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_wrong_index(spec, state):
|
def test_wrong_index(spec, state):
|
||||||
validator_index = len(state.validator_registry)
|
validator_index = len(state.validators)
|
||||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||||
|
|
||||||
# mess up deposit_index
|
# mess up eth1_deposit_index
|
||||||
deposit.index = state.deposit_index + 1
|
deposit.index = state.eth1_deposit_index + 1
|
||||||
|
|
||||||
sign_deposit_data(spec, state, deposit.data, privkeys[validator_index])
|
sign_deposit_data(spec, state, deposit.data, privkeys[validator_index])
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ def test_wrong_index(spec, state):
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_wrong_deposit_for_deposit_count(spec, state):
|
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
|
# build root for deposit_1
|
||||||
index_1 = len(deposit_data_leaves)
|
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 has root for deposit_2 but is at deposit_count for deposit_1
|
||||||
state.latest_eth1_data.deposit_root = root_2
|
state.eth1_data.deposit_root = root_2
|
||||||
state.latest_eth1_data.deposit_count = deposit_count_1
|
state.eth1_data.deposit_count = deposit_count_1
|
||||||
|
|
||||||
yield from run_deposit_processing(spec, state, deposit_2, index_2, valid=False)
|
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
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_bad_merkle_proof(spec, state):
|
def test_bad_merkle_proof(spec, state):
|
||||||
validator_index = len(state.validator_registry)
|
validator_index = len(state.validators)
|
||||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True)
|
||||||
yield 'post', state
|
yield 'post', state
|
||||||
|
|
||||||
# check if slashed
|
# 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.slashed
|
||||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||||
assert slashed_validator.withdrawable_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):
|
def test_invalid_proposer_index(spec, state):
|
||||||
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
# Index just too high (by 1)
|
# 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)
|
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)
|
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
|
|
||||||
# set proposer to be not active yet
|
# 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)
|
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)
|
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
|
|
||||||
# set proposer to slashed
|
# 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)
|
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
|
# set proposer withdrawable_epoch in past
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
proposer_index = proposer_slashing.proposer_index
|
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)
|
yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
|
||||||
|
|
|
@ -41,7 +41,7 @@ def run_transfer_processing(spec, state, transfer, valid=True):
|
||||||
def test_success_non_activated(spec, state):
|
def test_success_non_activated(spec, state):
|
||||||
transfer = get_valid_transfer(spec, state, signed=True)
|
transfer = get_valid_transfer(spec, state, signed=True)
|
||||||
# un-activate so validator can transfer
|
# 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)
|
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)
|
transfer = get_valid_transfer(spec, state, signed=True)
|
||||||
|
|
||||||
# withdrawable_epoch in past so can transfer
|
# 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)
|
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):
|
def test_invalid_signature(spec, state):
|
||||||
transfer = get_valid_transfer(spec, state)
|
transfer = get_valid_transfer(spec, state)
|
||||||
# un-activate so validator can transfer
|
# 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)
|
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):
|
def test_incorrect_slot(spec, state):
|
||||||
transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True)
|
transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True)
|
||||||
# un-activate so validator can transfer
|
# 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)
|
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)
|
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True)
|
||||||
|
|
||||||
# un-activate so validator can transfer
|
# 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)
|
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)
|
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True)
|
||||||
|
|
||||||
# un-activate so validator can transfer
|
# 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)
|
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
|
# 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)
|
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
|
state.balances[transfer.recipient] = 0
|
||||||
|
|
||||||
# un-activate so validator can transfer
|
# 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)
|
yield from run_transfer_processing(spec, state, transfer, False)
|
||||||
|
|
||||||
|
@ -176,9 +176,9 @@ def test_no_dust_recipient(spec, state):
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_invalid_pubkey(spec, state):
|
def test_invalid_pubkey(spec, state):
|
||||||
transfer = get_valid_transfer(spec, state, signed=True)
|
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
|
# 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)
|
yield from run_transfer_processing(spec, state, transfer, False)
|
||||||
|
|
|
@ -21,14 +21,14 @@ def run_voluntary_exit_processing(spec, state, voluntary_exit, valid=True):
|
||||||
yield 'post', None
|
yield 'post', None
|
||||||
return
|
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)
|
spec.process_voluntary_exit(state, voluntary_exit)
|
||||||
|
|
||||||
yield 'post', state
|
yield 'post', state
|
||||||
|
|
||||||
assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH
|
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
|
@with_all_phases
|
||||||
|
@ -39,7 +39,7 @@ def test_success(spec, state):
|
||||||
|
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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)
|
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)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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)
|
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
|
# Prepare a bunch of exits, based on the current state
|
||||||
exit_queue = []
|
exit_queue = []
|
||||||
for index in initial_indices:
|
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(
|
exit_queue.append(build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
|
@ -94,7 +94,7 @@ def test_success_exit_queue(spec, state):
|
||||||
|
|
||||||
# exit an additional validator
|
# exit an additional validator
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
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(
|
voluntary_exit = build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
state,
|
state,
|
||||||
|
@ -109,8 +109,8 @@ def test_success_exit_queue(spec, state):
|
||||||
yield from run_voluntary_exit_processing(spec, state, voluntary_exit)
|
yield from run_voluntary_exit_processing(spec, state, voluntary_exit)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
state.validator_registry[validator_index].exit_epoch ==
|
state.validators[validator_index].exit_epoch ==
|
||||||
state.validator_registry[initial_indices[0]].exit_epoch + 1
|
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)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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(
|
voluntary_exit = build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
|
@ -146,7 +146,7 @@ def test_validator_invalid_validator_index(spec, state):
|
||||||
|
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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(
|
voluntary_exit = build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
|
@ -156,7 +156,7 @@ def test_validator_invalid_validator_index(spec, state):
|
||||||
privkey,
|
privkey,
|
||||||
signed=False,
|
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)
|
sign_voluntary_exit(spec, state, voluntary_exit, privkey)
|
||||||
|
|
||||||
yield from run_voluntary_exit_processing(spec, state, voluntary_exit, False)
|
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):
|
def test_validator_not_active(spec, state):
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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
|
# build and test voluntary exit
|
||||||
voluntary_exit = build_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)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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
|
# 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(
|
voluntary_exit = build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
|
@ -214,7 +214,7 @@ def test_validator_already_exited(spec, state):
|
||||||
def test_validator_not_active_long_enough(spec, state):
|
def test_validator_not_active_long_enough(spec, state):
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
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(
|
voluntary_exit = build_voluntary_exit(
|
||||||
spec,
|
spec,
|
||||||
|
@ -226,7 +226,7 @@ def test_validator_not_active_long_enough(spec, state):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
current_epoch - state.validator_registry[validator_index].activation_epoch <
|
current_epoch - state.validators[validator_index].activation_epoch <
|
||||||
spec.PERSISTENT_COMMITTEE_PERIOD
|
spec.PERSISTENT_COMMITTEE_PERIOD
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -35,23 +35,23 @@ def run_process_registry_updates(spec, state, valid=True):
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_activation(spec, state):
|
def test_activation(spec, state):
|
||||||
index = 0
|
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
|
# Mock a new deposit
|
||||||
state.validator_registry[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
|
state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
|
||||||
state.validator_registry[index].activation_epoch = spec.FAR_FUTURE_EPOCH
|
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||||
state.validator_registry[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
|
state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
|
||||||
assert not spec.is_active_validator(state.validator_registry[index], spec.get_current_epoch(state))
|
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
|
||||||
|
|
||||||
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
|
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
|
||||||
next_epoch(spec, state)
|
next_epoch(spec, state)
|
||||||
|
|
||||||
yield from run_process_registry_updates(spec, state)
|
yield from run_process_registry_updates(spec, state)
|
||||||
|
|
||||||
assert state.validator_registry[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
|
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
|
||||||
assert state.validator_registry[index].activation_epoch != spec.FAR_FUTURE_EPOCH
|
assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||||
assert spec.is_active_validator(
|
assert spec.is_active_validator(
|
||||||
state.validator_registry[index],
|
state.validators[index],
|
||||||
spec.get_current_epoch(state),
|
spec.get_current_epoch(state),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,19 +60,19 @@ def test_activation(spec, state):
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_ejection(spec, state):
|
def test_ejection(spec, state):
|
||||||
index = 0
|
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))
|
||||||
assert state.validator_registry[index].exit_epoch == spec.FAR_FUTURE_EPOCH
|
assert state.validators[index].exit_epoch == spec.FAR_FUTURE_EPOCH
|
||||||
|
|
||||||
# Mock an ejection
|
# 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):
|
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
|
||||||
next_epoch(spec, state)
|
next_epoch(spec, state)
|
||||||
|
|
||||||
yield from run_process_registry_updates(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(
|
assert not spec.is_active_validator(
|
||||||
state.validator_registry[index],
|
state.validators[index],
|
||||||
spec.get_current_epoch(state),
|
spec.get_current_epoch(state),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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)
|
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:
|
if randao_key_reveal.epoch >= spec.get_current_epoch(state) + spec.CUSTODY_PERIOD_TO_RANDAO_PADDING:
|
||||||
assert slashed_validator.slashed
|
assert slashed_validator.slashed
|
||||||
|
@ -111,7 +111,7 @@ def test_double_reveal(spec, state):
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_revealer_is_slashed(spec, state):
|
def test_revealer_is_slashed(spec, state):
|
||||||
randao_key_reveal = get_valid_early_derived_secret_reveal(spec, state, spec.get_current_epoch(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)
|
yield from run_early_derived_secret_reveal_processing(spec, state, randao_key_reveal, False)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from eth2spec.utils.ssz.ssz_impl import signing_root
|
||||||
from eth2spec.utils.bls import bls_sign
|
from eth2spec.utils.bls import bls_sign
|
||||||
|
|
||||||
from eth2spec.test.helpers.state import get_balance
|
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.block import build_empty_block_for_next_slot, sign_block
|
||||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||||
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing
|
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.slot == block.slot
|
||||||
# assert state.finalized_epoch < spec.get_current_epoch(state) - 4
|
# 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)
|
# 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)
|
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
validator_index = proposer_slashing.proposer_index
|
validator_index = proposer_slashing.proposer_index
|
||||||
|
|
||||||
assert not state.validator_registry[validator_index].slashed
|
assert not state.validators[validator_index].slashed
|
||||||
|
|
||||||
yield 'pre', state
|
yield 'pre', state
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ def test_proposer_slashing(spec, state):
|
||||||
yield 'post', state
|
yield 'post', state
|
||||||
|
|
||||||
# check if slashed
|
# check if slashed
|
||||||
slashed_validator = state.validator_registry[validator_index]
|
slashed_validator = state.validators[validator_index]
|
||||||
assert slashed_validator.slashed
|
assert slashed_validator.slashed
|
||||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||||
assert slashed_validator.withdrawable_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 +
|
validator_index = (attester_slashing.attestation_1.custody_bit_0_indices +
|
||||||
attester_slashing.attestation_1.custody_bit_1_indices)[0]
|
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
|
yield 'pre', state
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ def test_attester_slashing(spec, state):
|
||||||
spec.state_transition(state, block)
|
spec.state_transition(state, block)
|
||||||
yield 'post', state
|
yield 'post', state
|
||||||
|
|
||||||
slashed_validator = state.validator_registry[validator_index]
|
slashed_validator = state.validators[validator_index]
|
||||||
assert slashed_validator.slashed
|
assert slashed_validator.slashed
|
||||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||||
assert slashed_validator.withdrawable_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
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_deposit_in_block(spec, state):
|
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)
|
initial_balances_len = len(state.balances)
|
||||||
|
|
||||||
validator_index = len(state.validator_registry)
|
validator_index = len(state.validators)
|
||||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
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)
|
spec.state_transition(state, block)
|
||||||
yield 'post', state
|
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 len(state.balances) == initial_balances_len + 1
|
||||||
assert get_balance(state, validator_index) == spec.MAX_EFFECTIVE_BALANCE
|
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
|
@with_all_phases
|
||||||
|
@ -203,7 +203,7 @@ def test_deposit_top_up(spec, state):
|
||||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
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)
|
initial_balances_len = len(state.balances)
|
||||||
validator_pre_balance = get_balance(state, validator_index)
|
validator_pre_balance = get_balance(state, validator_index)
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ def test_deposit_top_up(spec, state):
|
||||||
spec.state_transition(state, block)
|
spec.state_transition(state, block)
|
||||||
yield 'post', state
|
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 len(state.balances) == initial_balances_len
|
||||||
assert get_balance(state, validator_index) == validator_pre_balance + amount
|
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)
|
sign_block(spec, state, initiate_exit_block)
|
||||||
spec.state_transition(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
|
# Process within epoch transition
|
||||||
exit_block = build_empty_block_for_next_slot(spec, state)
|
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 'blocks', [initiate_exit_block, exit_block], List[spec.BeaconBlock]
|
||||||
yield 'post', state
|
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
|
# @with_all_phases
|
||||||
@spec_state_test
|
# @spec_state_test
|
||||||
def test_transfer(spec, state):
|
# def test_transfer(spec, state):
|
||||||
# overwrite default 0 to test
|
# 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]
|
# sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
|
||||||
amount = get_balance(state, sender_index)
|
# amount = get_balance(state, sender_index)
|
||||||
|
|
||||||
transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
|
# transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
|
||||||
recipient_index = transfer.recipient
|
# recipient_index = transfer.recipient
|
||||||
pre_transfer_recipient_balance = get_balance(state, recipient_index)
|
# pre_transfer_recipient_balance = get_balance(state, recipient_index)
|
||||||
|
|
||||||
# un-activate so validator can transfer
|
# 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
|
# Add to state via block transition
|
||||||
block = build_empty_block_for_next_slot(spec, state)
|
# block = build_empty_block_for_next_slot(spec, state)
|
||||||
block.body.transfers.append(transfer)
|
# block.body.transfers.append(transfer)
|
||||||
sign_block(spec, state, block)
|
# sign_block(spec, state, block)
|
||||||
|
|
||||||
yield 'blocks', [block], List[spec.BeaconBlock]
|
# yield 'blocks', [block], List[spec.BeaconBlock]
|
||||||
|
|
||||||
spec.state_transition(state, block)
|
# spec.state_transition(state, block)
|
||||||
yield 'post', state
|
# yield 'post', state
|
||||||
|
|
||||||
sender_balance = get_balance(state, sender_index)
|
# sender_balance = get_balance(state, sender_index)
|
||||||
recipient_balance = get_balance(state, recipient_index)
|
# recipient_balance = get_balance(state, recipient_index)
|
||||||
assert sender_balance == 0
|
# assert sender_balance == 0
|
||||||
assert recipient_balance == pre_transfer_recipient_balance + amount
|
# assert recipient_balance == pre_transfer_recipient_balance + amount
|
||||||
|
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
|
@ -343,10 +343,10 @@ def test_balance_driven_status_transitions(spec, state):
|
||||||
current_epoch = spec.get_current_epoch(state)
|
current_epoch = spec.get_current_epoch(state)
|
||||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
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
|
# 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
|
yield 'pre', state
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ def test_balance_driven_status_transitions(spec, state):
|
||||||
yield 'blocks', [block], List[spec.BeaconBlock]
|
yield 'blocks', [block], List[spec.BeaconBlock]
|
||||||
yield 'post', state
|
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
|
@with_all_phases
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import Dict, Any, Callable, Iterable
|
from typing import Dict, Any, Callable, Iterable
|
||||||
from eth2spec.debug.encode import encode
|
from eth2spec.debug.encode import encode
|
||||||
|
from eth2spec.utils.ssz.ssz_typing import Container
|
||||||
|
|
||||||
|
|
||||||
def spectest(description: str = None):
|
def spectest(description: str = None):
|
||||||
|
@ -30,9 +31,13 @@ def spectest(description: str = None):
|
||||||
else:
|
else:
|
||||||
# Otherwise, try to infer the type, but keep it as-is if it's not a SSZ container.
|
# Otherwise, try to infer the type, but keep it as-is if it's not a SSZ container.
|
||||||
(key, value) = data
|
(key, value) = data
|
||||||
if hasattr(value.__class__, 'fields'):
|
if isinstance(value, Container):
|
||||||
out[key] = encode(value, value.__class__)
|
out[key] = encode(value, value.__class__)
|
||||||
else:
|
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
|
out[key] = value
|
||||||
if has_contents:
|
if has_contents:
|
||||||
return out
|
return out
|
||||||
|
|
|
@ -1,5 +1,28 @@
|
||||||
from hashlib import sha256
|
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):
|
def hash(x):
|
||||||
return sha256(x).digest()
|
for (k, h) in hash_cache:
|
||||||
|
if x == k:
|
||||||
|
return h
|
||||||
|
return _hash(x)
|
||||||
|
|
|
@ -534,13 +534,11 @@ def read_vector_elem_type(vector_typ: Type[Vector[T, L]]) -> T:
|
||||||
|
|
||||||
|
|
||||||
def read_elem_type(typ):
|
def read_elem_type(typ):
|
||||||
if typ == bytes:
|
if typ == bytes or (isinstance(typ, type) and issubclass(typ, bytes)): # bytes or bytesN
|
||||||
return byte
|
return byte
|
||||||
elif is_list_type(typ):
|
elif is_list_type(typ):
|
||||||
return read_list_elem_type(typ)
|
return read_list_elem_type(typ)
|
||||||
elif is_vector_type(typ):
|
elif is_vector_type(typ):
|
||||||
return read_vector_elem_type(typ)
|
return read_vector_elem_type(typ)
|
||||||
elif issubclass(typ, bytes): # bytes or bytesN
|
|
||||||
return byte
|
|
||||||
else:
|
else:
|
||||||
raise TypeError("Unexpected type: {}".format(typ))
|
raise TypeError("Unexpected type: {}".format(typ))
|
||||||
|
|
Loading…
Reference in New Issue