Skip to content

Commit f42dafd

Browse files
authored
Merge pull request #186 from thenewboston-developers/BC-189-pv-notifies-pvs
filter_by_roles()
2 parents 21dc40c + 8f78ffe commit f42dafd

File tree

21 files changed

+221
-30
lines changed

21 files changed

+221
-30
lines changed

node/blockchain/facade.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ def has_blocks():
127127
def get_last_block():
128128
return get_block_model().objects.get_last_block()
129129

130-
def get_next_block_number(self) -> int:
130+
@staticmethod
131+
def get_next_block_number() -> int:
131132
# TODO(dmu) HIGH: Implement method via write-through cache
132133
# https://thenewboston.atlassian.net/browse/BC-175
133-
last_block = self.get_last_block()
134-
return last_block._id + 1 if last_block else 0
134+
return get_block_model().objects.get_next_block_number()
135135

136136
def get_next_block_identifier(self) -> Optional[BlockIdentifier]:
137137
# TODO(dmu) HIGH: Implement method via write-through cache
@@ -239,7 +239,7 @@ def get_primary_validator(self) -> Optional[Node]:
239239
"""
240240
from node.blockchain.models import Schedule
241241

242-
schedule = Schedule.objects.filter(_id__lte=self.get_next_block_number()).order_by('-_id').first()
242+
schedule = Schedule.objects.get_schedule_for_next_block()
243243
if not schedule:
244244
logger.warning('Schedule for the next block was not found')
245245
return None

node/blockchain/models/block.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ def create(self, *args, **kwargs):
1414
def get_last_block(self):
1515
return self.order_by('-_id').first()
1616

17+
def get_next_block_number(self):
18+
last_block = self.get_last_block()
19+
return last_block._id + 1 if last_block else 0
20+
1721

1822
class Block(CustomModel):
1923
_id = models.PositiveBigIntegerField('Block number', primary_key=True)

node/blockchain/models/node.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,54 @@
1+
from typing import Collection
2+
13
from djongo.models.fields import DjongoManager
24

35
from node.blockchain.inner_models import Node as PydanticNode
6+
from node.blockchain.types import NodeRole
47
from node.core.managers import CustomQuerySet
58

69
from .account_state import AccountState
710

11+
NODE_ROLES = set(NodeRole)
12+
13+
14+
class NodeQuerySet(CustomQuerySet):
15+
16+
def filter_by_roles(self, roles: Collection[NodeRole]):
17+
# self.annotate() does not work with Djongo
18+
roles = set(roles or ())
19+
if not roles or set(roles) == NODE_ROLES:
20+
return self
21+
22+
from node.blockchain.models import Schedule
23+
24+
assert {NodeRole.REGULAR_NODE, NodeRole.CONFIRMATION_VALIDATOR, NodeRole.PRIMARY_VALIDATOR} == NODE_ROLES
25+
26+
next_block_schedule = Schedule.objects.get_schedule_for_next_block()
27+
primary_validator_identifier = next_block_schedule.node_identifier if next_block_schedule else None
28+
validator_identifiers = {item.node_identifier for item in Schedule.objects.all().order_by('_id')}
29+
if NodeRole.REGULAR_NODE in roles:
30+
if NodeRole.PRIMARY_VALIDATOR in roles:
31+
if NodeRole.CONFIRMATION_VALIDATOR in roles:
32+
raise AssertionError('Should have exited on previous shortcut guard condition')
33+
else: # regular and primary validator
34+
return self.exclude(_id__in=validator_identifiers - {primary_validator_identifier})
35+
elif NodeRole.CONFIRMATION_VALIDATOR in roles: # regular and confirmation
36+
return self.exclude(_id=primary_validator_identifier)
37+
else: # only regular
38+
return self.exclude(_id__in=validator_identifiers)
39+
40+
if NodeRole.PRIMARY_VALIDATOR in roles:
41+
if NodeRole.CONFIRMATION_VALIDATOR in roles: # only all validators
42+
return self.filter(_id__in=validator_identifiers)
43+
else: # only primary validator
44+
return self.filter(_id=primary_validator_identifier)
45+
elif NodeRole.CONFIRMATION_VALIDATOR in roles: # only confirmation validators
46+
return self.filter(_id__in=validator_identifiers - {primary_validator_identifier})
47+
48+
raise AssertionError('Should have exited on previous shortcut guard condition')
49+
850

9-
class NodeManager(DjongoManager.from_queryset(CustomQuerySet)): # type: ignore
51+
class NodeManager(DjongoManager.from_queryset(NodeQuerySet)): # type: ignore
1052

1153
def get_queryset(self):
1254
return super().get_queryset().filter(node__isnull=False)

node/blockchain/models/schedule.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
from djongo import models
2+
from djongo.models.fields import DjongoManager
23

34
from node.blockchain.validators import HexStringValidator
5+
from node.core.managers import CustomQuerySet
46
from node.core.models import CustomModel
57

68

9+
class ScheduleQuerySet(CustomQuerySet):
10+
11+
def get_schedule_for_next_block(self):
12+
from .block import Block
13+
next_block = Block.objects.get_next_block_number()
14+
return self.filter(_id__lte=next_block).order_by('-_id').first()
15+
16+
17+
class ScheduleManager(DjongoManager.from_queryset(ScheduleQuerySet)): # type: ignore
18+
pass
19+
20+
721
class Schedule(CustomModel):
822
_id = models.PositiveBigIntegerField('Block number', primary_key=True)
923
node_identifier = models.CharField(max_length=64, validators=(HexStringValidator(64),), blank=False)
24+
25+
objects = ScheduleManager()
26+
27+
def __str__(self):
28+
return f'{self._id}: {self.node_identifier}'

node/blockchain/tasks/process_pending_blocks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from celery import shared_task
22

33

4-
@shared_task(bind=True)
5-
def process_pending_blocks_task(self):
4+
@shared_task
5+
def process_pending_blocks_task():
66
# TODO(dmu) CRITICAL: Process pending blocks. To be implemented in
77
# https://thenewboston.atlassian.net/browse/BC-263
88
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from celery import shared_task
2+
3+
4+
@shared_task
5+
def send_new_block_to_node_task():
6+
raise NotImplementedError
7+
8+
9+
@shared_task
10+
def send_new_block_task(block_number):
11+
raise NotImplementedError
12+
13+
14+
def start_send_new_block_task():
15+
send_new_block_task.delay()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from node.blockchain.inner_models import PVScheduleUpdateSignedChangeRequest
2+
from node.blockchain.types import AccountNumber, KeyPair
3+
from node.core.utils.types import non_negative_intstr
4+
5+
from ..signed_change_request_message.pv_schedule_update import make_pv_schedule_update_signed_change_request_message
6+
7+
8+
def make_pv_schedule_update_signed_change_request(
9+
schedule: dict[non_negative_intstr, AccountNumber], primary_validator_key_pair: KeyPair
10+
) -> PVScheduleUpdateSignedChangeRequest:
11+
signed_change_request = PVScheduleUpdateSignedChangeRequest.create_from_signed_change_request_message(
12+
message=make_pv_schedule_update_signed_change_request_message(schedule, primary_validator_key_pair.public),
13+
signing_key=primary_validator_key_pair.private, # only PV can sign such requests
14+
)
15+
assert signed_change_request.message
16+
assert signed_change_request.signer
17+
assert signed_change_request.signature
18+
19+
return signed_change_request
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from node.blockchain.facade import BlockchainFacade
2-
from node.blockchain.inner_models import Node
32
from node.blockchain.inner_models.signed_change_request_message import PVScheduleUpdateSignedChangeRequestMessage
3+
from node.blockchain.types import AccountNumber
4+
from node.core.utils.types import non_negative_intstr
45

56

6-
def make_pv_schedule_update_signed_change_request_message(node: Node) -> PVScheduleUpdateSignedChangeRequestMessage:
7+
def make_pv_schedule_update_signed_change_request_message(
8+
schedule: dict[non_negative_intstr, AccountNumber], signer
9+
) -> PVScheduleUpdateSignedChangeRequestMessage:
710
return PVScheduleUpdateSignedChangeRequestMessage(
8-
schedule={
9-
'1': node.identifier,
10-
},
11-
account_lock=BlockchainFacade.get_instance().get_account_lock(node.identifier),
11+
schedule=schedule, account_lock=BlockchainFacade.get_instance().get_account_lock(signer)
1212
)

node/blockchain/tests/fixtures/account.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ def primary_validator_key_pair() -> KeyPair:
2020
)
2121

2222

23+
@pytest.fixture
24+
def confirmation_validator_key_pair() -> KeyPair:
25+
return KeyPair(
26+
public=AccountNumber('d171de280d593efc740e4854ee2d2bd658cd1deb967eb51a02b89c6e636f46e1'),
27+
private=SigningKey('cd4c6388fcf3fe01ca5f2fcd902a6a5ed98a312674b3a330057742dcd95afd80'),
28+
)
29+
30+
2331
@pytest.fixture
2432
def regular_node_key_pair() -> KeyPair:
2533
return KeyPair(

node/blockchain/tests/fixtures/blockchain.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from node.blockchain.tests.factories.signed_change_request.node_declaration import (
66
make_node_declaration_signed_change_request
77
)
8+
from node.blockchain.tests.factories.signed_change_request.pv_schedule_update import (
9+
make_pv_schedule_update_signed_change_request
10+
)
811
from node.core.utils.cryptography import generate_key_pair
912

1013

@@ -21,8 +24,10 @@ def base_blockchain(genesis_block_message, primary_validator_key_pair, db):
2124
def rich_blockchain(
2225
base_blockchain,
2326
primary_validator_key_pair,
27+
confirmation_validator_key_pair,
2428
regular_node_declaration_signed_change_request,
2529
self_node_declaration_signed_change_request,
30+
confirmation_validator_declaration_signed_change_request,
2631
):
2732
blockchain_facade = BlockchainFacade.get_instance()
2833

@@ -37,6 +42,22 @@ def rich_blockchain(
3742
signing_key=primary_validator_key_pair.private,
3843
validate=False,
3944
)
45+
46+
blockchain_facade.add_block_from_signed_change_request(
47+
signed_change_request=confirmation_validator_declaration_signed_change_request,
48+
signing_key=primary_validator_key_pair.private,
49+
validate=False,
50+
)
51+
52+
blockchain_facade.add_block_from_signed_change_request(
53+
signed_change_request=make_pv_schedule_update_signed_change_request({
54+
'0': primary_validator_key_pair.public,
55+
'10000': confirmation_validator_key_pair.public,
56+
}, primary_validator_key_pair),
57+
signing_key=primary_validator_key_pair.private,
58+
validate=False,
59+
)
60+
4061
# TODO(dmu) MEDIUM: Add more blocks as new block types are developed
4162

4263

0 commit comments

Comments
 (0)