mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: voting code is not used anymore (#2357)
* Problem: voting code is not used anymore Solution: remove all voting related code * Problem: Some voting functionality is still present. Solution: Remove it. Update some of the related tests. * Problem: some skipped tests are now running Solution: remove pytest mark to not run them * Problem: fastquery is not related to votes Solution: remove it in another PR
This commit is contained in:
parent
67c4ce964a
commit
7449b026fa
@ -6,8 +6,6 @@ Attributes:
|
||||
* ``backlog`` for incoming transactions awaiting to be put into
|
||||
a block.
|
||||
* ``bigchain`` for blocks.
|
||||
* ``votes`` to store votes for each block by each federation
|
||||
node.
|
||||
|
||||
"""
|
||||
|
||||
@ -21,7 +19,7 @@ from bigchaindb.common.utils import validate_all_values_for_key
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TABLES = ('bigchain', 'backlog', 'votes', 'assets', 'metadata')
|
||||
TABLES = ('bigchain', 'backlog', 'assets', 'metadata')
|
||||
VALID_LANGUAGES = ('danish', 'dutch', 'english', 'finnish', 'french', 'german',
|
||||
'hungarian', 'italian', 'norwegian', 'portuguese', 'romanian',
|
||||
'russian', 'spanish', 'swedish', 'turkish', 'none',
|
||||
|
@ -66,14 +66,6 @@ class InvalidSignature(ValidationError):
|
||||
"""
|
||||
|
||||
|
||||
class ImproperVoteError(ValidationError):
|
||||
"""Raised if a vote is not constructed correctly, or signed incorrectly"""
|
||||
|
||||
|
||||
class MultipleVotesError(ValidationError):
|
||||
"""Raised if a voter has voted more than once"""
|
||||
|
||||
|
||||
class TransactionNotInValidBlock(ValidationError):
|
||||
"""Raised when a transfer transaction is attempting to fulfill the
|
||||
outputs of a transaction that is in an invalid or undecided block
|
||||
@ -96,10 +88,6 @@ class TransactionOwnerError(ValidationError):
|
||||
"""Raised if a user tries to transfer a transaction they don't own"""
|
||||
|
||||
|
||||
class SybilError(ValidationError):
|
||||
"""If a block or vote comes from an unidentifiable node"""
|
||||
|
||||
|
||||
class DuplicateTransaction(ValidationError):
|
||||
"""Raised if a duplicated transaction is found"""
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
---
|
||||
"$schema": "http://json-schema.org/draft-04/schema#"
|
||||
id: "http://www.bigchaindb.com/schema/vote.json"
|
||||
type: object
|
||||
additionalProperties: false
|
||||
title: Vote Schema
|
||||
required:
|
||||
- node_pubkey
|
||||
- signature
|
||||
- vote
|
||||
properties:
|
||||
node_pubkey:
|
||||
type: "string"
|
||||
pattern: "[1-9a-zA-Z^OIl]{43,44}"
|
||||
signature:
|
||||
type: "string"
|
||||
pattern: "[1-9a-zA-Z^OIl]{86,88}"
|
||||
vote:
|
||||
type: "object"
|
||||
additionalProperties: false
|
||||
required:
|
||||
- invalid_reason
|
||||
- is_block_valid
|
||||
- previous_block
|
||||
- voting_for_block
|
||||
- timestamp
|
||||
properties:
|
||||
previous_block:
|
||||
"$ref": "#/definitions/sha3_hexdigest"
|
||||
voting_for_block:
|
||||
"$ref": "#/definitions/sha3_hexdigest"
|
||||
is_block_valid:
|
||||
type: "boolean"
|
||||
invalid_reason:
|
||||
anyOf:
|
||||
- type: "string"
|
||||
- type: "null"
|
||||
timestamp:
|
||||
type: "string"
|
||||
pattern: "[0-9]{10}"
|
||||
definitions:
|
||||
sha3_hexdigest:
|
||||
pattern: "[0-9a-f]{64}"
|
||||
type: string
|
@ -1,4 +1,3 @@
|
||||
from bigchaindb.voting import Voting
|
||||
|
||||
|
||||
class BaseConsensusRules():
|
||||
@ -10,8 +9,6 @@ class BaseConsensusRules():
|
||||
|
||||
"""
|
||||
|
||||
voting = Voting
|
||||
|
||||
@staticmethod
|
||||
def validate_transaction(bigchain, transaction):
|
||||
"""See :meth:`bigchaindb.models.Transaction.validate`
|
||||
|
@ -14,7 +14,7 @@ class Bigchain(object):
|
||||
"""
|
||||
|
||||
BLOCK_INVALID = 'invalid'
|
||||
"""return if a block has been voted invalid"""
|
||||
"""return if a block is invalid"""
|
||||
|
||||
BLOCK_VALID = TX_VALID = 'valid'
|
||||
"""return if a block is valid, or tx is in valid block"""
|
||||
@ -372,11 +372,7 @@ class Bigchain(object):
|
||||
self.write_metadata(metadatas)
|
||||
|
||||
# write the block
|
||||
return backend.query.write_block(self.connection, block_dict)
|
||||
|
||||
def write_vote(self, vote):
|
||||
"""Write the vote to the database."""
|
||||
return backend.query.write_vote(self.connection, vote)
|
||||
return backend.query.store_block(self.connection, block_dict)
|
||||
|
||||
def get_assets(self, asset_ids):
|
||||
"""Return a list of assets that match the asset_ids
|
||||
@ -409,7 +405,7 @@ class Bigchain(object):
|
||||
assets (:obj:`list` of :obj:`dict`): A list of assets to write to
|
||||
the database.
|
||||
"""
|
||||
return backend.query.write_assets(self.connection, assets)
|
||||
return backend.query.store_assets(self.connection, assets)
|
||||
|
||||
def write_metadata(self, metadata):
|
||||
"""Writes a list of metadata into the database.
|
||||
|
@ -8,7 +8,3 @@ class CriticalDoubleSpend(BigchainDBError):
|
||||
|
||||
class CriticalDoubleInclusion(BigchainDBError):
|
||||
"""Data integrity error that requires attention"""
|
||||
|
||||
|
||||
class CriticalDuplicateVote(BigchainDBError):
|
||||
"""Data integrity error that requires attention"""
|
||||
|
@ -158,7 +158,7 @@ class Transaction(Transaction):
|
||||
|
||||
# TODO: Remove node_pubkey as part of cleanup II
|
||||
class Block(object):
|
||||
"""Bundle a list of Transactions in a Block. Nodes vote on its validity.
|
||||
"""Bundle a list of Transactions in a Block.
|
||||
|
||||
Attributes:
|
||||
transaction (:obj:`list` of :class:`~.Transaction`):
|
||||
@ -326,7 +326,7 @@ class Block(object):
|
||||
signature = block_body.get('signature')
|
||||
|
||||
return cls(transactions, block['node_pubkey'],
|
||||
block['timestamp'], [], signature)
|
||||
block['timestamp'], signature)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
|
@ -1,128 +0,0 @@
|
||||
import collections
|
||||
|
||||
from bigchaindb.exceptions import CriticalDuplicateVote
|
||||
from bigchaindb.common.utils import serialize
|
||||
from bigchaindb.common.crypto import PublicKey
|
||||
|
||||
|
||||
VALID = 'valid'
|
||||
INVALID = 'invalid'
|
||||
UNDECIDED = 'undecided'
|
||||
|
||||
|
||||
class Voting:
|
||||
"""Everything to do with verifying and counting votes for block election.
|
||||
|
||||
All functions in this class should be referentially transparent, that is,
|
||||
they always give the same output for a given input. This makes it easier
|
||||
to test. This also means no logging!
|
||||
|
||||
Assumptions regarding data:
|
||||
* Vote is a dictionary, but no assumptions are made on it's properties.
|
||||
* Everything else is assumed to be structurally correct, otherwise errors
|
||||
may be thrown.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def block_election(cls, block, votes):
|
||||
"""Calculate the election status of a block."""
|
||||
eligible_voters = set(block['block']['voters'])
|
||||
n_voters = len(eligible_voters)
|
||||
eligible_votes, ineligible_votes = \
|
||||
cls.partition_eligible_votes(votes, eligible_voters)
|
||||
by_voter = cls.dedupe_by_voter(eligible_votes)
|
||||
results = cls.count_votes(by_voter)
|
||||
results['block_id'] = block['id']
|
||||
results['status'] = cls.decide_votes(n_voters, **results['counts'])
|
||||
results['ineligible'] = ineligible_votes
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def partition_eligible_votes(cls, votes, eligible_voters):
|
||||
"""Filter votes from unknown nodes or nodes that are not listed on
|
||||
block. This is the primary Sybill protection.
|
||||
"""
|
||||
eligible, ineligible = ([], [])
|
||||
|
||||
for vote in votes:
|
||||
voter_eligible = vote.get('node_pubkey') in eligible_voters
|
||||
if voter_eligible:
|
||||
try:
|
||||
if cls.verify_vote_signature(vote):
|
||||
eligible.append(vote)
|
||||
continue
|
||||
except ValueError:
|
||||
pass
|
||||
ineligible.append(vote)
|
||||
return eligible, ineligible
|
||||
|
||||
@classmethod
|
||||
def dedupe_by_voter(cls, eligible_votes):
|
||||
"""Throw a critical error if there is a duplicate vote
|
||||
"""
|
||||
by_voter = {}
|
||||
for vote in eligible_votes:
|
||||
pubkey = vote['node_pubkey']
|
||||
if pubkey in by_voter:
|
||||
raise CriticalDuplicateVote(pubkey)
|
||||
by_voter[pubkey] = vote
|
||||
return by_voter
|
||||
|
||||
@classmethod
|
||||
def count_votes(cls, by_voter):
|
||||
"""Given a list of eligible votes, (votes from known nodes that are listed
|
||||
as voters), produce the number that say valid and the number that say
|
||||
invalid. Votes must agree on previous block, otherwise they become invalid.
|
||||
"""
|
||||
prev_blocks = collections.Counter()
|
||||
malformed = []
|
||||
|
||||
for vote in by_voter.values():
|
||||
if vote['vote']['is_block_valid'] is True:
|
||||
prev_blocks[vote['vote']['previous_block']] += 1
|
||||
|
||||
n_valid = 0
|
||||
prev_block = None
|
||||
# Valid votes must agree on previous block
|
||||
if prev_blocks:
|
||||
prev_block, n_valid = prev_blocks.most_common()[0]
|
||||
del prev_blocks[prev_block]
|
||||
|
||||
return {
|
||||
'counts': {
|
||||
'n_valid': n_valid,
|
||||
'n_invalid': len(by_voter) - n_valid,
|
||||
},
|
||||
'malformed': malformed,
|
||||
'previous_block': prev_block,
|
||||
'other_previous_block': dict(prev_blocks),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def decide_votes(cls, n_voters, n_valid, n_invalid):
|
||||
"""Decide on votes.
|
||||
|
||||
To return VALID there must be a clear majority that say VALID
|
||||
and also agree on the previous block.
|
||||
|
||||
A tie on an even number of votes counts as INVALID.
|
||||
"""
|
||||
if n_invalid * 2 >= n_voters:
|
||||
return INVALID
|
||||
if n_valid * 2 > n_voters:
|
||||
return VALID
|
||||
return UNDECIDED
|
||||
|
||||
@classmethod
|
||||
def verify_vote_signature(cls, vote):
|
||||
"""Verify the signature of a vote
|
||||
"""
|
||||
signature = vote.get('signature')
|
||||
pk_base58 = vote.get('node_pubkey')
|
||||
|
||||
if not (type(signature) == str and type(pk_base58) == str):
|
||||
raise ValueError('Malformed vote: %s' % vote)
|
||||
|
||||
public_key = PublicKey(pk_base58)
|
||||
body = serialize(vote['vote']).encode()
|
||||
return public_key.verify(body, signature)
|
@ -7,7 +7,6 @@ from bigchaindb.web.views import (
|
||||
info,
|
||||
transactions as tx,
|
||||
outputs,
|
||||
votes,
|
||||
validators,
|
||||
)
|
||||
|
||||
@ -34,7 +33,6 @@ ROUTES_API_V1 = [
|
||||
r('transactions/<string:tx_id>', tx.TransactionApi),
|
||||
r('transactions', tx.TransactionListApi),
|
||||
r('outputs/', outputs.OutputListApi),
|
||||
r('votes/', votes.VotesApi),
|
||||
r('validators/', validators.ValidatorsApi),
|
||||
]
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
"""This module provides the blueprint for the votes API endpoints.
|
||||
|
||||
For more information please refer to the documentation: http://bigchaindb.com/http-api
|
||||
|
||||
We might bring back a votes API endpoint in the future, see:
|
||||
https://github.com/bigchaindb/bigchaindb/issues/2037
|
||||
"""
|
||||
|
||||
from flask import jsonify
|
||||
from flask_restful import Resource
|
||||
# from flask import current_app
|
||||
# from flask_restful import Resource, reqparse
|
||||
|
||||
# from bigchaindb import backend
|
||||
|
||||
|
||||
class VotesApi(Resource):
|
||||
def get(self):
|
||||
"""API endpoint to get details about votes.
|
||||
|
||||
Return:
|
||||
404 Not Found
|
||||
"""
|
||||
# parser = reqparse.RequestParser()
|
||||
# parser.add_argument('block_id', type=str, required=True)
|
||||
|
||||
# args = parser.parse_args(strict=True)
|
||||
|
||||
# pool = current_app.config['bigchain_pool']
|
||||
# with pool() as bigchain:
|
||||
# votes = list(backend.query.get_votes_by_block_id(bigchain.connection, args['block_id']))
|
||||
|
||||
# return votes
|
||||
|
||||
# Return an HTTP status code 404 Not Found, which means:
|
||||
# The requested resource could not be found but may be available in the future.
|
||||
|
||||
gone = 'The votes endpoint is gone now, but it might return in the future.'
|
||||
response = jsonify({'message': gone})
|
||||
response.status_code = 404
|
||||
|
||||
return response
|
@ -312,21 +312,6 @@ def double_spend_tx(signed_create_tx, carol_pubkey, user_sk):
|
||||
return tx.sign([user_sk])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def structurally_valid_vote():
|
||||
return {
|
||||
'node_pubkey': 'c' * 44,
|
||||
'signature': 'd' * 86,
|
||||
'vote': {
|
||||
'voting_for_block': 'a' * 64,
|
||||
'previous_block': 'b' * 64,
|
||||
'is_block_valid': False,
|
||||
'invalid_reason': None,
|
||||
'timestamp': '1111111111'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _get_height(b):
|
||||
maybe_block = b.get_latest_block()
|
||||
return 0 if maybe_block is None else maybe_block['height']
|
||||
|
@ -10,16 +10,12 @@ class TestBlockModel(object):
|
||||
|
||||
block = Block()
|
||||
assert block.transactions == []
|
||||
assert block.voters == []
|
||||
assert block.timestamp == '1'
|
||||
assert block.node_pubkey is None
|
||||
assert block.signature is None
|
||||
|
||||
with raises(TypeError):
|
||||
Block('not a list or None')
|
||||
with raises(TypeError):
|
||||
Block(None, 'valid node_pubkey', 'valid timestamp',
|
||||
'not a list or None')
|
||||
|
||||
def test_block_serialization(self, b, alice):
|
||||
from bigchaindb.common.crypto import hash_data
|
||||
@ -28,12 +24,10 @@ class TestBlockModel(object):
|
||||
|
||||
transactions = [Transaction.create([alice.public_key], [([alice.public_key], 1)])]
|
||||
timestamp = gen_timestamp()
|
||||
voters = ['Qaaa', 'Qbbb']
|
||||
expected_block = {
|
||||
'timestamp': timestamp,
|
||||
'transactions': [tx.to_dict() for tx in transactions],
|
||||
'node_pubkey': alice.public_key,
|
||||
'voters': voters,
|
||||
}
|
||||
expected = {
|
||||
'id': hash_data(serialize(expected_block)),
|
||||
@ -41,7 +35,7 @@ class TestBlockModel(object):
|
||||
'signature': None,
|
||||
}
|
||||
|
||||
block = Block(transactions, alice.public_key, timestamp, voters)
|
||||
block = Block(transactions, alice.public_key, timestamp)
|
||||
|
||||
assert block.to_dict() == expected
|
||||
|
||||
@ -60,14 +54,12 @@ class TestBlockModel(object):
|
||||
transaction = Transaction.create([alice.public_key], [([alice.public_key], 1)])
|
||||
transaction.sign([alice.private_key])
|
||||
timestamp = gen_timestamp()
|
||||
voters = ['Qaaa', 'Qbbb']
|
||||
expected = Block([transaction], alice.public_key, timestamp, voters)
|
||||
expected = Block([transaction], alice.public_key, timestamp)
|
||||
|
||||
block = {
|
||||
'timestamp': timestamp,
|
||||
'transactions': [transaction.to_dict()],
|
||||
'node_pubkey': alice.public_key,
|
||||
'voters': voters,
|
||||
}
|
||||
|
||||
block_body = {
|
||||
@ -106,7 +98,6 @@ class TestBlockModel(object):
|
||||
'timestamp': timestamp,
|
||||
'transactions': [transaction.to_dict()],
|
||||
'node_pubkey': alice.public_key,
|
||||
'voters': list(b.federation),
|
||||
}
|
||||
|
||||
block_body = {
|
||||
@ -133,16 +124,14 @@ class TestBlockModel(object):
|
||||
|
||||
transactions = [Transaction.create([alice.public_key], [([alice.public_key], 1)])]
|
||||
timestamp = gen_timestamp()
|
||||
voters = ['Qaaa', 'Qbbb']
|
||||
expected_block = {
|
||||
'timestamp': timestamp,
|
||||
'transactions': [tx.to_dict() for tx in transactions],
|
||||
'node_pubkey': alice.public_key,
|
||||
'voters': voters,
|
||||
}
|
||||
expected_block_serialized = serialize(expected_block).encode()
|
||||
expected = PrivateKey(alice.private_key).sign(expected_block_serialized)
|
||||
block = Block(transactions, alice.public_key, timestamp, voters)
|
||||
block = Block(transactions, alice.public_key, timestamp)
|
||||
block = block.sign(alice.private_key)
|
||||
assert block.signature == expected.decode()
|
||||
|
||||
@ -150,12 +139,15 @@ class TestBlockModel(object):
|
||||
assert public_key.verify(expected_block_serialized, block.signature)
|
||||
|
||||
def test_block_dupe_tx(self, b, alice):
|
||||
from bigchaindb.models import Transaction
|
||||
from bigchaindb.models import Block, Transaction
|
||||
from bigchaindb.common.exceptions import DuplicateTransaction
|
||||
|
||||
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)])
|
||||
block = b.create_block([tx, tx])
|
||||
block = Block([tx, tx], alice.public_key)
|
||||
block.sign(alice.private_key)
|
||||
b.store_block(block.to_dict())
|
||||
with raises(DuplicateTransaction):
|
||||
block._validate_block(b)
|
||||
block.validate(b)
|
||||
|
||||
def test_decouple_assets(self, b, alice):
|
||||
from bigchaindb.models import Block, Transaction
|
||||
|
@ -1,137 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from bigchaindb.core import Bigchain
|
||||
from bigchaindb.voting import Voting, INVALID, VALID, UNDECIDED
|
||||
|
||||
|
||||
################################################################################
|
||||
# Tests for checking vote eligibility
|
||||
|
||||
|
||||
def test_partition_eligible_votes():
|
||||
class TestVoting(Voting):
|
||||
@classmethod
|
||||
def verify_vote_signature(cls, vote):
|
||||
if vote['node_pubkey'] == 'invalid sig':
|
||||
return False
|
||||
if vote['node_pubkey'] == 'value error':
|
||||
raise ValueError()
|
||||
return True
|
||||
|
||||
voters = ['valid', 'invalid sig', 'value error', 'not in set']
|
||||
votes = [{'node_pubkey': k} for k in voters]
|
||||
|
||||
el, inel = TestVoting.partition_eligible_votes(votes, voters[:-1])
|
||||
assert el == [votes[0]]
|
||||
assert inel == votes[1:]
|
||||
|
||||
|
||||
################################################################################
|
||||
# Test vote counting
|
||||
|
||||
|
||||
def test_count_votes():
|
||||
class TestVoting(Voting):
|
||||
@classmethod
|
||||
def verify_vote_schema(cls, vote):
|
||||
return vote['node_pubkey'] != 'malformed'
|
||||
|
||||
voters = (['says invalid', 'malformed'] +
|
||||
['kosher' + str(i) for i in range(10)])
|
||||
|
||||
votes = [Bigchain(v).vote('block', 'a', True) for v in voters]
|
||||
votes[0]['vote']['is_block_valid'] = False
|
||||
# Incorrect previous block subtracts from n_valid and adds to n_invalid
|
||||
votes[-1]['vote']['previous_block'] = 'z'
|
||||
|
||||
by_voter = dict(enumerate(votes))
|
||||
|
||||
assert TestVoting.count_votes(by_voter) == {
|
||||
'counts': {
|
||||
'n_valid': 9, # 9 kosher votes
|
||||
'n_invalid': 3, # 1 invalid, 1 malformed, 1 rogue prev block
|
||||
},
|
||||
'malformed': [votes[1]],
|
||||
'previous_block': 'a',
|
||||
'other_previous_block': {'z': 1},
|
||||
}
|
||||
|
||||
|
||||
def test_must_agree_prev_block():
|
||||
class TestVoting(Voting):
|
||||
@classmethod
|
||||
def verify_vote_schema(cls, vote):
|
||||
return True
|
||||
|
||||
voters = 'abcd'
|
||||
votes = [Bigchain(v).vote('block', 'a', True) for v in voters]
|
||||
votes[0]['vote']['previous_block'] = 'b'
|
||||
votes[1]['vote']['previous_block'] = 'c'
|
||||
by_voter = dict(enumerate(votes))
|
||||
assert TestVoting.count_votes(by_voter) == {
|
||||
'counts': {
|
||||
'n_valid': 2,
|
||||
'n_invalid': 2,
|
||||
},
|
||||
'previous_block': 'a',
|
||||
'other_previous_block': {'b': 1, 'c': 1},
|
||||
'malformed': [],
|
||||
}
|
||||
|
||||
|
||||
################################################################################
|
||||
# Tests for vote decision making
|
||||
|
||||
|
||||
DECISION_TESTS = [
|
||||
{'n_voters': 1, 'n_valid': 1, 'n_invalid': 1},
|
||||
{'n_voters': 2, 'n_valid': 2, 'n_invalid': 1},
|
||||
{'n_voters': 3, 'n_valid': 2, 'n_invalid': 2},
|
||||
{'n_voters': 4, 'n_valid': 3, 'n_invalid': 2},
|
||||
{'n_voters': 5, 'n_valid': 3, 'n_invalid': 3},
|
||||
{'n_voters': 6, 'n_valid': 4, 'n_invalid': 3},
|
||||
{'n_voters': 7, 'n_valid': 4, 'n_invalid': 4},
|
||||
{'n_voters': 8, 'n_valid': 5, 'n_invalid': 4}
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kwargs', DECISION_TESTS)
|
||||
def test_decide_votes_valid(kwargs):
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['n_invalid'] = 0
|
||||
assert Voting.decide_votes(**kwargs) == VALID
|
||||
kwargs['n_valid'] -= 1
|
||||
assert Voting.decide_votes(**kwargs) == UNDECIDED
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kwargs', DECISION_TESTS)
|
||||
def test_decide_votes_invalid(kwargs):
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['n_valid'] = 0
|
||||
assert Voting.decide_votes(**kwargs) == INVALID
|
||||
kwargs['n_invalid'] -= 1
|
||||
assert Voting.decide_votes(**kwargs) == UNDECIDED
|
||||
|
||||
|
||||
################################################################################
|
||||
# Tests for vote signature
|
||||
|
||||
|
||||
def test_verify_vote_signature_passes(b):
|
||||
vote = b.vote('block', 'a', True)
|
||||
assert Voting.verify_vote_signature(vote)
|
||||
vote['signature'] = ''
|
||||
assert not Voting.verify_vote_signature(vote)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Tests for vote schema
|
||||
|
||||
|
||||
def test_verify_vote_schema(b):
|
||||
vote = b.vote('b' * 64, 'a' * 64, True)
|
||||
assert Voting.verify_vote_schema(vote)
|
||||
vote = b.vote('b' * 64, 'a', True)
|
||||
assert not Voting.verify_vote_schema(vote)
|
||||
vote = b.vote('b', 'a' * 64, True)
|
||||
assert not Voting.verify_vote_schema(vote)
|
@ -86,10 +86,6 @@ def test_get_divisble_transactions_returns_500(b, client):
|
||||
block = b.create_block(tx_list)
|
||||
b.write_block(block)
|
||||
|
||||
# vote the block valid
|
||||
vote = b.vote(block.id, b.get_last_voted_block().id, True)
|
||||
b.write_vote(vote)
|
||||
|
||||
alice_priv, alice_pub = crypto.generate_key_pair()
|
||||
bob_priv, bob_pub = crypto.generate_key_pair()
|
||||
carly_priv, carly_pub = crypto.generate_key_pair()
|
||||
|
@ -1,99 +0,0 @@
|
||||
import pytest
|
||||
|
||||
# from bigchaindb.models import Transaction
|
||||
|
||||
VOTES_ENDPOINT = '/api/v1/votes'
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_get_votes_endpoint(client):
|
||||
gone = 'The votes endpoint is gone now, but it might return in the future.'
|
||||
response = {'message': gone}
|
||||
|
||||
res = client.get(VOTES_ENDPOINT)
|
||||
assert response == res.json
|
||||
assert res.status_code == 404
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=')
|
||||
assert response == res.json
|
||||
assert res.status_code == 404
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=123')
|
||||
assert response == res.json
|
||||
assert res.status_code == 404
|
||||
|
||||
|
||||
"""
|
||||
# Old tests are below. We're keeping their code in a long comment block for now,
|
||||
# because we might bring back a votes endpoint in the future.
|
||||
# https://github.com/bigchaindb/bigchaindb/issues/2037
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_votes_endpoint(b, client, alice):
|
||||
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)])
|
||||
tx = tx.sign([alice.private_key])
|
||||
|
||||
block = b.create_block([tx])
|
||||
b.write_block(block)
|
||||
|
||||
# vote the block valid
|
||||
vote = b.vote(block.id, b.get_last_voted_block().id, True)
|
||||
b.write_vote(vote)
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=' + block.id)
|
||||
assert vote == res.json[0]
|
||||
assert len(res.json) == 1
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_votes_endpoint_multiple_votes(b, client):
|
||||
from bigchaindb.common.crypto import generate_key_pair
|
||||
|
||||
tx = Transaction.create([alice.public_key], [([alice.public_key], 1)])
|
||||
tx = tx.sign([alice.private_key])
|
||||
|
||||
block = b.create_block([tx])
|
||||
b.write_block(block)
|
||||
last_block = b.get_last_voted_block().id
|
||||
# vote the block valid
|
||||
vote_valid = b.vote(block.id, last_block, True)
|
||||
b.write_vote(vote_valid)
|
||||
|
||||
# vote the block invalid
|
||||
# a note can only vote once so we need a new node_pubkey for the second
|
||||
# vote
|
||||
_, pk = generate_key_pair()
|
||||
vote_invalid = b.vote(block.id, last_block, False)
|
||||
vote_invalid['node_pubkey'] = pk
|
||||
b.write_vote(vote_invalid)
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=' + block.id)
|
||||
assert len(res.json) == 2
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_votes_endpoint_returns_empty_list_not_found(client):
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=')
|
||||
assert [] == res.json
|
||||
assert res.status_code == 200
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?block_id=123')
|
||||
assert [] == res.json
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_votes_endpoint_returns_400_bad_query_params(client):
|
||||
res = client.get(VOTES_ENDPOINT)
|
||||
assert res.status_code == 400
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?ts_id=123')
|
||||
assert res.status_code == 400
|
||||
|
||||
res = client.get(VOTES_ENDPOINT + '?tx_id=123&block_id=123')
|
||||
assert res.status_code == 400
|
||||
"""
|
Loading…
x
Reference in New Issue
Block a user