UUID is added even if payload is None

Prevent the creation of empty blocks
Created and updated tests
This commit is contained in:
Rodolphe Marques 2016-06-15 12:07:53 +02:00
parent a694efd9dc
commit 6d41f6971d
4 changed files with 101 additions and 43 deletions

View File

@ -386,6 +386,10 @@ class Bigchain(object):
dict: created block.
"""
# Prevent the creation of empty blocks
if len(validated_transactions) == 0:
raise exceptions.OperationError('Empty block creation is not allowed')
# Create the new block
block = {
'timestamp': util.timestamp(),

View File

@ -221,14 +221,13 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
# handle payload
data = None
if payload is not None:
if isinstance(payload, dict):
data = {
'uuid': str(uuid.uuid4()),
'payload': payload
}
else:
raise TypeError('`payload` must be an dict instance')
if isinstance(payload, (dict, type(None))):
data = {
'uuid': str(uuid.uuid4()),
'payload': payload
}
else:
raise TypeError('`payload` must be an dict instance or None')
# handle inputs
fulfillments = []

View File

@ -22,6 +22,20 @@ def test_remove_unclosed_sockets():
pass
# Some util functions
def dummy_tx():
b = bigchaindb.Bigchain()
tx = b.create_transaction(b.me, b.me, None, 'CREATE')
tx_signed = b.sign_transaction(tx, b.me_private)
return tx_signed
def dummy_block():
b = bigchaindb.Bigchain()
block = b.create_block([dummy_tx()])
return block
class TestBigchainApi(object):
def test_create_transaction_create(self, b, user_sk):
tx = b.create_transaction(b.me, user_sk, None, 'CREATE')
@ -33,6 +47,17 @@ class TestBigchainApi(object):
with pytest.raises(TypeError):
b.create_transaction('a', 'b', 'c', 'd', payload=[])
def test_create_transaction_payload_none(self, b, user_vk):
tx = b.create_transaction(b.me, user_vk, None, 'CREATE')
assert len(tx['transaction']['data']['uuid']) == 36
assert tx['transaction']['data']['payload'] is None
def test_create_transaction_payload(self, b, user_vk):
payload = {'msg': 'Hello BigchainDB!'}
tx = b.create_transaction(b.me, user_vk, None, 'CREATE', payload=payload)
assert len(tx['transaction']['data']['uuid']) == 36
assert tx['transaction']['data']['payload'] == payload
@pytest.mark.usefixtures('inputs')
def test_create_transaction_transfer(self, b, user_vk, user_sk):
input_tx = b.get_owned_ids(user_vk).pop()
@ -200,7 +225,8 @@ class TestBigchainApi(object):
assert prev_block_id == last_block['id']
def test_create_new_block(self, b):
new_block = b.create_block([])
tx = dummy_tx()
new_block = b.create_block([tx])
block_hash = crypto.hash_data(util.serialize(new_block['block']))
assert new_block['block']['voters'] == [b.me]
@ -209,6 +235,12 @@ class TestBigchainApi(object):
assert new_block['id'] == block_hash
assert new_block['votes'] == []
def test_create_empty_block(self, b):
with pytest.raises(exceptions.OperationError) as excinfo:
b.create_block([])
assert excinfo.value.args[0] == 'Empty block creation is not allowed'
def test_get_last_voted_block_returns_genesis_if_no_votes_has_been_casted(self, b):
b.create_genesis_block()
genesis = list(r.table('bigchain')
@ -221,9 +253,9 @@ class TestBigchainApi(object):
assert b.get_last_voted_block() == genesis
block_1 = b.create_block([])
block_2 = b.create_block([])
block_3 = b.create_block([])
block_1 = dummy_block()
block_2 = dummy_block()
block_3 = dummy_block()
b.write_block(block_1, durability='hard')
b.write_block(block_2, durability='hard')
@ -241,7 +273,7 @@ class TestBigchainApi(object):
def test_no_vote_written_if_block_already_has_vote(self, b):
b.create_genesis_block()
block_1 = b.create_block([])
block_1 = dummy_block()
b.write_block(block_1, durability='hard')
@ -387,7 +419,7 @@ class TestTransactionValidation(object):
class TestBlockValidation(object):
def test_wrong_block_hash(self, b):
block = b.create_block([])
block = dummy_block()
# change block hash
block.update({'id': 'abc'})
@ -428,7 +460,7 @@ class TestBlockValidation(object):
assert excinfo.value.args[0] == 'current_owner `a` does not own the input `{}`'.format(valid_input)
def test_invalid_block_id(self, b):
block = b.create_block([])
block = dummy_block()
# change block hash
block.update({'id': 'abc'})
@ -450,7 +482,7 @@ class TestBlockValidation(object):
def test_invalid_signature(self, b):
# create a valid block
block = b.create_block([])
block = dummy_block()
# replace the block signature with an invalid one
block['signature'] = crypto.SigningKey(b.me_private).sign(b'wrongdata')
@ -462,7 +494,7 @@ class TestBlockValidation(object):
def test_invalid_node_pubkey(self, b):
# blocks can only be created by a federation node
# create a valid block
block = b.create_block([])
block = dummy_block()
# create some temp keys
tmp_sk, tmp_vk = crypto.generate_key_pair()
@ -488,7 +520,7 @@ class TestBigchainVoter(object):
genesis = b.create_genesis_block()
# create valid block
block = b.create_block([])
block = dummy_block()
# assert block is valid
assert b.is_valid_block(block)
b.write_block(block, durability='hard')
@ -560,7 +592,7 @@ class TestBigchainVoter(object):
def test_vote_creation_valid(self, b):
# create valid block
block = b.create_block([])
block = dummy_block()
# retrieve vote
vote = b.vote(block, 'abc', True)
@ -574,7 +606,7 @@ class TestBigchainVoter(object):
def test_vote_creation_invalid(self, b):
# create valid block
block = b.create_block([])
block = dummy_block()
# retrieve vote
vote = b.vote(block, 'abc', False)
@ -786,9 +818,9 @@ class TestBigchainBlock(object):
def test_revert_delete_block(self, b):
b.create_genesis_block()
block_1 = b.create_block([])
block_2 = b.create_block([])
block_3 = b.create_block([])
block_1 = dummy_block()
block_2 = dummy_block()
block_3 = dummy_block()
b.write_block(block_1, durability='hard')
b.write_block(block_2, durability='hard')
@ -2088,7 +2120,7 @@ class TestCryptoconditions(object):
assert b.is_valid_transaction(escrow_tx_transfer) == escrow_tx_transfer
assert b.validate_transaction(escrow_tx_transfer) == escrow_tx_transfer
time.sleep(time_sleep)
time.sleep(time_sleep + 1)
assert b.is_valid_transaction(escrow_tx_transfer) is False
with pytest.raises(exceptions.InvalidSignature):
@ -2223,7 +2255,7 @@ class TestCryptoconditions(object):
block = b.create_block([escrow_tx_transfer])
b.write_block(block, durability='hard')
time.sleep(time_sleep)
time.sleep(time_sleep + 1)
assert b.is_valid_transaction(escrow_tx_transfer) is False
with pytest.raises(exceptions.InvalidSignature):

View File

@ -9,6 +9,20 @@ from bigchaindb.voter import Voter, Election, BlockStream
from bigchaindb import crypto, Bigchain
# Some util functions
def dummy_tx():
b = Bigchain()
tx = b.create_transaction(b.me, b.me, None, 'CREATE')
tx_signed = b.sign_transaction(tx, b.me_private)
return tx_signed
def dummy_block():
b = Bigchain()
block = b.create_block([dummy_tx()])
return block
class TestBigchainVoter(object):
def test_valid_block_voting(self, b):
@ -17,7 +31,9 @@ class TestBigchainVoter(object):
genesis = b.create_genesis_block()
# create valid block
block = b.create_block([])
# sleep so that `block` as a higher timestamp then genesis
time.sleep(1)
block = dummy_block()
# assert block is valid
assert b.is_valid_block(block)
b.write_block(block, durability='hard')
@ -59,6 +75,8 @@ class TestBigchainVoter(object):
assert b.is_valid_transaction(tx_signed)
# create valid block
# sleep so that block as a higher timestamp then genesis
time.sleep(1)
block = b.create_block([tx_signed])
# assert block is valid
assert b.is_valid_block(block)
@ -172,6 +190,8 @@ class TestBigchainVoter(object):
genesis = b.create_genesis_block()
# create invalid block
# sleep so that `block` as a higher timestamp then `genesis`
time.sleep(1)
block = b.create_block([transaction_signed])
# change transaction id to make it invalid
block['block']['transactions'][0]['id'] = 'abc'
@ -201,7 +221,7 @@ class TestBigchainVoter(object):
def test_vote_creation_valid(self, b):
# create valid block
block = b.create_block([])
block = dummy_block()
# retrieve vote
vote = b.vote(block, 'abc', True)
@ -215,7 +235,7 @@ class TestBigchainVoter(object):
def test_vote_creation_invalid(self, b):
# create valid block
block = b.create_block([])
block = dummy_block()
# retrieve vote
vote = b.vote(block, 'abc', False)
@ -233,9 +253,9 @@ class TestBigchainVoter(object):
# insert blocks in the database while the voter process is not listening
# (these blocks won't appear in the changefeed)
block_1 = b.create_block([])
block_1 = dummy_block()
b.write_block(block_1, durability='hard')
block_2 = b.create_block([])
block_2 = dummy_block()
b.write_block(block_2, durability='hard')
# voter is back online, we simulate that by creating a queue and a Voter instance
@ -243,7 +263,7 @@ class TestBigchainVoter(object):
voter = Voter(q_new_block)
# create a new block that will appear in the changefeed
block_3 = b.create_block([])
block_3 = dummy_block()
b.write_block(block_3, durability='hard')
# put the last block in the queue
@ -266,9 +286,12 @@ class TestBigchainVoter(object):
def test_voter_chains_blocks_with_the_previous_ones(self, b):
b.create_genesis_block()
block_1 = b.create_block([])
# sleep so that `block_*` as a higher timestamp then `genesis`
time.sleep(1)
block_1 = dummy_block()
b.write_block(block_1, durability='hard')
block_2 = b.create_block([])
time.sleep(1)
block_2 = dummy_block()
b.write_block(block_2, durability='hard')
q_new_block = mp.Queue()
@ -294,7 +317,7 @@ class TestBigchainVoter(object):
def test_voter_checks_for_previous_vote(self, b):
b.create_genesis_block()
block_1 = b.create_block([])
block_1 = dummy_block()
b.write_block(block_1, durability='hard')
q_new_block = mp.Queue()
@ -326,7 +349,7 @@ class TestBlockElection(object):
def test_quorum(self, b):
# create a new block
test_block = b.create_block([])
test_block = dummy_block()
# simulate a federation with four voters
key_pairs = [crypto.generate_key_pair() for _ in range(4)]
@ -393,7 +416,7 @@ class TestBlockElection(object):
def test_quorum_odd(self, b):
# test partial quorum situations for odd numbers of voters
# create a new block
test_block = b.create_block([])
test_block = dummy_block()
# simulate a federation with four voters
key_pairs = [crypto.generate_key_pair() for _ in range(5)]
@ -476,7 +499,7 @@ class TestBlockStream(object):
b.federation_nodes.append(crypto.generate_key_pair()[1])
new_blocks = mp.Queue()
bs = BlockStream(new_blocks)
block_1 = b.create_block([])
block_1 = dummy_block()
new_blocks.put(block_1)
assert block_1 == bs.get()
@ -485,8 +508,8 @@ class TestBlockStream(object):
bs = BlockStream(new_blocks)
# create two blocks
block_1 = b.create_block([])
block_2 = b.create_block([])
block_1 = dummy_block()
block_2 = dummy_block()
# write the blocks
b.write_block(block_1, durability='hard')
@ -502,8 +525,8 @@ class TestBlockStream(object):
def test_if_old_blocks_get_should_return_old_block_first(self, b):
# create two blocks
block_1 = b.create_block([])
block_2 = b.create_block([])
block_1 = dummy_block()
block_2 = dummy_block()
# write the blocks
b.write_block(block_1, durability='hard')
@ -520,8 +543,8 @@ class TestBlockStream(object):
# pp(block_2)
# create two new blocks that will appear in the changefeed
block_3 = b.create_block([])
block_4 = b.create_block([])
block_3 = dummy_block()
block_4 = dummy_block()
# simulate a changefeed
new_blocks.put(block_3)