From 553148c5e49411254ec0ba34c1689a94e7f3f2b7 Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 18 Jul 2016 13:49:42 +0200 Subject: [PATCH] Add CyclicBlockchainError exception, fix tests --- bigchaindb/core.py | 24 +++++++++++++----------- bigchaindb/exceptions.py | 4 ++++ tests/db/test_bigchain_api.py | 17 ++++++++++------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/bigchaindb/core.py b/bigchaindb/core.py index bc4d4c2b..a4afa583 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -537,6 +537,9 @@ class Bigchain(object): invalid_reason (Optional[str]): Reason the block is invalid """ + if block['id'] == previous_block_id: + raise exceptions.CyclicBlockchainError() + vote = { 'voting_for_block': block['id'], 'previous_block': previous_block_id, @@ -591,17 +594,16 @@ class Bigchain(object): # since the resolution of timestamp is a second, # we might have more than one vote per timestamp - if len(last_voted) > 1: - mapping = {v['vote']['previous_block']: v['vote']['voting_for_block'] - for v in last_voted} - last_block_id = list(mapping.values())[0] - while True: - try: - last_block_id = mapping[last_block_id] - except KeyError: - break - else: - last_block_id = last_voted[0]['vote']['voting_for_block'] + mapping = {v['vote']['previous_block']: v['vote']['voting_for_block'] + for v in last_voted} + last_block_id = list(mapping.values())[0] + while True: + try: + if last_block_id == mapping[last_block_id]: + raise exceptions.CyclicBlockchainError() + last_block_id = mapping[last_block_id] + except KeyError: + break res = r.table('bigchain').get(last_block_id).run(self.conn) diff --git a/bigchaindb/exceptions.py b/bigchaindb/exceptions.py index 9985d722..480a0bd8 100644 --- a/bigchaindb/exceptions.py +++ b/bigchaindb/exceptions.py @@ -56,3 +56,7 @@ class MultipleVotesError(Exception): class GenesisBlockAlreadyExistsError(Exception): """Raised when trying to create the already existing genesis block""" + + +class CyclicBlockchainError(Exception): + """Raised when there is a cycle in the blockchain""" diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 9c5bcebd..d36902c3 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -315,17 +315,17 @@ class TestBigchainApi(object): assert b.get_last_voted_block()['id'] == block_3['id'] def test_no_vote_written_if_block_already_has_vote(self, b): - b.create_genesis_block() + genesis = b.create_genesis_block() block_1 = dummy_block() b.write_block(block_1, durability='hard') - b.write_vote(block_1, b.vote(block_1, b.get_last_voted_block()['id'], True)) + b.write_vote(block_1, b.vote(block_1, genesis['id'], True)) retrieved_block_1 = r.table('bigchain').get(block_1['id']).run(b.conn) # try to vote again on the retrieved block, should do nothing - b.write_vote(retrieved_block_1, b.vote(retrieved_block_1, b.get_last_voted_block()['id'], True)) + b.write_vote(retrieved_block_1, b.vote(retrieved_block_1, genesis['id'], True)) retrieved_block_2 = r.table('bigchain').get(block_1['id']).run(b.conn) assert retrieved_block_1 == retrieved_block_2 @@ -348,12 +348,12 @@ class TestBigchainApi(object): .format(block_id=block_1['id'], n_votes=str(2), n_voters=str(1)) def test_multiple_votes_single_node(self, b): - b.create_genesis_block() + genesis = b.create_genesis_block() block_1 = dummy_block() b.write_block(block_1, durability='hard') # insert duplicate votes for i in range(2): - r.table('votes').insert(b.vote(block_1, b.get_last_voted_block()['id'], True)).run(b.conn) + r.table('votes').insert(b.vote(block_1, genesis['id'], True)).run(b.conn) from bigchaindb.exceptions import MultipleVotesError with pytest.raises(MultipleVotesError) as excinfo: @@ -1215,6 +1215,7 @@ class TestMultipleInputs(object): assert owned_inputs_user2 == [{'cid': 0, 'txid': tx['id']}] def test_get_owned_ids_single_tx_single_output_invalid_block(self, b, user_sk, user_vk): + genesis = b.create_genesis_block() # create a new users user2_sk, user2_vk = crypto.generate_key_pair() @@ -1225,7 +1226,7 @@ class TestMultipleInputs(object): b.write_block(block, durability='hard') # vote the block VALID - vote = b.vote(block, b.get_unvoted_blocks()[0]['id'], True) + vote = b.vote(block, genesis['id'], True) b.write_vote(block, vote) # get input @@ -1343,6 +1344,8 @@ class TestMultipleInputs(object): assert spent_inputs_user1 == tx_signed def test_get_spent_single_tx_single_output_invalid_block(self, b, user_sk, user_vk): + genesis = b.create_genesis_block() + # create a new users user2_sk, user2_vk = crypto.generate_key_pair() @@ -1353,7 +1356,7 @@ class TestMultipleInputs(object): b.write_block(block, durability='hard') # vote the block VALID - vote = b.vote(block, b.get_unvoted_blocks()[0]['id'], True) + vote = b.vote(block, genesis['id'], True) b.write_vote(block, vote) # get input