Skip to content

Add verifier concept for block verification #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions node/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from transaction.transaction_parser import TransactionParser
from verification.in_block_transactions_acceptor import InBlockTransactionsAcceptor
from verification.mempool_transactions_acceptor import MempoolTransactionsAcceptor
from verification.block_acceptor import BlockAcceptor
from verification.block_acceptor import BlockVerifier
from crypto.keys import Keys
from crypto.private import Private
from crypto.secret import split_secret, encode_splits
Expand Down Expand Up @@ -373,8 +373,9 @@ def handle_block_message(self, node_id, raw_signed_block):

if is_block_allowed:
block = signed_block.block
block_verifier = BlockAcceptor(self.epoch, self.logger)
if block_verifier.check_if_valid(block):
block_verifier = BlockVerifier(self.epoch, block, block_number)
verification_result = block_verifier.verify()
if verification_result.is_ok():
current_block_number = self.epoch.get_current_timeframe_block_number()

for prev_hash in block.prev_hashes: # check received block ancestor
Expand All @@ -389,7 +390,7 @@ def handle_block_message(self, node_id, raw_signed_block):
self.mempool.remove_transactions(block.system_txs)
self.utxo.apply_payments(block.payment_txs)
else:
self.logger.error("Block was not added. Considered invalid")
self.logger.error("Block was not added: %s", verification_result.value)
else:
self.logger.error("Received block from %d, but it's signature is wrong", node_id)

Expand All @@ -413,8 +414,9 @@ def handle_block_out_of_timeslot(self, node_id, raw_signed_block):

if is_block_allowed:
block = signed_block.block
block_verifier = BlockAcceptor(self.epoch, self.logger)
if block_verifier.check_if_valid(block):
block_verifier = BlockVerifier(self.epoch, block, block_number)
verification_result = block_verifier.verify()
if verification_result.is_ok():

for prev_hash in block.prev_hashes: # check received block ancestor
if prev_hash not in self.dag.blocks_by_hash: # verify received block for local ancestor
Expand All @@ -437,7 +439,7 @@ def handle_block_out_of_timeslot(self, node_id, raw_signed_block):
self.utxo.apply_payments(block.payment_txs)
self.logger.error("Added block out of timeslot")
else:
self.logger.error("Block was not added. Considered invalid")
self.logger.error("Block was not added. %s", verification_result.value)
else:
self.logger.error("Received block from %d, but it's signature is wrong", node_id)

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pycrypto==2.6.1
seccure==0.3.2
result==0.3.0
git+https://github.com/blockstack/secret-sharing.git
67 changes: 46 additions & 21 deletions verification/block_acceptor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from result import Ok, Err
from verification.acceptor import Acceptor, AcceptionException

from chain.params import Round
Expand All @@ -9,36 +10,38 @@

#TODO check if block don't have itself in prev_hashes

class BlockAcceptor(Acceptor):
# interface, probably should go to separate file
class Verifier:
def verify(self):
raise NotImplementedError("verify() method should be implemented in a child class!")

def __init__(self, epoch, logger):
super().__init__(logger)
class TimeslotVerifier(Verifier):
def __init__(self, block, current_block_number, epoch):
self.block = block
self.current_block_number = current_block_number
self.epoch = epoch

def validate(self, block):

current_round = self.epoch.get_current_round()
current_block_number = self.epoch.get_current_timeframe_block_number()

self.validate_timeslot(block, current_block_number)
self.validate_private_transactions_in_block(block, current_round)

def validate_timeslot(self, block, current_block_number):

for prev_hash in block.prev_hashes:

def verify(self):
for prev_hash in self.block.prev_hashes:
prev_hash_number = self.epoch.dag.get_block_number(prev_hash)
if prev_hash_number >= current_block_number:
raise AcceptionException("Block refers to blocks in current or future timeslots!")
if prev_hash_number >= self.current_block_number:
raise AcceptionException("Block refers to blocks in current or future timeslots!")

class PrivateKeyInBlockVerifier(Verifier):
def __init__(self, block, current_round, epoch):
self.block = block
self.current_round = current_round
self.epoch = epoch

def validate_private_transactions_in_block(self, block, current_round):
def verify(self):
private_key_transactions = []
for tx in block.system_txs:
for tx in self.block.system_txs:
if isinstance(tx, PrivateKeyTransaction):
private_key_transactions.append(tx)

private_key_transactions_count_in_block = len(private_key_transactions)

if current_round != Round.PRIVATE:
if self.current_round != Round.PRIVATE:
if private_key_transactions_count_in_block > 0:
raise AcceptionException("PrivateKeyTransaction was found in round " + current_round.name)

Expand All @@ -60,4 +63,26 @@ def validate_private_transactions_in_block(self, block, current_round):
public_keys = self.epoch.get_public_keys_for_epoch(top)
if not Keys.to_bytes(expected_public) in public_keys.values():
raise AcceptionException(
"No correspondig public key was found for private key in PrivateKeyTransaction!")
"No corresponding public key was found for private key in PrivateKeyTransaction!")


class BlockVerifier(Verifier):
def __init__(self, epoch, block, timeslot_number):
self.epoch = epoch
self.block = block
self.timeslot_number = timeslot_number
current_round = self.epoch.get_current_round()
timeslot_verifier = TimeslotVerifier(block, timeslot_number, epoch)
private_tx_in_block_verifier = PrivateKeyInBlockVerifier(block, current_round, epoch)

self.verifiers = [timeslot_verifier, private_tx_in_block_verifier]

def verify(self):
try:
for verifier in self.verifiers:
verifier.verify()
except AcceptionException as e:
return Err(e)

return Ok(True)