Skip to content

Commit 8194295

Browse files
committed
Process pending blocks
1 parent 0b79abc commit 8194295

File tree

14 files changed

+128
-50
lines changed

14 files changed

+128
-50
lines changed

node/blockchain/facade.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def add_block(self, block: Block, *, validate=True) -> 'ORMBlock':
6868
block.validate_business_logic()
6969

7070
# Make blockchain state specific validations
71+
# We need `bypass_lock_validation=True` because we have already validated it
7172
block.validate_blockchain_state_dependent(self, bypass_lock_validation=True)
7273

7374
from node.blockchain.models import Block as ORMBlock

node/blockchain/inner_models/block.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def validate_signer(self, blockchain_facade):
6060

6161
@lock(BLOCK_LOCK, expect_locked=True)
6262
def validate_blockchain_state_dependent(self, blockchain_facade):
63-
self.message.validate_blockchain_state_dependent(blockchain_facade)
63+
self.message.validate_blockchain_state_dependent(blockchain_facade, bypass_lock_validation=True)
6464
self.validate_signer(blockchain_facade)
6565

6666

node/blockchain/inner_models/block_message/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def validate_update(self, blockchain_facade):
109109

110110
@lock(BLOCK_LOCK, expect_locked=True)
111111
def validate_blockchain_state_dependent(self, blockchain_facade):
112-
self.request.validate_blockchain_state_dependent(blockchain_facade)
112+
self.request.validate_blockchain_state_dependent(blockchain_facade, bypass_lock_validation=True)
113113
self.validate_number(blockchain_facade)
114114
self.validate_identifier(blockchain_facade)
115115
self.validate_update(blockchain_facade)

node/blockchain/inner_models/block_message/genesis.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
from pydantic import Field
77

8+
from node.blockchain.constants import BLOCK_LOCK
89
from node.blockchain.inner_models.account_state import AccountState
910
from node.blockchain.inner_models.node import Node
1011
from node.blockchain.inner_models.signed_change_request import GenesisSignedChangeRequest
12+
from node.blockchain.utils.lock import lock
1113
from node.core.exceptions import ValidationError
1214

1315
from ...types import BlockIdentifier, Type
@@ -76,7 +78,8 @@ def validate_update(self, blockchain_facade):
7678
# TODO(dmu) MEDIUM: Is it critical not to be able to validate genesis block?
7779
pass
7880

81+
@lock(BLOCK_LOCK, expect_locked=True)
7982
def validate_blockchain_state_dependent(self, blockchain_facade):
80-
super().validate_blockchain_state_dependent(blockchain_facade)
83+
super().validate_blockchain_state_dependent(blockchain_facade, bypass_lock_validation=True)
8184
if blockchain_facade.has_blocks():
8285
raise ValidationError('Blockchain must not have blocks')

node/blockchain/inner_models/signed_change_request/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def validate_account_lock(self, blockchain_facade):
6666

6767
@lock(BLOCK_LOCK, expect_locked=True)
6868
def validate_blockchain_state_dependent(self, blockchain_facade):
69-
self.message.validate_blockchain_state_dependent(blockchain_facade)
69+
self.message.validate_blockchain_state_dependent(blockchain_facade, bypass_lock_validation=True)
7070
self.validate_account_lock(blockchain_facade)
7171

7272
def get_type(self):

node/blockchain/inner_models/signed_change_request/coin_transfer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from node.blockchain.constants import BLOCK_LOCK
2+
from node.blockchain.utils.lock import lock
13
from node.core.exceptions import ValidationError
24

35
from ..signed_change_request_message import CoinTransferSignedChangeRequestMessage
@@ -11,8 +13,9 @@ def validate_business_logic(self):
1113
super().validate_business_logic()
1214
self.validate_circular_transactions()
1315

16+
@lock(BLOCK_LOCK, expect_locked=True)
1417
def validate_blockchain_state_dependent(self, blockchain_facade):
15-
super().validate_blockchain_state_dependent(blockchain_facade)
18+
super().validate_blockchain_state_dependent(blockchain_facade, bypass_lock_validation=True)
1619
self.validate_amount(blockchain_facade)
1720

1821
def validate_circular_transactions(self):

node/blockchain/inner_models/signed_change_request_message/pv_schedule_update.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from django.conf import settings
44
from pydantic import Field, validator
55

6+
from node.blockchain.constants import BLOCK_LOCK
7+
from node.blockchain.utils.lock import lock
68
from node.core.exceptions import ValidationError
79
from node.core.utils.types import non_negative_intstr
810

@@ -40,6 +42,7 @@ def validate_block_numbers(self, blockchain_facade):
4042
if insertion_point > 1:
4143
raise ValidationError('Outdated block numbers detected in schedule')
4244

45+
@lock(BLOCK_LOCK, expect_locked=True)
4346
def validate_blockchain_state_dependent(self, blockchain_facade):
4447
super().validate_blockchain_state_dependent(blockchain_facade)
4548
self.validate_nodes_are_declared(blockchain_facade)

node/blockchain/mixins/validatable.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ class ValidatableMixin:
33
def validate_business_logic(self): # validate() is used by pydantic there we use a longer name
44
raise NotImplementedError('Must be implemented in child class')
55

6-
def validate_blockchain_state_dependent(self, blockchain_facade):
6+
def validate_blockchain_state_dependent(self, blockchain_facade, **kwargs):
77
raise NotImplementedError('Must be implemented in child class')
88

9-
def validate_all(self, blockchain_facade):
9+
def validate_all(self, blockchain_facade, **kwargs):
1010
self.validate_business_logic()
11-
self.validate_blockchain_state_dependent(blockchain_facade)
11+
self.validate_blockchain_state_dependent(blockchain_facade, **kwargs)

node/blockchain/serializers/block.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from node.blockchain.inner_models import Block as PydanticBlock
99
from node.blockchain.models import Block as ORMBlock
1010
from node.blockchain.models import PendingBlock
11+
from node.blockchain.tasks.process_pending_blocks import start_process_pending_blocks_task
12+
from node.core.utils.misc import apply_on_commit
1113

1214
logger = logging.getLogger(__name__)
1315

@@ -22,16 +24,21 @@ def to_representation(self, instance):
2224
# This "hack" is needed to reduce deserialization / serialization overhead when reading blocks
2325
return OrderedDict(body=instance.body)
2426

25-
def validate_message(self, message):
26-
is_invalid_number = ((block_number := message.get('number')) is None or
27-
block_number < BlockchainFacade.get_instance().get_next_block_number())
28-
if is_invalid_number:
29-
raise ValidationError('Invalid number')
30-
31-
return message
32-
3327
def create(self, validated_data):
3428
block = PydanticBlock.parse_obj(validated_data)
29+
30+
facade = BlockchainFacade.get_instance()
31+
block_number = block.get_block_number()
32+
next_block_number = facade.get_next_block_number()
33+
if block_number < next_block_number:
34+
raise ValidationError('Invalid block number')
35+
36+
if block_number == next_block_number:
37+
# Preliminary validation (we will revalidate it later) therefore providing `bypass_lock_validation=True`
38+
block.validate_all(facade, bypass_lock_validation=True)
39+
else:
40+
block.validate_business_logic()
41+
3542
instance, _ = PendingBlock.objects.update_or_create(
3643
number=block.get_block_number(),
3744
signer=block.signer,
@@ -42,6 +49,9 @@ def create(self, validated_data):
4249
},
4350
)
4451

52+
if block_number == next_block_number:
53+
apply_on_commit(start_process_pending_blocks_task)
54+
4555
return instance
4656

4757
class Meta:

node/blockchain/tasks/process_block_confirmations.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@ def process_next_block() -> bool:
9797
raise ValidationError('Pending block body hash is not valid') # we should never get here
9898

9999
with transaction.atomic():
100-
facade.add_block_from_json(block_body, expect_locked=True)
100+
orm_block = facade.add_block_from_json(block_body, expect_locked=True)
101101
# There may be blocks with other hashes therefore we delete all of them
102-
PendingBlock.objects.filter(number__lte=next_block_number).delete()
103-
BlockConfirmation.objects.filter(number__lte=next_block_number).delete()
102+
block_number = orm_block._id
103+
PendingBlock.objects.filter(number__lte=block_number).delete()
104+
BlockConfirmation.objects.filter(number__lte=block_number).delete()
104105

105106
return True
106107

0 commit comments

Comments
 (0)