diff --git a/bigchaindb/pipelines/block.py b/bigchaindb/pipelines/block.py index 5f372384..1f2e9017 100644 --- a/bigchaindb/pipelines/block.py +++ b/bigchaindb/pipelines/block.py @@ -67,28 +67,19 @@ class BlockPipeline: AmountError): return None - if self.bigchain.transaction_exists(tx.id): - # if the transaction already exists, we must check whether - # it's in a valid or undecided block - tx, status = self.bigchain.get_transaction(tx.id, - include_status=True) - if status == self.bigchain.TX_VALID \ - or status == self.bigchain.TX_UNDECIDED: - # if the tx is already in a valid or undecided block, - # then it no longer should be in the backlog, or added - # to a new block. We can delete and drop it. - self.bigchain.delete_transaction(tx.id) - return None - - tx_validated = self.bigchain.is_valid_transaction(tx) - if tx_validated: - return tx - else: - # if the transaction is not valid, remove it from the - # backlog + # If transaction is in any VALID or UNDECIDED block we + # should not include it again + if not self.bigchain.is_new_transaction(tx.id): self.bigchain.delete_transaction(tx.id) return None + # If transaction is not valid it should not be included + if not self.bigchain.is_valid_transaction(tx): + self.bigchain.delete_transaction(tx.id) + return None + + return tx + def create(self, tx, timeout=False): """Create a block. diff --git a/bigchaindb/pipelines/vote.py b/bigchaindb/pipelines/vote.py index 5f385f53..958e5b9c 100644 --- a/bigchaindb/pipelines/vote.py +++ b/bigchaindb/pipelines/vote.py @@ -90,7 +90,8 @@ class Vote: yield tx, block_id, num_tx def validate_tx(self, tx, block_id, num_tx): - """Validate a transaction. + """Validate a transaction. Transaction must also not be in any VALID + block. Args: tx (dict): the transaction to validate @@ -101,7 +102,12 @@ class Vote: Three values are returned, the validity of the transaction, ``block_id``, ``num_tx``. """ - return bool(self.bigchain.is_valid_transaction(tx)), block_id, num_tx + new = self.bigchain.is_new_transaction(tx.id, exclude_block_id=block_id) + if not new: + return False, block_id, num_tx + + valid = bool(self.bigchain.is_valid_transaction(tx)) + return valid, block_id, num_tx def vote(self, tx_validity, block_id, num_tx): """Collect the validity of transactions and cast a vote when ready. diff --git a/tests/pipelines/test_vote.py b/tests/pipelines/test_vote.py index e0b27f50..20beac1e 100644 --- a/tests/pipelines/test_vote.py +++ b/tests/pipelines/test_vote.py @@ -629,3 +629,17 @@ def test_start(mock_start, b): from bigchaindb.pipelines import vote vote.start() mock_start.assert_called_with() + + +@pytest.mark.genesis +def test_vote_no_double_inclusion(b): + from bigchaindb.pipelines import vote + + tx = dummy_tx(b) + block = b.create_block([tx]) + r = vote.Vote().validate_tx(tx, block.id, 1) + assert r == (True, block.id, 1) + + b.write_block(block) + r = vote.Vote().validate_tx(tx, 'other_block_id', 1) + assert r == (False, 'other_block_id', 1)