Removed duplicated transaction validation in votes pipeline.

Separated block validation from transaction validation.
Refactored block signature validation.
This commit is contained in:
Rodolphe Marques 2017-02-02 13:35:20 +01:00
parent d49b06933a
commit 6b073f0898
3 changed files with 19 additions and 32 deletions

View File

@ -203,6 +203,12 @@ class Block(object):
InvalidSignature: If a Block's signature is invalid.
"""
self._validate_block(bigchain)
self._validate_block_transactions(bigchain)
return self
def _validate_block(self, bigchain):
# First, make sure this node hasn't already voted on this block
if bigchain.has_previous_vote(self.id, self.voters):
return self
@ -212,18 +218,16 @@ class Block(object):
if self.node_pubkey not in possible_voters:
raise OperationError('Only federation nodes can create blocks')
# Check that the signature is valid
if not self.is_signature_valid():
raise InvalidSignature('Block signature invalid')
raise InvalidSignature('Invalid block signature')
# Finally: Tentative assumption that every blockchain will want to
# validate all transactions in each block
def _validate_block_transactions(self, bigchain):
for tx in self.transactions:
# NOTE: If a transaction is not valid, `is_valid` will throw an
# an exception and block validation will be canceled.
# If a transaction is not valid, `validate_transactions` will
# throw an an exception and block validation will be canceled.
bigchain.validate_transaction(tx)
return self
def sign(self, private_key):
"""Create a signature for the Block and overwrite `self.signature`.
@ -273,34 +277,19 @@ class Block(object):
InvalidSignature: If the block's signature is not corresponding
to it's data or `node_pubkey`.
"""
# TODO: Reuse `is_signature_valid` method here.
# Validate block id
block = block_body['block']
block_serialized = serialize(block)
block_id = hash_data(block_serialized)
public_key = PublicKey(block['node_pubkey'])
try:
signature = block_body['signature']
except KeyError:
signature = None
if block_id != block_body['id']:
raise InvalidHash()
if signature is not None:
# NOTE: CC throws a `ValueError` on some wrong signatures
# https://github.com/bigchaindb/cryptoconditions/issues/27
try:
signature_valid = public_key\
.verify(block_serialized.encode(), signature)
except ValueError:
signature_valid = False
if signature_valid is False:
raise InvalidSignature('Invalid block signature')
transactions = [Transaction.from_dict(tx) for tx
in block['transactions']]
signature = block_body.get('signature')
return cls(transactions, block['node_pubkey'],
block['timestamp'], block['voters'], signature)

View File

@ -53,7 +53,7 @@ class Vote:
block['block']['voters']):
try:
block = Block.from_dict(block)
except (exceptions.InvalidHash, exceptions.InvalidSignature):
except (exceptions.InvalidHash):
# XXX: if a block is invalid we should skip the `validate_tx`
# step, but since we are in a pipeline we cannot just jump to
# another function. Hackish solution: generate an invalid
@ -61,10 +61,8 @@ class Vote:
# pipeline.
return block['id'], [self.invalid_dummy_tx]
try:
self.consensus.validate_block(self.bigchain, block)
except (exceptions.InvalidHash,
exceptions.OperationError,
exceptions.InvalidSignature):
block._validate_block(self.bigchain)
except (exceptions.OperationError, exceptions.InvalidSignature):
# XXX: if a block is invalid we should skip the `validate_tx`
# step, but since we are in a pipeline we cannot just jump to
# another function. Hackish solution: generate an invalid

View File

@ -107,7 +107,7 @@ class TestBlockModel(object):
with raises(InvalidHash):
Block.from_dict(block)
def test_block_invalid_signature_deserialization(self, b):
def test_block_invalid_signature(self, b):
from bigchaindb.common.crypto import hash_data
from bigchaindb.common.exceptions import InvalidSignature
from bigchaindb.common.utils import gen_timestamp, serialize
@ -131,7 +131,7 @@ class TestBlockModel(object):
}
with raises(InvalidSignature):
Block.from_dict(block_body)
Block.from_dict(block_body).validate(b)
def test_compare_blocks(self, b):
from bigchaindb.models import Block, Transaction