Skip to content

Commit e8a1b2c

Browse files
committed
Forgotten confirmations validation
1 parent 8960cc8 commit e8a1b2c

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

node/blockchain/tasks/process_block_confirmations.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from itertools import groupby
23
from operator import attrgetter
34

@@ -8,30 +9,52 @@
89
from node.blockchain.facade import BlockchainFacade
910
from node.blockchain.models import BlockConfirmation, PendingBlock
1011
from node.blockchain.utils.lock import lock
12+
from node.core.exceptions import ValidationError
13+
14+
logger = logging.getLogger(__name__)
1115

1216

1317
@lock(BLOCK_LOCK)
1418
def process_next_block():
1519
facade = BlockchainFacade.get_instance()
1620
next_block_number = facade.get_next_block_number()
1721
cv_identifiers = facade.get_confirmation_validator_identifiers()
18-
confirmations = BlockConfirmation.objects.filter(number=next_block_number, signer__in=cv_identifiers)
19-
grouped_confirmations = groupby(confirmations.order_by('hash'), key=attrgetter('hash'))
22+
23+
# Query only confirmations for the next block number and received from confirmation validators
24+
all_confirmations = BlockConfirmation.objects.filter(number=next_block_number, signer__in=cv_identifiers)
25+
26+
# Group confirmations by hash to see which hash wins the consensus
27+
grouped_confirmations = groupby(all_confirmations.order_by('hash'), key=attrgetter('hash'))
2028
minimum_consensus = facade.get_minimum_consensus()
2129

22-
finalizable_hashes = [
23-
hash_ for hash_, _confirmations in grouped_confirmations if len(list(_confirmations)) >= minimum_consensus
24-
]
30+
finalizable_hashes = [(hash_, confirmations)
31+
for hash_, confirmations in grouped_confirmations
32+
if len(list(confirmations)) >= minimum_consensus]
2533

2634
if not finalizable_hashes:
27-
return False
35+
return False # No consensus, yet
2836

2937
if len(finalizable_hashes) >= 2:
3038
# We should never get here
3139
raise ValueError('More than one finalizable hash found')
3240

3341
assert len(finalizable_hashes) == 1
34-
hash_ = finalizable_hashes[0]
42+
hash_, consensus_confirmations = finalizable_hashes[0]
43+
44+
# Validate confirmations, since they may have not been validated on API call because some of them were added
45+
# much earlier then the next block number become equal to confirmation block number
46+
valid_confirmations = []
47+
for confirmation in consensus_confirmations:
48+
try:
49+
confirmation.validate_all()
50+
except ValidationError:
51+
logger.warning('Invalid confirmation detected: %s', confirmation)
52+
continue
53+
54+
valid_confirmations.append(confirmation)
55+
56+
if len(valid_confirmations) < minimum_consensus: # Check that we still have consensus after validation
57+
return False
3558

3659
pending_block = PendingBlock.objects.get_or_none(number=next_block_number, hash=hash_)
3760
if pending_block is None:

0 commit comments

Comments
 (0)