Skip to content

Commit 2c2404a

Browse files
CarlBeekadiasg
andauthored
Local slashing db (#3)
* Migrate consensus specs from a submodule to the pypi eth2specs * Move from install script to Makefile & add linting * All of the linting * Move over to local slashing db & start defining own types * Add ValidatorIdentity, fix tests, fix imports * Revert to relative imports in src/dvspec/* module files * Add glossary * Update UML diagrams * Formatting in glossary Co-authored-by: Aditya Asgaonkar <[email protected]>
1 parent f444d69 commit 2c2404a

File tree

11 files changed

+281
-83
lines changed

11 files changed

+281
-83
lines changed

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ venv_activate:
2525
$(VENV_ACTIVATE)
2626

2727
venv_lint: venv_activate
28-
flake8 --config=flake8.ini ./src ./tests && mypy --config-file mypy.ini ./src ./tests
28+
$(VENV_ACTIVATE) && flake8 --config=flake8.ini ./src ./tests && mypy --config-file mypy.ini ./src ./tests
2929

3030
venv_test: venv_activate
3131
@echo "TODO: implement tests"
32-

consensus-specs

Submodule consensus-specs added at 58b291b
125 KB
Loading
119 KB
Loading

glossary.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Glossary
2+
3+
## Ethereum Concepts
4+
5+
- **Validator**: A public key participating in proof-of-stake validation of Ethereum. In Phase 0, validators are expected to perform attestation & block proposal duties for beacon chain blocks.
6+
- **Validator Client (VC)**: Software to perform the duties of Validators. The VC has access to the private key of the Validators.
7+
8+
## Distributed Validator Concepts
9+
10+
- **Distributed Validator (DV)**: A group of participants collboratively performing the duties of a Validator. The Validator's private key is secret-shared among the participants so that a complete signature cannot be formed without some majority threshold of participants.
11+
- **Co-Validator**: A threshold BLS public key participating in the DV protocol for a *particular* Validator.
12+
- **Distributed Validator Client (DVC)**: Software to participate as a Co-Validator by running the DV protocol (or, to participate as multiple Co-Validators that are each associated with a different Validator). The DVC has access to the private key(s) of the Co-Validator(s), which is(are) the secret-shared threshold private key of the respective Validator(s).

src/dvspec/consensus.py

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,78 @@
1-
from dvspec.eth_node_interface import (
1+
import eth2spec.phase0.mainnet as eth2spec
2+
3+
from .eth_node_interface import (
24
AttestationData,
3-
AttestationDuty,
45
BeaconBlock,
6+
)
7+
from .utils.types import (
8+
AttestationDuty,
9+
BLSPubkey,
510
ProposerDuty,
6-
vc_is_slashable_attestation_data,
7-
vc_is_slashable_block
11+
SlashingDB,
812
)
913

14+
"""
15+
Helper Functions
16+
"""
17+
18+
19+
def is_slashable_attestation_data(slashing_db: SlashingDB,
20+
attestation_data: AttestationData, pubkey: BLSPubkey) -> bool:
21+
matching_slashing_db_data = [data for data in slashing_db.data if data.pubkey == pubkey]
22+
if matching_slashing_db_data == []:
23+
return True
24+
assert len(matching_slashing_db_data) == 1
25+
slashing_db_data = matching_slashing_db_data[0]
26+
# Check for EIP-3076 conditions:
27+
# https://eips.ethereum.org/EIPS/eip-3076#conditions
28+
if slashing_db_data.signed_attestations != []:
29+
min_target = min(attn.target_epoch for attn in slashing_db_data.signed_attestations)
30+
min_source = min(attn.source_epoch for attn in slashing_db_data.signed_attestations)
31+
if attestation_data.target.epoch <= min_target:
32+
return True
33+
if attestation_data.source.epoch < min_source:
34+
return True
35+
for past_attn in slashing_db_data.signed_attestations:
36+
past_attn_data = AttestationData(source=past_attn.source_epoch, target=past_attn.target_epoch)
37+
if eth2spec.is_slashable_attestation_data(past_attn_data, attestation_data):
38+
return True
39+
return False
40+
41+
42+
def is_slashable_block(slashing_db: SlashingDB, block: BeaconBlock, pubkey: BLSPubkey) -> bool:
43+
matching_slashing_db_data = [data for data in slashing_db.data if data.pubkey == pubkey]
44+
if matching_slashing_db_data == []:
45+
return False
46+
assert len(matching_slashing_db_data) == 1
47+
slashing_db_data = matching_slashing_db_data[0]
48+
# Check for EIP-3076 conditions:
49+
# https://eips.ethereum.org/EIPS/eip-3076#conditions
50+
if slashing_db_data.signed_blocks != []:
51+
min_block = slashing_db_data.signed_blocks[0]
52+
for b in slashing_db_data.signed_blocks[1:]:
53+
if b.slot < min_block.slot:
54+
min_block = b
55+
if block.slot < min_block.slot:
56+
return True
57+
for past_block in slashing_db_data.signed_blocks:
58+
if past_block.slot == block.slot:
59+
if past_block.signing_root() != block.hash_tree_root():
60+
return True
61+
return False
62+
63+
1064
"""
1165
Consensus Specification
1266
"""
1367

1468

15-
def consensus_is_valid_attestation_data(attestation_data: AttestationData, attestation_duty: AttestationDuty) -> bool:
69+
def consensus_is_valid_attestation_data(slashing_db: SlashingDB,
70+
attestation_data: AttestationData, attestation_duty: AttestationDuty) -> bool:
1671
"""Determines if the given attestation is valid for the attestation duty.
1772
"""
1873
assert attestation_data.slot == attestation_duty.slot
1974
assert attestation_data.committee_index == attestation_duty.committee_index
20-
assert not vc_is_slashable_attestation_data(attestation_data, attestation_duty.pubkey)
75+
assert not is_slashable_attestation_data(slashing_db, attestation_data, attestation_duty.pubkey)
2176
return True
2277

2378

@@ -30,12 +85,12 @@ def consensus_on_attestation(attestation_duty: AttestationDuty) -> AttestationDa
3085
pass
3186

3287

33-
def consensus_is_valid_block(block: BeaconBlock, proposer_duty: ProposerDuty) -> bool:
88+
def consensus_is_valid_block(slashing_db: SlashingDB, block: BeaconBlock, proposer_duty: ProposerDuty) -> bool:
3489
"""Determines if the given block is valid for the proposer duty.
3590
"""
3691
assert block.slot == proposer_duty.slot
3792
# TODO: Assert correct block.proposer_index
38-
assert not vc_is_slashable_block(block, proposer_duty.pubkey)
93+
assert not is_slashable_block(slashing_db, block, proposer_duty.pubkey)
3994
return True
4095

4196

src/dvspec/eth_node_interface.py

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,21 @@
33
Attestation,
44
AttestationData,
55
BeaconBlock,
6-
BLSPubkey,
6+
SignedBeaconBlock,
7+
)
8+
9+
from .utils.types import (
10+
AttestationDuty,
711
BLSSignature,
812
Bytes32,
913
CommitteeIndex,
10-
Container,
1114
Epoch,
12-
SignedBeaconBlock,
15+
ProposerDuty,
1316
Slot,
14-
uint64,
1517
ValidatorIndex,
1618
)
1719

1820

19-
class AttestationDuty(Container):
20-
pubkey: BLSPubkey
21-
validator_index: ValidatorIndex
22-
committee_index: CommitteeIndex
23-
committee_length: uint64
24-
committees_at_slot: uint64
25-
validator_committee_index: ValidatorIndex # TODO: Is this the correct datatype?
26-
slot: Slot
27-
28-
29-
class ProposerDuty(Container):
30-
pubkey: BLSPubkey
31-
validator_index: ValidatorIndex
32-
slot: Slot
33-
34-
3521
# Beacon Node Interface
3622

3723
def bn_get_attestation_duties_for_epoch(validator_indices: List[ValidatorIndex], epoch: Epoch) -> List[AttestationDuty]:
@@ -80,12 +66,6 @@ def bn_submit_block(block: SignedBeaconBlock) -> None:
8066

8167
# Validator Client Interface
8268

83-
def vc_is_slashable_attestation_data(attestation_data: AttestationData, validator_pubkey: BLSPubkey) -> bool:
84-
"""Checks whether the attestation data is slashable according to the anti-slashing database.
85-
This endpoint does not exist in beacon-APIs.
86-
"""
87-
pass
88-
8969

9070
def vc_sign_attestation(attestation_data: AttestationData, attestation_duty: AttestationDuty) -> Attestation:
9171
"""Returns a signed attestations that is constructed using the given attestation data & attestation duty.
@@ -96,13 +76,6 @@ def vc_sign_attestation(attestation_data: AttestationData, attestation_duty: Att
9676
pass
9777

9878

99-
def vc_is_slashable_block(block: BeaconBlock, validator_pubkey: BLSPubkey) -> bool:
100-
"""Checks whether the block is slashable according to the anti-slashing database.
101-
This endpoint does not exist in beacon-APIs.
102-
"""
103-
pass
104-
105-
10679
def vc_sign_block(block: BeaconBlock, proposer_duty: ProposerDuty) -> SignedBeaconBlock:
10780
"""Returns a signed beacon block using the validator index given in the proposer duty.
10881
This endpoint does not exist in beacon-APIs.

src/dvspec/spec.py

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,69 @@
1-
from dvspec.eth_node_interface import (
1+
from dataclasses import dataclass
2+
from typing import (
3+
List,
4+
)
5+
6+
from .eth_node_interface import (
27
AttestationDuty,
38
bn_submit_attestation,
49
bn_submit_block,
510
ProposerDuty,
611
vc_sign_attestation,
712
vc_sign_block,
813
)
9-
from dvspec.consensus import (
14+
from .consensus import (
1015
consensus_on_attestation,
1116
consensus_on_block,
1217
)
13-
from dvspec.networking import (
18+
from .networking import (
1419
broadcast_threshold_signed_attestation,
1520
broadcast_threshold_signed_block,
1621
construct_signed_attestation,
1722
construct_signed_block,
1823
listen_for_threshold_signed_attestations,
1924
listen_for_threshold_signed_blocks
2025
)
26+
from .utils.types import (
27+
BLSPubkey,
28+
SlashingDB,
29+
UInt64
30+
)
31+
32+
33+
@dataclass
34+
class ValidatorIdentity:
35+
"""Identity of the Ethereum validator.
36+
"""
37+
# Ethereum public key
38+
pubkey: BLSPubkey
39+
# Index of Ethereum validator
40+
index: UInt64
41+
42+
43+
@dataclass
44+
class CoValidator:
45+
"""Identity of distributed co-validator participating in the DV protocol.
46+
"""
47+
# Identity of Ethereum validator that this co-validator performs duties for
48+
validator_identity: ValidatorIdentity
49+
# Secret-shared public key
50+
pubkey: BLSPubkey
51+
# Index of the co-validator in the distributed validator protocol
52+
index: UInt64
53+
54+
55+
@dataclass
56+
class DistributedValidator:
57+
"""State object that tracks a single Ethereum validator being run using the distributed validator protocol.
58+
"""
59+
validator_identity: ValidatorIdentity
60+
co_validators: List[CoValidator]
61+
slashing_db: SlashingDB
62+
63+
64+
@dataclass
65+
class State:
66+
distributed_validators: List[DistributedValidator]
2167

2268

2369
def serve_attestation_duty(attestation_duty: AttestationDuty) -> None:
@@ -28,7 +74,6 @@ def serve_attestation_duty(attestation_duty: AttestationDuty) -> None:
2874
2. For each attestation_duty received in Step 1, schedule
2975
serve_attestation_duty(attestation_duty) at 1/3rd way through the slot
3076
attestation_duty.slot
31-
3277
See notes here:
3378
https://github.com/ethereum/beacon-APIs/blob/05c1bc142e1a3fb2a63c79098743776241341d08/validator-flow.md#attestation
3479
"""
@@ -50,7 +95,6 @@ def serve_proposer_duty(proposer_duty: ProposerDuty) -> None:
5095
bn_get_proposer_duties_for_epoch(epoch+1)
5196
2. For each proposer_duty received in Step 1 for our validators, schedule
5297
serve_proposer_duty(proposer_duty) at beginning of slot proposer_duty.slot
53-
5498
See notes here:
5599
https://github.com/ethereum/beacon-APIs/blob/05c1bc142e1a3fb2a63c79098743776241341d08/validator-flow.md#block-proposing
56100
"""

src/dvspec/utils/__init__.py

Whitespace-only changes.

src/dvspec/utils/types.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from dataclasses import dataclass
2+
from typing import (
3+
List,
4+
)
5+
6+
7+
"""
8+
Basic Datatypes
9+
"""
10+
11+
12+
UInt64 = int
13+
Bytes32 = bytes
14+
Bytes48 = bytes
15+
Bytes96 = bytes
16+
17+
18+
"""
19+
Aliased Data Types
20+
"""
21+
22+
Epoch = UInt64
23+
BLSPubkey = Bytes48
24+
BLSSignature = Bytes96
25+
CommitteeIndex = UInt64
26+
CommitteeLength = UInt64
27+
Root = Bytes32
28+
Slot = UInt64
29+
ValidatorIndex = UInt64
30+
Version = UInt64
31+
32+
33+
"""
34+
Types for EIP-3076 Slashing DB.
35+
See here for details:
36+
https://eips.ethereum.org/EIPS/eip-3076
37+
"""
38+
39+
40+
@dataclass
41+
class SlashingDBBlock:
42+
slot: Slot
43+
signing_root: Root
44+
45+
46+
@dataclass
47+
class SlashingDBAttestation:
48+
source_epoch: Epoch
49+
target_epoch: Epoch
50+
signing_root: Root
51+
52+
53+
@dataclass
54+
class SlashingDBData:
55+
pubkey: BLSPubkey
56+
signed_blocks: List[SlashingDBBlock]
57+
signed_attestations: List[SlashingDBAttestation]
58+
59+
60+
@dataclass
61+
class SlashingDB:
62+
interchange_format_version: Version
63+
genesis_validators_root: Root
64+
data: List[SlashingDBData]
65+
66+
67+
"""
68+
Types for talking to VCs and BNs
69+
"""
70+
71+
72+
@dataclass
73+
class AttestationDuty:
74+
pubkey: BLSPubkey
75+
validator_index: ValidatorIndex
76+
committee_index: CommitteeIndex
77+
committee_length: UInt64
78+
committees_at_slot: UInt64
79+
validator_committee_index: ValidatorIndex # TODO: Is this the correct datatype?
80+
slot: Slot
81+
82+
83+
@dataclass
84+
class ProposerDuty:
85+
pubkey: BLSPubkey
86+
validator_index: ValidatorIndex
87+
slot: Slot

0 commit comments

Comments
 (0)