Skip to content

Commit a8cd25e

Browse files
committed
Simple StateMachine
1 parent bfa1f2f commit a8cd25e

File tree

12 files changed

+325
-7
lines changed

12 files changed

+325
-7
lines changed

eth/beacon/state_machines/base.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from abc import (
2+
ABC,
3+
)
4+
from typing import (
5+
Tuple,
6+
Type,
7+
)
8+
9+
from eth.utils.datatypes import (
10+
Configurable,
11+
)
12+
13+
from eth.beacon.db.chain import BaseBeaconChainDB
14+
from eth.beacon.types.blocks import BaseBeaconBlock
15+
from eth.beacon.types.states import BeaconState
16+
17+
18+
from .state_transitions import (
19+
BaseStateTransition,
20+
)
21+
from .configs import ( # noqa: F401
22+
BeaconConfig,
23+
)
24+
25+
26+
class BaseBeaconStateMachine(Configurable, ABC):
27+
fork = None # type: str
28+
chaindb = None # type: BaseBeaconChainDB
29+
config = None # type: BeaconConfig
30+
31+
block = None # type: BaseBeaconBlock
32+
state = None # type: BeaconState
33+
34+
block_class = None # type: Type[BaseBeaconBlock]
35+
state_class = None # type: Type[BeaconState]
36+
state_transition_class = None # type: Type[BaseStateTransition]
37+
38+
39+
class BeaconStateMachine(BaseBeaconStateMachine):
40+
def __init__(self,
41+
chaindb: BaseBeaconChainDB,
42+
block: BaseBeaconBlock,
43+
state: BeaconState) -> None:
44+
# TODO: get state from DB, now it's just a stub!
45+
self.state = state
46+
47+
@classmethod
48+
def get_block_class(cls) -> Type[BaseBeaconBlock]:
49+
"""
50+
Return the :class:`~eth.beacon.types.blocks.BeaconBlock` class that this
51+
StateMachine uses for blocks.
52+
"""
53+
if cls.block_class is None:
54+
raise AttributeError("No `block_class` has been set for this StateMachine")
55+
else:
56+
return cls.block_class
57+
58+
@classmethod
59+
def get_state_class(cls) -> Type[BeaconState]:
60+
"""
61+
Return the :class:`~eth.beacon.types.states.BeaconState` class that this
62+
StateMachine uses for BeaconState.
63+
"""
64+
if cls.state_class is None:
65+
raise AttributeError("No `state_class` has been set for this StateMachine")
66+
else:
67+
return cls.state_class
68+
69+
@classmethod
70+
def get_state_transiton_class(cls) -> Type[BaseStateTransition]:
71+
"""
72+
Return the :class:`~eth.beacon.state_machines.state_transition.state_transition_class`
73+
class that this StateTransition uses for BeaconState.
74+
"""
75+
if cls.state_transition_class is None:
76+
raise AttributeError("No `state_transition_class` has been set for this StateMachine")
77+
else:
78+
return cls.state_transition_class
79+
80+
@property
81+
def state_transition(self) -> BaseStateTransition:
82+
return self.get_state_transiton_class()(self.config)
83+
84+
#
85+
# Import block API
86+
#
87+
def import_block(self, block: BaseBeaconBlock) -> Tuple[BeaconState, BaseBeaconBlock]:
88+
state = self.state_transition.apply_state_transition(
89+
self.state,
90+
block,
91+
)
92+
# TODO: Validate state roots
93+
# TODO: Update self.state
94+
# TODO: persist states in BeaconChain
95+
return state, block

eth/beacon/state_machines/configs.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
('TARGET_COMMITTEE_SIZE', int),
1616
('EJECTION_BALANCE', int),
1717
('MAX_BALANCE_CHURN_QUOTIENT', int),
18-
('GWEI_PER_ETH', int),
1918
('BEACON_CHAIN_SHARD_NUMBER', int),
2019
('BLS_WITHDRAWAL_PREFIX_BYTE', bytes),
2120
('MAX_CASPER_VOTES', int),
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import Type # noqa: F401
2+
3+
from eth.beacon.types.blocks import BaseBeaconBlock # noqa: F401
4+
from eth.beacon.types.states import BeaconState # noqa: F401
5+
6+
from eth.beacon.state_machines.base import BeaconStateMachine
7+
from eth.beacon.state_machines.state_transitions import BaseStateTransition # noqa: F401
8+
9+
from .blocks import SerenityBeaconBlock
10+
from .states import SerenityBeaconState
11+
from .state_transitions import SerenityStateTransition
12+
from .configs import SERENITY_CONFIG
13+
14+
15+
class SerenityStateMachine(BeaconStateMachine):
16+
# fork name
17+
fork = 'serenity' # type: str
18+
19+
# classes
20+
block_class = SerenityBeaconBlock # type: Type[BaseBeaconBlock]
21+
state_class = SerenityBeaconState # type: Type[BeaconState]
22+
state_transition_class = SerenityStateTransition # type: Type[BaseStateTransition]
23+
config = SERENITY_CONFIG
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from eth.beacon.types.blocks import BaseBeaconBlock
2+
3+
4+
class SerenityBeaconBlock(BaseBeaconBlock):
5+
pass

eth/beacon/state_machines/forks/serenity/configs.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
TARGET_COMMITTEE_SIZE=2**8, # (= 256) validators
1111
EJECTION_BALANCE=2**4, # (= 16) ETH
1212
MAX_BALANCE_CHURN_QUOTIENT=2**5, # (= 32)
13-
GWEI_PER_ETH=10**9, # Gwei/ETH
1413
BEACON_CHAIN_SHARD_NUMBER=2**64 - 1,
1514
BLS_WITHDRAWAL_PREFIX_BYTE=b'\x00',
1615
MAX_CASPER_VOTES=2**10, # (= 1,024) votes
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from eth.beacon.types.blocks import BaseBeaconBlock
2+
from eth.beacon.types.states import BeaconState
3+
from eth.beacon.state_machines.configs import BeaconConfig
4+
5+
6+
def process_attestations(state: BeaconState,
7+
block: BaseBeaconBlock,
8+
config: BeaconConfig) -> BeaconState:
9+
# TODO
10+
# It's just for demo!!!
11+
state = state.copy(
12+
slot=config.ZERO_BALANCE_VALIDATOR_TTL,
13+
)
14+
return state
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from eth.beacon.types.blocks import BaseBeaconBlock
2+
from eth.beacon.types.states import BeaconState
3+
4+
from eth.beacon.state_machines.configs import BeaconConfig
5+
from eth.beacon.state_machines.state_transitions import BaseStateTransition
6+
7+
from .operations import (
8+
process_attestations,
9+
)
10+
11+
12+
class SerenityStateTransition(BaseStateTransition):
13+
config = None
14+
15+
def __init__(self, config: BeaconConfig):
16+
self.config = config
17+
18+
def apply_state_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
19+
state = self.per_slot_transition(state, block)
20+
state = self.per_block_transition(state, block)
21+
state = self.per_epoch_transition(state, block)
22+
23+
return state
24+
25+
def per_slot_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
26+
state = process_attestations(state, block, self.config)
27+
# TODO
28+
return state
29+
30+
def per_block_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
31+
# TODO
32+
return state
33+
34+
def per_epoch_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
35+
# TODO
36+
return state
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from eth.beacon.types.states import BeaconState
2+
3+
4+
class SerenityBeaconState(BeaconState):
5+
pass
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from abc import (
2+
ABC,
3+
abstractmethod,
4+
)
5+
6+
from eth.utils.datatypes import (
7+
Configurable,
8+
)
9+
10+
from eth.beacon.types.blocks import BaseBeaconBlock
11+
from eth.beacon.types.states import BeaconState
12+
13+
from eth.beacon.state_machines.configs import BeaconConfig
14+
15+
16+
class BaseStateTransition(Configurable, ABC):
17+
config = None
18+
19+
def __init__(self, config: BeaconConfig):
20+
self.config = config
21+
22+
@abstractmethod
23+
def apply_state_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
24+
pass
25+
26+
@abstractmethod
27+
def per_slot_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
28+
pass
29+
30+
@abstractmethod
31+
def per_block_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
32+
pass
33+
34+
@abstractmethod
35+
def per_epoch_transition(self, state: BeaconState, block: BaseBeaconBlock) -> BeaconState:
36+
pass

tests/beacon/conftest.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,6 @@ def max_balance_churn_quotient():
340340
return SERENITY_CONFIG.MAX_BALANCE_CHURN_QUOTIENT
341341

342342

343-
@pytest.fixture
344-
def gwei_per_eth():
345-
return SERENITY_CONFIG.GWEI_PER_ETH
346-
347-
348343
@pytest.fixture
349344
def beacon_chain_shard_number():
350345
return SERENITY_CONFIG.BEACON_CHAIN_SHARD_NUMBER
@@ -385,6 +380,16 @@ def max_deposit():
385380
return SERENITY_CONFIG.MAX_DEPOSIT
386381

387382

383+
@pytest.fixture
384+
def initial_fork_version():
385+
return SERENITY_CONFIG.INITIAL_FORK_VERSION
386+
387+
388+
@pytest.fixture
389+
def initial_slot_number():
390+
return SERENITY_CONFIG.INITIAL_SLOT_NUMBER
391+
392+
388393
@pytest.fixture
389394
def slot_duration():
390395
return SERENITY_CONFIG.SLOT_DURATION

0 commit comments

Comments
 (0)