bigchaindb/tests/pipelines/test_election.py
Sylvain Bellemare 64cafc62ad Merge common lib (#739)
* Planning release

* Clean up after move

* Add exceptions.py

* Add crypto.py

* Adjust setup to package structure

* Fix tests

* Add test coverage

* Comply to flake8

* Add test coverage

* Transfer-tx fulfillments validation

* Remove condition and fulfillment ids

* Fix signing logic

Specifically for transfer-tx with multiple inputs
and outputs.

* Compliance to legacy BDB models

* Adjust fulfillment validation interface

* Add serialization validation for txids

* Use __eq__ to compare objects

* Heavy refactor to comply with current implementation

* Add Transaction.create

* Correct fulfillment validation logic

* Add Transaction.create for hashlock conditions

* Add hashlock condition serialization

* Transaction.transfer add single input and outputs

* Small adjustments to transfer-tx interface

* Create transfer-tx interface

* Increase test coverage

* Adjust fulfillment (de)serialization

* Catch CC Error for Fulfillment

* Allow custom thresholds

* PR feedback

* Fix tests

* Rename Data to Metadata

* Add Asset exceptions

* Add basic Asset model

* More renaming of payload => data

* Add Asset into work-flow-functions

* Add Asset amount to condition

* add fulfillment exception

* initial integration of asset

* Make transaction.py compy to 79 chars

* Make util.py comply to 79 chars

* Make exceptions.py comply to 80 chars

* Renaming inp to input_

* fix pep8 issues

* Correct raised error

* Remove resolved TODOs

* prevent adding None as fulfillment / condition to Transaction

* Small modifications to support new cryptoconditions

* Improve documentation (#42)

* Add doc strings for Fulfillment cls

* Add doc strings for TransactionLink cls

* Add doc strings for Condition cls

* Add doc strings for Data cls

* Add doc strings for Transaction cls

* Add doc strings for Asset cls

* Extract common implementation

* Tx model: Add test for empty inputs

* WIP: Implement sign tx

* Add tests for:
    - Conditions; and
    - Fulfillments

Mostly on the (de)serialization part.

* Finalize serialization logic for tx class

* Add Tests for tx serialization logic

* Add fulfillment validation

* Add ThresholdCondition support

* WIP transfer

* Clean up after move

* Adjust setup to package structure

* Fix tests

* Add test coverage

* Add test coverage

* Transfer-tx fulfillments validation

* Remove condition and fulfillment ids

* Fix signing logic

Specifically for transfer-tx with multiple inputs
and outputs.

* Fix test case

* Compliance to legacy BDB models

* Adjust fulfillment validation interface

* Add serialization validation for txids

* Use __eq__ to compare objects

* Heavy refactor to comply with current implementation

* Add Transaction.create

* Add validation tests

* Add Transaction.create for hashlock conditions

* Add hashlock condition serialization

* Transaction.transfer add single input and outputs

* Small adjustments to transfer-tx interface

* Create transfer-tx interface

* Increase test coverage

* Adjust fulfillment (de)serialization

* Catch CC Error for Fulfillment

* Allow custom thresholds

* Rename Data to Metadata

* Add basic Asset model

* Add Asset into work-flow-functions

* Add Asset amount to condition

* initial integration of asset

* Make tests comply to 79 chars per line

* Fixed tests

* fix pep8 issues

* Correct raised error

* Add test for asset initialization

* Remove resolved TODOs

* prevent adding None as fulfillment / condition to Transaction

* Small modifications to support new cryptoconditions

* Extract common tests

* Copy conftest from bigchaindb-common - by @timdaub

* Replace bigchaindb_common pkg by bigchaindb.common
2016-10-25 10:21:20 +02:00

171 lines
5.6 KiB
Python

import time
from unittest.mock import patch
from bigchaindb.common import crypto
import rethinkdb as r
from multipipes import Pipe, Pipeline
from bigchaindb import Bigchain
from bigchaindb.pipelines import election
def test_check_for_quorum_invalid(b, user_vk):
from bigchaindb.models import Transaction
e = election.Election()
# create blocks with transactions
tx1 = Transaction.create([b.me], [user_vk])
test_block = b.create_block([tx1])
# simulate a federation with four voters
key_pairs = [crypto.generate_key_pair() for _ in range(4)]
test_federation = [Bigchain(public_key=key_pair[1], private_key=key_pair[0])
for key_pair in key_pairs]
# add voters to block and write
test_block.voters = [key_pair[1] for key_pair in key_pairs]
test_block = test_block.sign(b.me_private)
b.write_block(test_block)
# split_vote (invalid)
votes = [member.vote(test_block.id, 'abc', True) for member in test_federation[:2]] + \
[member.vote(test_block.id, 'abc', False) for member in test_federation[2:]]
# cast votes
b.connection.run(r.table('votes').insert(votes, durability='hard'))
# since this block is now invalid, should pass to the next process
assert e.check_for_quorum(votes[-1]) == test_block
def test_check_for_quorum_invalid_prev_node(b, user_vk):
from bigchaindb.models import Transaction
e = election.Election()
# create blocks with transactions
tx1 = Transaction.create([b.me], [user_vk])
test_block = b.create_block([tx1])
# simulate a federation with four voters
key_pairs = [crypto.generate_key_pair() for _ in range(4)]
test_federation = [Bigchain(public_key=key_pair[1], private_key=key_pair[0])
for key_pair in key_pairs]
# add voters to block and write
test_block.voters = [key_pair[1] for key_pair in key_pairs]
test_block = test_block.sign(b.me_private)
b.write_block(test_block)
# split vote over prev node
votes = [member.vote(test_block.id, 'abc', True) for member in test_federation[:2]] + \
[member.vote(test_block.id, 'def', True) for member in test_federation[2:]]
# cast votes
b.connection.run(r.table('votes').insert(votes, durability='hard'))
# since nodes cannot agree on prev block, the block is invalid
assert e.check_for_quorum(votes[-1]) == test_block
def test_check_for_quorum_valid(b, user_vk):
from bigchaindb.models import Transaction
e = election.Election()
# create blocks with transactions
tx1 = Transaction.create([b.me], [user_vk])
test_block = b.create_block([tx1])
# simulate a federation with four voters
key_pairs = [crypto.generate_key_pair() for _ in range(4)]
test_federation = [Bigchain(public_key=key_pair[1], private_key=key_pair[0])
for key_pair in key_pairs]
# add voters to block and write
test_block.voters = [key_pair[1] for key_pair in key_pairs]
test_block = test_block.sign(b.me_private)
b.write_block(test_block)
# votes for block one
votes = [member.vote(test_block.id, 'abc', True)
for member in test_federation]
# cast votes
b.connection.run(r.table('votes').insert(votes, durability='hard'))
# since this block is valid, should go nowhere
assert e.check_for_quorum(votes[-1]) is None
def test_check_requeue_transaction(b, user_vk):
from bigchaindb.models import Transaction
e = election.Election()
# create blocks with transactions
tx1 = Transaction.create([b.me], [user_vk])
test_block = b.create_block([tx1])
e.requeue_transactions(test_block)
backlog_tx = b.connection.run(r.table('backlog').get(tx1.id))
backlog_tx.pop('assignee')
backlog_tx.pop('assignment_timestamp')
assert backlog_tx == tx1.to_dict()
@patch.object(Pipeline, 'start')
def test_start(mock_start):
# TODO: `block.election` is just a wrapper around `block.create_pipeline`,
# that is tested by `test_full_pipeline`.
# If anyone has better ideas on how to test this, please do a PR :)
election.start()
mock_start.assert_called_with()
def test_full_pipeline(b, user_vk):
import random
from bigchaindb.models import Transaction
outpipe = Pipe()
# write two blocks
txs = []
for i in range(100):
tx = Transaction.create([b.me], [user_vk], {'msg': random.random()})
tx = tx.sign([b.me_private])
txs.append(tx)
valid_block = b.create_block(txs)
b.write_block(valid_block)
txs = []
for i in range(100):
tx = Transaction.create([b.me], [user_vk], {'msg': random.random()})
tx = tx.sign([b.me_private])
txs.append(tx)
invalid_block = b.create_block(txs)
b.write_block(invalid_block)
pipeline = election.create_pipeline()
pipeline.setup(indata=election.get_changefeed(), outdata=outpipe)
pipeline.start()
time.sleep(1)
# vote one block valid, one invalid
vote_valid = b.vote(valid_block.id, 'abc', True)
vote_invalid = b.vote(invalid_block.id, 'abc', False)
b.connection.run(r.table('votes').insert(vote_valid, durability='hard'))
b.connection.run(r.table('votes').insert(vote_invalid, durability='hard'))
outpipe.get()
pipeline.terminate()
# only transactions from the invalid block should be returned to
# the backlog
assert b.connection.run(r.table('backlog').count()) == 100
# NOTE: I'm still, I'm still tx from the block.
tx_from_block = set([tx.id for tx in invalid_block.transactions])
tx_from_backlog = set([tx['id'] for tx in list(b.connection.run(r.table('backlog')))])
assert tx_from_block == tx_from_backlog