373 integration of the dataaccessor singleton (#389)

* initial singleton usage

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* passing all tests

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* blackified

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* aggretated code into helper functions

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
This commit is contained in:
Jürgen Eckel 2023-04-21 10:48:40 +02:00 committed by GitHub
parent 884c3cc32b
commit 5c4923dbd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 985 additions and 487 deletions

40
docker-compose-aio.yml Normal file
View File

@ -0,0 +1,40 @@
# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
version: '2.2'
services:
planetmint-all-in-one:
image: planetmint/planetmint-aio:latest
expose:
- "22"
- "9984"
- "9985"
- "26656"
- "26657"
- "26658"
command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"]
volumes:
- ./integration/scripts:/usr/src/app/scripts
- shared:/shared
scale: ${SCALE:-4}
test:
build:
context: .
dockerfile: integration/python/Dockerfile
depends_on:
- planetmint-all-in-one
command: ["/scripts/pre-config-test.sh", "/scripts/wait-for-planetmint.sh", "/scripts/test.sh", "pytest", "/src"]
environment:
SCALE: ${SCALE:-4}
volumes:
- ./integration/python/src:/src
- ./integration/scripts:/scripts
- ./integration/cli:/tests
- shared:/shared
volumes:
shared:

View File

@ -28,14 +28,14 @@ from planetmint.backend.models.output import Output
from planetmint.model.dataaccessor import DataAccessor from planetmint.model.dataaccessor import DataAccessor
from planetmint.config import Config from planetmint.config import Config
from planetmint.config_utils import load_validation_plugin from planetmint.config_utils import load_validation_plugin
from planetmint.utils.singleton import Singleton
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Validator: class Validator:
def __init__(self, async_io: bool = False): def __init__(self):
self.async_io = async_io self.models = DataAccessor()
self.models = DataAccessor(async_io=async_io)
self.validation = Validator._get_validation_method() self.validation = Validator._get_validation_method()
@staticmethod @staticmethod
@ -269,7 +269,7 @@ class Validator:
value as the `voting_power` value as the `voting_power`
""" """
validators = {} validators = {}
for validator in self.models.get_validators(height): for validator in self.models.get_validators(height=height):
# NOTE: we assume that Tendermint encodes public key in base64 # NOTE: we assume that Tendermint encodes public key in base64
public_key = public_key_from_ed25519_key(key_from_base64(validator["public_key"]["value"])) public_key = public_key_from_ed25519_key(key_from_base64(validator["public_key"]["value"]))
validators[public_key] = validator["voting_power"] validators[public_key] = validator["voting_power"]
@ -493,7 +493,7 @@ class Validator:
self.migrate_abci_chain() self.migrate_abci_chain()
if election.operation == VALIDATOR_ELECTION: if election.operation == VALIDATOR_ELECTION:
validator_updates = [election.assets[0].data] validator_updates = [election.assets[0].data]
curr_validator_set = self.models.get_validators(new_height) curr_validator_set = self.models.get_validators(height=new_height)
updated_validator_set = new_validator_set(curr_validator_set, validator_updates) updated_validator_set = new_validator_set(curr_validator_set, validator_updates)
updated_validator_set = [v for v in updated_validator_set if v["voting_power"] > 0] updated_validator_set = [v for v in updated_validator_set if v["voting_power"] > 0]

View File

@ -64,7 +64,6 @@ class DBConnection(metaclass=DBSingleton):
backend: str = None, backend: str = None,
connection_timeout: int = None, connection_timeout: int = None,
max_tries: int = None, max_tries: int = None,
async_io: bool = False,
**kwargs **kwargs
): ):
"""Create a new :class:`~.Connection` instance. """Create a new :class:`~.Connection` instance.

View File

@ -407,11 +407,12 @@ def store_validator_set(conn, validators_update: dict):
conn.connect().select(TARANT_TABLE_VALIDATOR_SETS, validators_update["height"], index="height", limit=1).data conn.connect().select(TARANT_TABLE_VALIDATOR_SETS, validators_update["height"], index="height", limit=1).data
) )
unique_id = uuid4().hex if _validator is None or len(_validator) == 0 else _validator[0][0] unique_id = uuid4().hex if _validator is None or len(_validator) == 0 else _validator[0][0]
conn.connect().upsert( result = conn.connect().upsert(
TARANT_TABLE_VALIDATOR_SETS, TARANT_TABLE_VALIDATOR_SETS,
(unique_id, validators_update["height"], validators_update["validators"]), (unique_id, validators_update["height"], validators_update["validators"]),
op_list=[("=", 1, validators_update["height"]), ("=", 2, validators_update["validators"])], op_list=[("=", 1, validators_update["height"]), ("=", 2, validators_update["validators"])],
) )
return result
@register_query(TarantoolDBConnection) @register_query(TarantoolDBConnection)

View File

@ -22,12 +22,19 @@ from planetmint.backend.models.output import Output
from planetmint.backend.models.asset import Asset from planetmint.backend.models.asset import Asset
from planetmint.backend.models.metadata import MetaData from planetmint.backend.models.metadata import MetaData
from planetmint.backend.models.dbtransaction import DbTransaction from planetmint.backend.models.dbtransaction import DbTransaction
from planetmint.utils.singleton import Singleton
class DataAccessor: class DataAccessor(metaclass=Singleton):
def __init__(self, database_connection=None, async_io: bool = False): def __init__(self, database_connection=None):
config_utils.autoconfigure() config_utils.autoconfigure()
self.connection = database_connection if database_connection is not None else Connection(async_io=async_io) self.connection = database_connection if database_connection is not None else Connection()
def close_connection(self):
self.connection.close()
def connect(self):
self.connection.connect()
def store_bulk_transactions(self, transactions): def store_bulk_transactions(self, transactions):
txns = [] txns = []
@ -144,7 +151,7 @@ class DataAccessor:
value as the `voting_power` value as the `voting_power`
""" """
validators = {} validators = {}
for validator in self.get_validators(height): for validator in self.get_validators(height=height):
# NOTE: we assume that Tendermint encodes public key in base64 # NOTE: we assume that Tendermint encodes public key in base64
public_key = public_key_from_ed25519_key(key_from_base64(validator["public_key"]["value"])) public_key = public_key_from_ed25519_key(key_from_base64(validator["public_key"]["value"]))
validators[public_key] = validator["voting_power"] validators[public_key] = validator["voting_power"]

View File

@ -1,7 +1,7 @@
[pytest] [pytest]
testpaths = tests/ testpaths = tests/
norecursedirs = .* *.egg *.egg-info env* devenv* docs norecursedirs = .* *.egg *.egg-info env* devenv* docs
addopts = -m "abci" addopts = -m "not abci"
looponfailroots = planetmint tests looponfailroots = planetmint tests
asyncio_mode = strict asyncio_mode = strict
markers = markers =

View File

@ -157,14 +157,14 @@ def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
b.models.store_bulk_transactions([tx_create_signed])
inputs = tx_create.to_inputs()
# TRANSFER # TRANSFER
tx_transfer = Transfer.generate( tx_transfer = Transfer.generate(
tx_create.to_inputs(), [([alice.public_key], 50), ([alice.public_key], 50)], asset_ids=[tx_create.id] inputs, [([alice.public_key], 50), ([alice.public_key], 50)], asset_ids=[tx_create.id]
) )
tx_transfer_signed = tx_transfer.sign([user_sk]) tx_transfer_signed = tx_transfer.sign([user_sk])
b.models.store_bulk_transactions([tx_create_signed])
assert b.validate_transaction(tx_transfer_signed) == tx_transfer_signed assert b.validate_transaction(tx_transfer_signed) == tx_transfer_signed
assert len(tx_transfer_signed.outputs) == 2 assert len(tx_transfer_signed.outputs) == 2
assert tx_transfer_signed.outputs[0].amount == 50 assert tx_transfer_signed.outputs[0].amount == 50

View File

@ -26,6 +26,103 @@ from planetmint.backend.connection import Connection
from tests.utils import generate_election, generate_validators from tests.utils import generate_election, generate_validators
def mock_get_validators(self, height):
return [
{
"public_key": {
"value": "zL/DasvKulXZzhSNFwx4cLRXKkSM9GPK7Y0nZ4FEylM=",
"type": "ed25519-base64",
},
"voting_power": 10,
}
]
@patch("planetmint.commands.utils.start")
def test_main_entrypoint(mock_start):
from planetmint.commands.planetmint import main
from planetmint.model.dataaccessor import DataAccessor
da = DataAccessor
del da
main()
assert mock_start.called
# @pytest.mark.bdb
def test_chain_migration_election_show_shows_inconclusive(b_flushed, test_abci_rpc):
from tests.utils import flush_db
b = b_flushed
validators = generate_validators([1] * 4)
output = b.models.store_validator_set(1, [v["storage"] for v in validators])
public_key = validators[0]["public_key"]
private_key = validators[0]["private_key"]
voter_keys = [v["private_key"] for v in validators]
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, [{"data": {}}], voter_keys)
assert not run_election_show(Namespace(election_id=election.id), b)
b.process_block(1, [election])
b.models.store_bulk_transactions([election])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_block(Block(height=1, transactions=[], app_hash="")._asdict())
b.models.store_validator_set(2, [v["storage"] for v in validators])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_block(Block(height=2, transactions=[], app_hash="")._asdict())
# TODO insert yet another block here when upgrading to Tendermint 0.22.4.
assert run_election_show(Namespace(election_id=election.id), b) == "status=inconclusive"
@pytest.mark.bdb
def test_chain_migration_election_show_shows_concluded(b_flushed):
b = b_flushed
validators = generate_validators([1] * 4)
b.models.store_validator_set(1, [v["storage"] for v in validators])
public_key = validators[0]["public_key"]
private_key = validators[0]["private_key"]
voter_keys = [v["private_key"] for v in validators]
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, [{"data": {}}], voter_keys)
assert not run_election_show(Namespace(election_id=election.id), b)
b.models.store_bulk_transactions([election])
b.process_block(1, [election])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_abci_chain(1, "chain-X")
b.models.store_block(Block(height=1, transactions=[v.id for v in votes], app_hash="last_app_hash")._asdict())
b.process_block(2, votes)
assert (
run_election_show(Namespace(election_id=election.id), b)
== f'''status=concluded
chain_id=chain-X-migrated-at-height-1
app_hash=last_app_hash
validators=[{''.join([f"""
{{
"pub_key": {{
"type": "tendermint/PubKeyEd25519",
"value": "{v['public_key']}"
}},
"power": {v['storage']['voting_power']}
}}{',' if i + 1 != len(validators) else ''}""" for i, v in enumerate(validators)])}
]'''
)
def test_make_sure_we_dont_remove_any_command(): def test_make_sure_we_dont_remove_any_command():
# thanks to: http://stackoverflow.com/a/18161115/597097 # thanks to: http://stackoverflow.com/a/18161115/597097
from planetmint.commands.planetmint import create_parser from planetmint.commands.planetmint import create_parser
@ -50,22 +147,44 @@ def test_make_sure_we_dont_remove_any_command():
] ]
).command ).command
assert parser.parse_args( assert parser.parse_args(
["election", "new", "chain-migration", "--private-key", "TEMP_PATH_TO_PRIVATE_KEY"] [
"election",
"new",
"chain-migration",
"--private-key",
"TEMP_PATH_TO_PRIVATE_KEY",
]
).command ).command
assert parser.parse_args( assert parser.parse_args(
["election", "approve", "ELECTION_ID", "--private-key", "TEMP_PATH_TO_PRIVATE_KEY"] [
"election",
"approve",
"ELECTION_ID",
"--private-key",
"TEMP_PATH_TO_PRIVATE_KEY",
]
).command ).command
assert parser.parse_args(["election", "show", "ELECTION_ID"]).command assert parser.parse_args(["election", "show", "ELECTION_ID"]).command
assert parser.parse_args(["tendermint-version"]).command assert parser.parse_args(["tendermint-version"]).command
@patch("planetmint.commands.utils.start") @pytest.mark.bdb
def test_main_entrypoint(mock_start): def test_election_approve_called_with_bad_key(
from planetmint.commands.planetmint import main monkeypatch, caplog, b, bad_validator_path, new_validator, node_key, test_abci_rpc
):
from argparse import Namespace
main() b, election_id = call_election(monkeypatch, b, new_validator, node_key, test_abci_rpc)
assert mock_start.called # call run_upsert_validator_approve with args that point to the election, but a bad signing key
args = Namespace(action="approve", election_id=election_id, sk=bad_validator_path, config={})
with caplog.at_level(logging.ERROR):
assert not run_election_approve(args, b, test_abci_rpc)
assert (
caplog.records[0].msg == "The key you provided does not match any of "
"the eligible voters in this election."
)
@patch("planetmint.config_utils.setup_logging") @patch("planetmint.config_utils.setup_logging")
@ -168,7 +287,10 @@ def test_drop_db_does_not_drop_when_interactive_no(mock_db_drop, monkeypatch):
# switch with pytest. It will just hang. Seems related to the monkeypatching of # switch with pytest. It will just hang. Seems related to the monkeypatching of
# input_on_stderr. # input_on_stderr.
def test_run_configure_when_config_does_not_exist( def test_run_configure_when_config_does_not_exist(
monkeypatch, mock_write_config, mock_generate_key_pair, mock_planetmint_backup_config monkeypatch,
mock_write_config,
mock_generate_key_pair,
mock_planetmint_backup_config,
): ):
from planetmint.commands.planetmint import run_configure from planetmint.commands.planetmint import run_configure
@ -180,7 +302,10 @@ def test_run_configure_when_config_does_not_exist(
def test_run_configure_when_config_does_exist( def test_run_configure_when_config_does_exist(
monkeypatch, mock_write_config, mock_generate_key_pair, mock_planetmint_backup_config monkeypatch,
mock_write_config,
mock_generate_key_pair,
mock_planetmint_backup_config,
): ):
value = {} value = {}
@ -329,28 +454,34 @@ def test_election_new_upsert_validator_with_tendermint(b, priv_validator_path, u
@pytest.mark.bdb @pytest.mark.bdb
def test_election_new_upsert_validator_without_tendermint(caplog, b, priv_validator_path, user_sk, test_abci_rpc): def test_election_new_upsert_validator_without_tendermint(
def mock_write(modelist, endpoint, mode_commit, transaction, mode): monkeypatch, caplog, b, priv_validator_path, user_sk, test_abci_rpc
):
def mock_write(self, modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction]) b.models.store_bulk_transactions([transaction])
return (202, "") return (202, "")
b.models.get_validators = mock_get_validators with monkeypatch.context() as m:
test_abci_rpc.write_transaction = mock_write from planetmint.model.dataaccessor import DataAccessor
args = Namespace( m.setattr(DataAccessor, "get_validators", mock_get_validators)
action="new", m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write)
election_type="upsert-validator",
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
power=1,
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
sk=priv_validator_path,
config={},
)
with caplog.at_level(logging.INFO): args = Namespace(
election_id = run_election_new_upsert_validator(args, b, test_abci_rpc) action="new",
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id election_type="upsert-validator",
assert b.models.get_transaction(election_id) public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
power=1,
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
sk=priv_validator_path,
config={},
)
with caplog.at_level(logging.INFO):
election_id = run_election_new_upsert_validator(args, b, test_abci_rpc)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
assert b.models.get_transaction(election_id)
m.undo()
@pytest.mark.abci @pytest.mark.abci
@ -363,20 +494,25 @@ def test_election_new_chain_migration_with_tendermint(b, priv_validator_path, us
@pytest.mark.bdb @pytest.mark.bdb
def test_election_new_chain_migration_without_tendermint(caplog, b, priv_validator_path, user_sk, test_abci_rpc): def test_election_new_chain_migration_without_tendermint(
def mock_write(modelist, endpoint, mode_commit, transaction, mode): monkeypatch, caplog, b, priv_validator_path, user_sk, test_abci_rpc
):
def mock_write(self, modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction]) b.models.store_bulk_transactions([transaction])
return (202, "") return (202, "")
b.models.get_validators = mock_get_validators with monkeypatch.context() as m:
test_abci_rpc.write_transaction = mock_write from planetmint.model.dataaccessor import DataAccessor
args = Namespace(action="new", election_type="migration", sk=priv_validator_path, config={}) m.setattr(DataAccessor, "get_validators", mock_get_validators)
m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write)
with caplog.at_level(logging.INFO): args = Namespace(action="new", election_type="migration", sk=priv_validator_path, config={})
election_id = run_election_new_chain_migration(args, b, test_abci_rpc)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id with caplog.at_level(logging.INFO):
assert b.models.get_transaction(election_id) election_id = run_election_new_chain_migration(args, b, test_abci_rpc)
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
assert b.models.get_transaction(election_id)
@pytest.mark.bdb @pytest.mark.bdb
@ -397,28 +533,34 @@ def test_election_new_upsert_validator_invalid_election(caplog, b, priv_validato
@pytest.mark.bdb @pytest.mark.bdb
def test_election_new_upsert_validator_invalid_power(caplog, b, priv_validator_path, user_sk, test_abci_rpc): def test_election_new_upsert_validator_invalid_power(
monkeypatch, caplog, b, priv_validator_path, user_sk, test_abci_rpc
):
from transactions.common.exceptions import InvalidPowerChange from transactions.common.exceptions import InvalidPowerChange
def mock_write(modelist, endpoint, mode_commit, transaction, mode): def mock_write(self, modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction]) b.models.store_bulk_transactions([transaction])
return (400, "") return (400, "")
test_abci_rpc.write_transaction = mock_write with monkeypatch.context() as m:
b.models.get_validators = mock_get_validators from planetmint.model.dataaccessor import DataAccessor
args = Namespace(
action="new",
election_type="upsert-validator",
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
power=10,
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
sk=priv_validator_path,
config={},
)
with caplog.at_level(logging.ERROR): m.setattr(DataAccessor, "get_validators", mock_get_validators)
assert not run_election_new_upsert_validator(args, b, test_abci_rpc) m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write)
assert caplog.records[0].msg.__class__ == InvalidPowerChange
args = Namespace(
action="new",
election_type="upsert-validator",
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
power=10,
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
sk=priv_validator_path,
config={},
)
with caplog.at_level(logging.ERROR):
assert not run_election_new_upsert_validator(args, b, test_abci_rpc)
assert caplog.records[0].msg.__class__ == InvalidPowerChange
@pytest.mark.abci @pytest.mark.abci
@ -444,27 +586,43 @@ def test_election_approve_with_tendermint(b, priv_validator_path, user_sk, valid
@pytest.mark.bdb @pytest.mark.bdb
def test_election_approve_without_tendermint(caplog, b, priv_validator_path, new_validator, node_key, test_abci_rpc): def test_election_approve_without_tendermint(
monkeypatch, caplog, b, priv_validator_path, new_validator, node_key, test_abci_rpc
):
def mock_write(self, modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction])
return (202, "")
from planetmint.commands.planetmint import run_election_approve from planetmint.commands.planetmint import run_election_approve
from argparse import Namespace from argparse import Namespace
b, election_id = call_election(b, new_validator, node_key, test_abci_rpc) with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
# call run_election_approve with args that point to the election m.setattr(DataAccessor, "get_validators", mock_get_validators)
args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={}) m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write)
# assert returned id is in the db b, election_id = call_election_internal(b, new_validator, node_key)
with caplog.at_level(logging.INFO):
approval_id = run_election_approve(args, b, test_abci_rpc) # call run_election_approve with args that point to the election
assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted" args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
assert b.models.get_transaction(approval_id)
# assert returned id is in the db
with caplog.at_level(logging.INFO):
approval_id = run_election_approve(args, b, test_abci_rpc)
assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted"
assert b.models.get_transaction(approval_id)
m.undo()
from unittest import mock
@pytest.mark.bdb @pytest.mark.bdb
def test_election_approve_failure(caplog, b, priv_validator_path, new_validator, node_key, test_abci_rpc): def test_election_approve_failure(monkeypatch, caplog, b, priv_validator_path, new_validator, node_key, test_abci_rpc):
from argparse import Namespace from argparse import Namespace
b, election_id = call_election(b, new_validator, node_key, test_abci_rpc) b, election_id = call_election(monkeypatch, b, new_validator, node_key, test_abci_rpc)
def mock_write(modelist, endpoint, mode_commit, transaction, mode): def mock_write(modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction]) b.models.store_bulk_transactions([transaction])
@ -480,91 +638,6 @@ def test_election_approve_failure(caplog, b, priv_validator_path, new_validator,
assert caplog.records[0].msg == "Failed to commit vote" assert caplog.records[0].msg == "Failed to commit vote"
@pytest.mark.bdb
def test_election_approve_called_with_bad_key(caplog, b, bad_validator_path, new_validator, node_key, test_abci_rpc):
from argparse import Namespace
b, election_id = call_election(b, new_validator, node_key, test_abci_rpc)
# call run_upsert_validator_approve with args that point to the election, but a bad signing key
args = Namespace(action="approve", election_id=election_id, sk=bad_validator_path, config={})
with caplog.at_level(logging.ERROR):
assert not run_election_approve(args, b, test_abci_rpc)
assert (
caplog.records[0].msg == "The key you provided does not match any of "
"the eligible voters in this election."
)
@pytest.mark.bdb
def test_chain_migration_election_show_shows_inconclusive(b):
validators = generate_validators([1] * 4)
b.models.store_validator_set(1, [v["storage"] for v in validators])
public_key = validators[0]["public_key"]
private_key = validators[0]["private_key"]
voter_keys = [v["private_key"] for v in validators]
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, [{"data": {}}], voter_keys)
assert not run_election_show(Namespace(election_id=election.id), b)
b.process_block(1, [election])
b.models.store_bulk_transactions([election])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_block(Block(height=1, transactions=[], app_hash="")._asdict())
b.models.store_validator_set(2, [v["storage"] for v in validators])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_block(Block(height=2, transactions=[], app_hash="")._asdict())
# TODO insert yet another block here when upgrading to Tendermint 0.22.4.
assert run_election_show(Namespace(election_id=election.id), b) == "status=inconclusive"
@pytest.mark.bdb
def test_chain_migration_election_show_shows_concluded(b):
validators = generate_validators([1] * 4)
b.models.store_validator_set(1, [v["storage"] for v in validators])
public_key = validators[0]["public_key"]
private_key = validators[0]["private_key"]
voter_keys = [v["private_key"] for v in validators]
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, [{"data": {}}], voter_keys)
assert not run_election_show(Namespace(election_id=election.id), b)
b.models.store_bulk_transactions([election])
b.process_block(1, [election])
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
b.models.store_abci_chain(1, "chain-X")
b.models.store_block(Block(height=1, transactions=[v.id for v in votes], app_hash="last_app_hash")._asdict())
b.process_block(2, votes)
assert (
run_election_show(Namespace(election_id=election.id), b)
== f'''status=concluded
chain_id=chain-X-migrated-at-height-1
app_hash=last_app_hash
validators=[{''.join([f"""
{{
"pub_key": {{
"type": "tendermint/PubKeyEd25519",
"value": "{v['public_key']}"
}},
"power": {v['storage']['voting_power']}
}}{',' if i + 1 != len(validators) else ''}""" for i, v in enumerate(validators)])}
]'''
)
def test_bigchain_tendermint_version(capsys): def test_bigchain_tendermint_version(capsys):
from planetmint.commands.planetmint import run_tendermint_version from planetmint.commands.planetmint import run_tendermint_version
@ -578,24 +651,7 @@ def test_bigchain_tendermint_version(capsys):
assert sorted(output_config["tendermint"]) == sorted(__tm_supported_versions__) assert sorted(output_config["tendermint"]) == sorted(__tm_supported_versions__)
def mock_get_validators(height): def call_election_internal(b, new_validator, node_key):
return [
{
"public_key": {"value": "zL/DasvKulXZzhSNFwx4cLRXKkSM9GPK7Y0nZ4FEylM=", "type": "ed25519-base64"},
"voting_power": 10,
}
]
def call_election(b, new_validator, node_key, abci_rpc):
def mock_write(modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction])
return (202, "")
# patch the validator set. We now have one validator with power 10
b.models.get_validators = mock_get_validators
abci_rpc.write_transaction = mock_write
# our voters is a list of length 1, populated from our mocked validator # our voters is a list of length 1, populated from our mocked validator
voters = b.get_recipients_list() voters = b.get_recipients_list()
# and our voter is the public key from the voter list # and our voter is the public key from the voter list
@ -607,3 +663,18 @@ def call_election(b, new_validator, node_key, abci_rpc):
b.models.store_bulk_transactions([valid_election]) b.models.store_bulk_transactions([valid_election])
return b, election_id return b, election_id
def call_election(monkeypatch, b, new_validator, node_key, abci_rpc):
def mock_write(self, modelist, endpoint, mode_commit, transaction, mode):
b.models.store_bulk_transactions([transaction])
return (202, "")
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
m.setattr(DataAccessor, "get_validators", mock_get_validators)
m.setattr("planetmint.abci.rpc.ABCI_RPC.write_transaction", mock_write)
b, election_id = call_election_internal(b, new_validator, node_key)
m.undo()
return b, election_id

View File

@ -27,7 +27,10 @@ from transactions.common import crypto
from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT
from planetmint.abci.utils import key_from_base64 from planetmint.abci.utils import key_from_base64
from planetmint.backend import schema, query from planetmint.backend import schema, query
from transactions.common.crypto import key_pair_from_ed25519_key, public_key_from_ed25519_key from transactions.common.crypto import (
key_pair_from_ed25519_key,
public_key_from_ed25519_key,
)
from planetmint.abci.block import Block from planetmint.abci.block import Block
from planetmint.abci.rpc import MODE_LIST from planetmint.abci.rpc import MODE_LIST
from tests.utils import gen_vote from tests.utils import gen_vote
@ -107,7 +110,10 @@ def _configure_planetmint(request):
# backend = request.config.getoption('--database-backend') # backend = request.config.getoption('--database-backend')
backend = "tarantool_db" backend = "tarantool_db"
config = {"database": Config().get_db_map(backend), "tendermint": Config()._private_real_config["tendermint"]} config = {
"database": Config().get_db_map(backend),
"tendermint": Config()._private_real_config["tendermint"],
}
config["database"]["name"] = test_db_name config["database"]["name"] = test_db_name
config = config_utils.env_config(config) config = config_utils.env_config(config)
config_utils.set_config(config) config_utils.set_config(config)
@ -133,6 +139,28 @@ def _setup_database(_configure_planetmint): # TODO Here is located setup databa
print("Finished deleting `{}`".format(dbname)) print("Finished deleting `{}`".format(dbname))
@pytest.fixture
def da_reset(_setup_database):
from transactions.common.memoize import to_dict, from_dict
from transactions.common.transaction import Transaction
from .utils import flush_db
from planetmint.model.dataaccessor import DataAccessor
da = DataAccessor()
del da
da = DataAccessor()
da.close_connection()
da.connect()
yield
dbname = Config().get()["database"]["name"]
flush_db(da.connection, dbname)
to_dict.cache_clear()
from_dict.cache_clear()
Transaction._input_valid.cache_clear()
@pytest.fixture @pytest.fixture
def _bdb(_setup_database): def _bdb(_setup_database):
from transactions.common.memoize import to_dict, from_dict from transactions.common.memoize import to_dict, from_dict
@ -273,6 +301,38 @@ def test_abci_rpc():
def b(): def b():
from planetmint.application import Validator from planetmint.application import Validator
old_validator_instance = Validator()
del old_validator_instance.models
del old_validator_instance
validator = Validator()
validator.models.connection.close()
validator.models.connection.connect()
return validator
@pytest.fixture
def b_flushed(_setup_database):
from planetmint.application import Validator
from transactions.common.memoize import to_dict, from_dict
from transactions.common.transaction import Transaction
from .utils import flush_db
from planetmint.config import Config
old_validator_instance = Validator()
del old_validator_instance.models
del old_validator_instance
conn = Connection()
conn.close()
conn.connect()
dbname = Config().get()["database"]["name"]
flush_db(conn, dbname)
to_dict.cache_clear()
from_dict.cache_clear()
Transaction._input_valid.cache_clear()
validator = Validator() validator = Validator()
validator.models.connection.close() validator.models.connection.close()
validator.models.connection.connect() validator.models.connection.connect()
@ -286,22 +346,6 @@ def eventqueue_fixture():
return Queue() return Queue()
@pytest.fixture
def b_mock(b, network_validators):
b.models.get_validators = mock_get_validators(network_validators)
return b
def mock_get_validators(network_validators):
def validator_set(height):
validators = []
for public_key, power in network_validators.items():
validators.append({"public_key": {"type": "ed25519-base64", "value": public_key}, "voting_power": power})
return validators
return validator_set
@pytest.fixture @pytest.fixture
def create_tx(alice, user_pk): def create_tx(alice, user_pk):
from transactions.types.assets.create import Create from transactions.types.assets.create import Create
@ -319,7 +363,10 @@ def signed_create_tx(alice, create_tx):
@pytest.fixture @pytest.fixture
def posted_create_tx(b, signed_create_tx, test_abci_rpc): def posted_create_tx(b, signed_create_tx, test_abci_rpc):
res = test_abci_rpc.post_transaction( res = test_abci_rpc.post_transaction(
MODE_LIST, test_abci_rpc.tendermint_rpc_endpoint, signed_create_tx, BROADCAST_TX_COMMIT MODE_LIST,
test_abci_rpc.tendermint_rpc_endpoint,
signed_create_tx,
BROADCAST_TX_COMMIT,
) )
assert res.status_code == 200 assert res.status_code == 200
return signed_create_tx return signed_create_tx
@ -356,7 +403,9 @@ def inputs(user_pk, b, alice):
for height in range(1, 4): for height in range(1, 4):
transactions = [ transactions = [
Create.generate( Create.generate(
[alice.public_key], [([user_pk], 1)], metadata=multihash(marshal({"data": f"{random.random()}"})) [alice.public_key],
[([user_pk], 1)],
metadata=multihash(marshal({"data": f"{random.random()}"})),
).sign([alice.private_key]) ).sign([alice.private_key])
for _ in range(10) for _ in range(10)
] ]
@ -428,7 +477,13 @@ def _abci_http(request):
@pytest.fixture @pytest.fixture
def abci_http(_setup_database, _configure_planetmint, abci_server, tendermint_host, tendermint_port): def abci_http(
_setup_database,
_configure_planetmint,
abci_server,
tendermint_host,
tendermint_port,
):
import requests import requests
import time import time
@ -632,19 +687,19 @@ def new_validator():
node_id = "fake_node_id" node_id = "fake_node_id"
return [ return [
{"data": {"public_key": {"value": public_key, "type": "ed25519-base16"}, "power": power, "node_id": node_id}} {
"data": {
"public_key": {"value": public_key, "type": "ed25519-base16"},
"power": power,
"node_id": node_id,
}
}
] ]
@pytest.fixture @pytest.fixture
def valid_upsert_validator_election(b_mock, node_key, new_validator): def valid_upsert_validator_election(b, node_key, new_validator):
voters = b_mock.get_recipients_list() voters = b.get_recipients_list()
return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key])
@pytest.fixture
def valid_upsert_validator_election_2(b_mock, node_key, new_validator):
voters = b_mock.get_recipients_list()
return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key]) return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key])
@ -660,40 +715,6 @@ def ongoing_validator_election(b, valid_upsert_validator_election, ed25519_node_
return valid_upsert_validator_election return valid_upsert_validator_election
@pytest.fixture
def ongoing_validator_election_2(b, valid_upsert_validator_election_2, ed25519_node_keys):
validators = b.models.get_validators(height=1)
genesis_validators = {"validators": validators, "height": 0, "election_id": None}
query.store_validator_set(b.models.connection, genesis_validators)
b.models.store_bulk_transactions([valid_upsert_validator_election_2])
block_1 = Block(app_hash="hash_2", height=1, transactions=[valid_upsert_validator_election_2.id])
b.models.store_block(block_1._asdict())
return valid_upsert_validator_election_2
@pytest.fixture
def validator_election_votes(b_mock, ongoing_validator_election, ed25519_node_keys):
voters = b_mock.get_recipients_list()
votes = generate_votes(ongoing_validator_election, voters, ed25519_node_keys)
return votes
@pytest.fixture
def validator_election_votes_2(b_mock, ongoing_validator_election_2, ed25519_node_keys):
voters = b_mock.get_recipients_list()
votes = generate_votes(ongoing_validator_election_2, voters, ed25519_node_keys)
return votes
def generate_votes(election, voters, keys):
votes = []
for voter, _ in enumerate(voters):
v = gen_vote(election, voter, keys)
votes.append(v)
return votes
@pytest.fixture @pytest.fixture
def signed_2_0_create_tx(): def signed_2_0_create_tx():
return { return {

View File

@ -5,10 +5,14 @@ from planetmint.abci.block import Block
from transactions.types.elections.election import Election from transactions.types.elections.election import Election
from transactions.types.elections.chain_migration_election import ChainMigrationElection from transactions.types.elections.chain_migration_election import ChainMigrationElection
from transactions.types.elections.validator_election import ValidatorElection from transactions.types.elections.validator_election import ValidatorElection
from planetmint.model.dataaccessor import DataAccessor
@pytest.mark.bdb @pytest.mark.bdb
def test_process_block_concludes_all_elections(b): def test_process_block_concludes_all_elections(b):
del b.models
b.models = DataAccessor()
b.models.connect()
validators = generate_validators([1] * 4) validators = generate_validators([1] * 4)
b.models.store_validator_set(1, [v["storage"] for v in validators]) b.models.store_validator_set(1, [v["storage"] for v in validators])

View File

@ -1,9 +1,28 @@
import pytest
from transactions.types.elections.chain_migration_election import ChainMigrationElection from transactions.types.elections.chain_migration_election import ChainMigrationElection
def test_valid_migration_election(b_mock, node_key): @pytest.mark.bdb
voters = b_mock.get_recipients_list() def test_valid_migration_election(monkeypatch, b, node_key, network_validators):
election = ChainMigrationElection.generate([node_key.public_key], voters, [{"data": {}}], None).sign( def mock_get_validators(self, height):
[node_key.private_key] validators = []
) for public_key, power in network_validators.items():
assert b_mock.validate_election(election) validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
election = ChainMigrationElection.generate([node_key.public_key], voters, [{"data": {}}], None).sign(
[node_key.private_key]
)
assert b.validate_election(election)
m.undo()

View File

@ -46,6 +46,7 @@ def generate_init_chain_request(chain_id, vals=None):
return types.RequestInitChain(validators=vals, chain_id=chain_id) return types.RequestInitChain(validators=vals, chain_id=chain_id)
@pytest.mark.bdb
def test_init_chain_successfully_registers_chain(b): def test_init_chain_successfully_registers_chain(b):
request = generate_init_chain_request("chain-XYZ") request = generate_init_chain_request("chain-XYZ")
res = ApplicationLogic(validator=b).init_chain(request) res = ApplicationLogic(validator=b).init_chain(request)

View File

@ -11,15 +11,15 @@ from transactions.types.elections.validator_election import ValidatorElection
@pytest.fixture @pytest.fixture
def valid_upsert_validator_election_b(b, node_key, new_validator): def valid_upsert_validator_election(b, node_key, new_validator):
voters = b.get_recipients_list() voters = b.get_recipients_list()
return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key]) return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key])
@pytest.fixture @pytest.fixture
@patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4") @patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4")
def fixed_seed_election(b_mock, node_key, new_validator): def fixed_seed_election(b, node_key, new_validator):
voters = b_mock.get_recipients_list() voters = b.get_recipients_list()
return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key]) return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key])

View File

@ -6,6 +6,7 @@
import pytest import pytest
import codecs import codecs
from planetmint.model.dataaccessor import DataAccessor
from planetmint.abci.rpc import MODE_LIST, MODE_COMMIT from planetmint.abci.rpc import MODE_LIST, MODE_COMMIT
from planetmint.abci.utils import public_key_to_base64 from planetmint.abci.utils import public_key_to_base64
@ -22,196 +23,290 @@ from tests.utils import generate_block, gen_vote
pytestmark = [pytest.mark.execute] pytestmark = [pytest.mark.execute]
@pytest.mark.bdb # helper
def test_upsert_validator_valid_election_vote(b_mock, valid_upsert_validator_election, ed25519_node_keys): def get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator):
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
valid_upsert_validator_election = ValidatorElection.generate(
[node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
b.models.store_bulk_transactions([valid_upsert_validator_election])
return valid_upsert_validator_election
# helper
def get_voting_set(valid_upsert_validator_election, ed25519_node_keys):
input0 = valid_upsert_validator_election.to_inputs()[0] input0 = valid_upsert_validator_election.to_inputs()[0]
votes = valid_upsert_validator_election.outputs[0].amount votes = valid_upsert_validator_election.outputs[0].amount
public_key0 = input0.owners_before[0] public_key0 = input0.owners_before[0]
key0 = ed25519_node_keys[public_key0] key0 = ed25519_node_keys[public_key0]
return input0, votes, key0
election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
vote = Vote.generate(
[input0], [([election_pub_key], votes)], election_ids=[valid_upsert_validator_election.id]
).sign([key0.private_key])
assert b_mock.validate_transaction(vote)
@pytest.mark.bdb @pytest.mark.bdb
def test_upsert_validator_valid_non_election_vote(b_mock, valid_upsert_validator_election, ed25519_node_keys): def test_upsert_validator_valid_election_vote(
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) monkeypatch, b, network_validators, new_validator, node_key, ed25519_node_keys
):
def mock_get_validators(self, height):
validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
input0 = valid_upsert_validator_election.to_inputs()[0] with monkeypatch.context() as m:
votes = valid_upsert_validator_election.outputs[0].amount valid_upsert_validator_election = get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator)
public_key0 = input0.owners_before[0] input0, votes, key0 = get_voting_set(valid_upsert_validator_election, ed25519_node_keys)
key0 = ed25519_node_keys[public_key0]
election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id) election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
# Ensure that threshold conditions are now allowed vote = Vote.generate(
with pytest.raises(ValidationError): [input0], [([election_pub_key], votes)], election_ids=[valid_upsert_validator_election.id]
Vote.generate( ).sign([key0.private_key])
[input0], [([election_pub_key, key0.public_key], votes)], election_ids=[valid_upsert_validator_election.id] assert b.validate_transaction(vote)
m.undo()
@pytest.mark.bdb
def test_upsert_validator_valid_non_election_vote(
monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys
):
def mock_get_validators(self, height):
validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
valid_upsert_validator_election = get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator)
input0, votes, key0 = get_voting_set(valid_upsert_validator_election, ed25519_node_keys)
election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
# Ensure that threshold conditions are now allowed
with pytest.raises(ValidationError):
Vote.generate(
[input0],
[([election_pub_key, key0.public_key], votes)],
election_ids=[valid_upsert_validator_election.id],
).sign([key0.private_key])
m.undo()
@pytest.mark.bdb
def test_upsert_validator_delegate_election_vote(
monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys
):
def mock_get_validators(self, height):
validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
valid_upsert_validator_election = get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator)
alice = generate_key_pair()
input0, votes, key0 = get_voting_set(valid_upsert_validator_election, ed25519_node_keys)
delegate_vote = Vote.generate(
[input0],
[([alice.public_key], 3), ([key0.public_key], votes - 3)],
election_ids=[valid_upsert_validator_election.id],
).sign([key0.private_key]) ).sign([key0.private_key])
assert b.validate_transaction(delegate_vote)
@pytest.mark.bdb b.models.store_bulk_transactions([delegate_vote])
def test_upsert_validator_delegate_election_vote(b_mock, valid_upsert_validator_election, ed25519_node_keys): election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
alice = generate_key_pair()
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) alice_votes = delegate_vote.to_inputs()[0]
alice_casted_vote = Vote.generate(
[alice_votes], [([election_pub_key], 3)], election_ids=[valid_upsert_validator_election.id]
).sign([alice.private_key])
assert b.validate_transaction(alice_casted_vote)
input0 = valid_upsert_validator_election.to_inputs()[0] key0_votes = delegate_vote.to_inputs()[1]
votes = valid_upsert_validator_election.outputs[0].amount key0_casted_vote = Vote.generate(
public_key0 = input0.owners_before[0] [key0_votes], [([election_pub_key], votes - 3)], election_ids=[valid_upsert_validator_election.id]
key0 = ed25519_node_keys[public_key0] ).sign([key0.private_key])
assert b.validate_transaction(key0_casted_vote)
delegate_vote = Vote.generate( m.undo()
[input0],
[([alice.public_key], 3), ([key0.public_key], votes - 3)],
election_ids=[valid_upsert_validator_election.id],
).sign([key0.private_key])
assert b_mock.validate_transaction(delegate_vote)
b_mock.models.store_bulk_transactions([delegate_vote])
election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
alice_votes = delegate_vote.to_inputs()[0]
alice_casted_vote = Vote.generate(
[alice_votes], [([election_pub_key], 3)], election_ids=[valid_upsert_validator_election.id]
).sign([alice.private_key])
assert b_mock.validate_transaction(alice_casted_vote)
key0_votes = delegate_vote.to_inputs()[1]
key0_casted_vote = Vote.generate(
[key0_votes], [([election_pub_key], votes - 3)], election_ids=[valid_upsert_validator_election.id]
).sign([key0.private_key])
assert b_mock.validate_transaction(key0_casted_vote)
@pytest.mark.bdb @pytest.mark.bdb
def test_upsert_validator_invalid_election_vote(b_mock, valid_upsert_validator_election, ed25519_node_keys): def test_upsert_validator_invalid_election_vote(
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys
):
def mock_get_validators(self, height):
validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
input0 = valid_upsert_validator_election.to_inputs()[0] with monkeypatch.context() as m:
votes = valid_upsert_validator_election.outputs[0].amount valid_upsert_validator_election = get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator)
public_key0 = input0.owners_before[0] input0, votes, key0 = get_voting_set(valid_upsert_validator_election, ed25519_node_keys)
key0 = ed25519_node_keys[public_key0]
election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id) election_pub_key = election_id_to_public_key(valid_upsert_validator_election.id)
vote = Vote.generate( vote = Vote.generate(
[input0], [([election_pub_key], votes + 1)], election_ids=[valid_upsert_validator_election.id] [input0], [([election_pub_key], votes + 1)], election_ids=[valid_upsert_validator_election.id]
).sign([key0.private_key]) ).sign([key0.private_key])
with pytest.raises(AmountError): with pytest.raises(AmountError):
assert b_mock.validate_transaction(vote) assert b.validate_transaction(vote)
@pytest.mark.bdb @pytest.mark.bdb
def test_valid_election_votes_received(b_mock, valid_upsert_validator_election, ed25519_node_keys): def test_valid_election_votes_received(monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys):
alice = generate_key_pair() def mock_get_validators(self, height):
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) validators = []
assert b_mock.get_commited_votes(valid_upsert_validator_election) == 0 for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
input0 = valid_upsert_validator_election.to_inputs()[0] with monkeypatch.context() as m:
votes = valid_upsert_validator_election.outputs[0].amount valid_upsert_validator_election = get_valid_upsert_election(m, b, mock_get_validators, node_key, new_validator)
public_key0 = input0.owners_before[0] alice = generate_key_pair()
key0 = ed25519_node_keys[public_key0]
# delegate some votes to alice assert b.get_commited_votes(valid_upsert_validator_election) == 0
delegate_vote = Vote.generate( input0, votes, key0 = get_voting_set(valid_upsert_validator_election, ed25519_node_keys)
[input0],
[([alice.public_key], 4), ([key0.public_key], votes - 4)],
election_ids=[valid_upsert_validator_election.id],
).sign([key0.private_key])
b_mock.models.store_bulk_transactions([delegate_vote])
assert b_mock.get_commited_votes(valid_upsert_validator_election) == 0
election_public_key = election_id_to_public_key(valid_upsert_validator_election.id) # delegate some votes to alice
alice_votes = delegate_vote.to_inputs()[0] delegate_vote = Vote.generate(
key0_votes = delegate_vote.to_inputs()[1] [input0],
[([alice.public_key], 4), ([key0.public_key], votes - 4)],
election_ids=[valid_upsert_validator_election.id],
).sign([key0.private_key])
b.models.store_bulk_transactions([delegate_vote])
assert b.get_commited_votes(valid_upsert_validator_election) == 0
alice_casted_vote = Vote.generate( election_public_key = election_id_to_public_key(valid_upsert_validator_election.id)
[alice_votes], alice_votes = delegate_vote.to_inputs()[0]
[([election_public_key], 2), ([alice.public_key], 2)], key0_votes = delegate_vote.to_inputs()[1]
election_ids=[valid_upsert_validator_election.id],
).sign([alice.private_key])
assert b_mock.validate_transaction(alice_casted_vote) alice_casted_vote = Vote.generate(
b_mock.models.store_bulk_transactions([alice_casted_vote]) [alice_votes],
[([election_public_key], 2), ([alice.public_key], 2)],
election_ids=[valid_upsert_validator_election.id],
).sign([alice.private_key])
# Check if the delegated vote is count as valid vote assert b.validate_transaction(alice_casted_vote)
assert b_mock.get_commited_votes(valid_upsert_validator_election) == 2 b.models.store_bulk_transactions([alice_casted_vote])
key0_casted_vote = Vote.generate( # Check if the delegated vote is count as valid vote
[key0_votes], [([election_public_key], votes - 4)], election_ids=[valid_upsert_validator_election.id] assert b.get_commited_votes(valid_upsert_validator_election) == 2
).sign([key0.private_key])
assert b_mock.validate_transaction(key0_casted_vote) key0_casted_vote = Vote.generate(
b_mock.models.store_bulk_transactions([key0_casted_vote]) [key0_votes], [([election_public_key], votes - 4)], election_ids=[valid_upsert_validator_election.id]
assert b_mock.get_commited_votes(valid_upsert_validator_election) == votes - 2 ).sign([key0.private_key])
assert b.validate_transaction(key0_casted_vote)
b.models.store_bulk_transactions([key0_casted_vote])
assert b.get_commited_votes(valid_upsert_validator_election) == votes - 2
@pytest.mark.bdb @pytest.mark.bdb
def test_valid_election_conclude(b_mock, valid_upsert_validator_election, ed25519_node_keys): def test_valid_election_conclude(monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys):
# Node 0: cast vote def mock_get_validators(self, height):
tx_vote0 = gen_vote(valid_upsert_validator_election, 0, ed25519_node_keys) validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
# check if the vote is valid even before the election doesn't exist with monkeypatch.context() as m:
with pytest.raises(ValidationError): from planetmint.model.dataaccessor import DataAccessor
assert b_mock.validate_transaction(tx_vote0)
# store election m.setattr(DataAccessor, "get_validators", mock_get_validators)
b_mock.models.store_bulk_transactions([valid_upsert_validator_election]) voters = b.get_recipients_list()
# cannot conclude election as not votes exist valid_upsert_validator_election = ValidatorElection.generate(
assert not b_mock.has_election_concluded(valid_upsert_validator_election) [node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
# validate vote # Node 0: cast vote
assert b_mock.validate_transaction(tx_vote0) tx_vote0 = gen_vote(valid_upsert_validator_election, 0, ed25519_node_keys)
assert not b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote0])
b_mock.models.store_bulk_transactions([tx_vote0]) # check if the vote is valid even before the election doesn't exist
assert not b_mock.has_election_concluded(valid_upsert_validator_election) with pytest.raises(ValidationError):
assert b.validate_transaction(tx_vote0)
# Node 1: cast vote # store election
tx_vote1 = gen_vote(valid_upsert_validator_election, 1, ed25519_node_keys) b.models.store_bulk_transactions([valid_upsert_validator_election])
# cannot conclude election as not votes exist
assert not b.has_election_concluded(valid_upsert_validator_election)
# Node 2: cast vote # validate vote
tx_vote2 = gen_vote(valid_upsert_validator_election, 2, ed25519_node_keys) assert b.validate_transaction(tx_vote0)
assert not b.has_election_concluded(valid_upsert_validator_election, [tx_vote0])
# Node 3: cast vote b.models.store_bulk_transactions([tx_vote0])
tx_vote3 = gen_vote(valid_upsert_validator_election, 3, ed25519_node_keys) assert not b.has_election_concluded(valid_upsert_validator_election)
assert b_mock.validate_transaction(tx_vote1) # Node 1: cast vote
assert not b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote1]) tx_vote1 = gen_vote(valid_upsert_validator_election, 1, ed25519_node_keys)
# 2/3 is achieved in the same block so the election can be.has_concludedd # Node 2: cast vote
assert b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote1, tx_vote2]) tx_vote2 = gen_vote(valid_upsert_validator_election, 2, ed25519_node_keys)
b_mock.models.store_bulk_transactions([tx_vote1]) # Node 3: cast vote
assert not b_mock.has_election_concluded(valid_upsert_validator_election) tx_vote3 = gen_vote(valid_upsert_validator_election, 3, ed25519_node_keys)
assert b_mock.validate_transaction(tx_vote2) assert b.validate_transaction(tx_vote1)
assert b_mock.validate_transaction(tx_vote3) assert not b.has_election_concluded(valid_upsert_validator_election, [tx_vote1])
# conclusion can be triggered my different votes in the same block # 2/3 is achieved in the same block so the election can be.has_concludedd
assert b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote2]) assert b.has_election_concluded(valid_upsert_validator_election, [tx_vote1, tx_vote2])
assert b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote2, tx_vote3])
b_mock.models.store_bulk_transactions([tx_vote2]) b.models.store_bulk_transactions([tx_vote1])
assert not b.has_election_concluded(valid_upsert_validator_election)
# Once the blockchain records >2/3 of the votes the election is assumed to be.has_concludedd assert b.validate_transaction(tx_vote2)
# so any invocation of `.has_concluded` for that election should return False assert b.validate_transaction(tx_vote3)
assert not b_mock.has_election_concluded(valid_upsert_validator_election)
# Vote is still valid but the election cannot be.has_concluded as it it assumed that it has # conclusion can be triggered my different votes in the same block
# been.has_concludedd before assert b.has_election_concluded(valid_upsert_validator_election, [tx_vote2])
assert b_mock.validate_transaction(tx_vote3) assert b.has_election_concluded(valid_upsert_validator_election, [tx_vote2, tx_vote3])
assert not b_mock.has_election_concluded(valid_upsert_validator_election, [tx_vote3])
b.models.store_bulk_transactions([tx_vote2])
# Once the blockchain records >2/3 of the votes the election is assumed to be.has_concludedd
# so any invocation of `.has_concluded` for that election should return False
assert not b.has_election_concluded(valid_upsert_validator_election)
# Vote is still valid but the election cannot be.has_concluded as it it assumed that it has
# been.has_concludedd before
assert b.validate_transaction(tx_vote3)
assert not b.has_election_concluded(valid_upsert_validator_election, [tx_vote3])
@pytest.mark.abci @pytest.mark.abci

View File

@ -21,110 +21,280 @@ from transactions.common.exceptions import (
pytestmark = pytest.mark.bdb pytestmark = pytest.mark.bdb
def test_upsert_validator_valid_election(b_mock, new_validator, node_key): def test_upsert_validator_valid_election(monkeypatch, b, network_validators, new_validator, node_key):
voters = b_mock.get_recipients_list() def mock_get_validators(self, height):
election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign( validators = []
[node_key.private_key] for public_key, power in network_validators.items():
) validators.append(
assert b_mock.validate_election(election) {
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign(
[node_key.private_key]
)
assert b.validate_election(election)
m.undo()
def test_upsert_validator_invalid_election_public_key(b_mock, new_validator, node_key): def test_upsert_validator_invalid_election_public_key(monkeypatch, b, network_validators, new_validator, node_key):
from transactions.common.exceptions import InvalidPublicKey def mock_get_validators(self, height):
validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
for iv in ["ed25519-base32", "ed25519-base64"]: with monkeypatch.context() as m:
new_validator[0]["data"]["public_key"]["type"] = iv from planetmint.model.dataaccessor import DataAccessor
voters = b_mock.get_recipients_list()
with pytest.raises(InvalidPublicKey): m.setattr(DataAccessor, "get_validators", mock_get_validators)
ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key]) from transactions.common.exceptions import InvalidPublicKey
for iv in ["ed25519-base32", "ed25519-base64"]:
new_validator[0]["data"]["public_key"]["type"] = iv
voters = b.get_recipients_list()
with pytest.raises(InvalidPublicKey):
ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign(
[node_key.private_key]
)
m.undo()
def test_upsert_validator_invalid_power_election(b_mock, new_validator, node_key): def test_upsert_validator_invalid_power_election(monkeypatch, b, network_validators, new_validator, node_key):
voters = b_mock.get_recipients_list() def mock_get_validators(self, height):
new_validator[0]["data"]["power"] = 30 validators = []
for public_key, power in network_validators.items():
validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign( with monkeypatch.context() as m:
[node_key.private_key] from planetmint.model.dataaccessor import DataAccessor
)
with pytest.raises(InvalidPowerChange): m.setattr(DataAccessor, "get_validators", mock_get_validators)
b_mock.validate_election(election) voters = b.get_recipients_list()
new_validator[0]["data"]["power"] = 30
election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign(
[node_key.private_key]
)
with pytest.raises(InvalidPowerChange):
b.validate_election(election)
m.undo()
def test_upsert_validator_invalid_proposed_election(b_mock, new_validator, node_key): def test_upsert_validator_invalid_proposed_election(monkeypatch, b, network_validators, new_validator, node_key):
from transactions.common.crypto import generate_key_pair from transactions.common.crypto import generate_key_pair
alice = generate_key_pair() def mock_get_validators(self, height):
voters = b_mock.get_recipients_list() validators = []
election = ValidatorElection.generate([alice.public_key], voters, new_validator, None).sign([alice.private_key]) for public_key, power in network_validators.items():
with pytest.raises(InvalidProposer): validators.append(
b_mock.validate_election(election) {
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
m.setattr(DataAccessor, "get_validators", mock_get_validators)
alice = generate_key_pair()
voters = b.get_recipients_list()
election = ValidatorElection.generate([alice.public_key], voters, new_validator, None).sign(
[alice.private_key]
)
with pytest.raises(InvalidProposer):
b.validate_election(election)
def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_key): def test_upsert_validator_invalid_inputs_election(monkeypatch, b, network_validators, new_validator, node_key):
from transactions.common.crypto import generate_key_pair from transactions.common.crypto import generate_key_pair
alice = generate_key_pair() def mock_get_validators(self, height):
voters = b_mock.get_recipients_list() validators = []
election = ValidatorElection.generate([node_key.public_key, alice.public_key], voters, new_validator, None).sign( for public_key, power in network_validators.items():
[node_key.private_key, alice.private_key] validators.append(
) {
with pytest.raises(MultipleInputsError): "public_key": {"type": "ed25519-base64", "value": public_key},
b_mock.validate_election(election) "voting_power": power,
}
)
return validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
m.setattr(DataAccessor, "get_validators", mock_get_validators)
alice = generate_key_pair()
voters = b.get_recipients_list()
election = ValidatorElection.generate(
[node_key.public_key, alice.public_key], voters, new_validator, None
).sign([node_key.private_key, alice.private_key])
with pytest.raises(MultipleInputsError):
b.validate_election(election)
m.undo()
@patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4") @patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4")
def test_upsert_validator_invalid_election(b_mock, new_validator, node_key, fixed_seed_election): def test_upsert_validator_invalid_election(monkeypatch, b, network_validators, new_validator, node_key):
voters = b_mock.get_recipients_list() def mock_get_validators(self, height):
duplicate_election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign( validators = []
[node_key.private_key] for public_key, power in network_validators.items():
) validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return validators
with pytest.raises(DuplicateTransaction): with monkeypatch.context() as m:
b_mock.validate_election(fixed_seed_election, [duplicate_election]) from planetmint.model.dataaccessor import DataAccessor
b_mock.models.store_bulk_transactions([fixed_seed_election]) m.setattr(DataAccessor, "get_validators", mock_get_validators)
with pytest.raises(DuplicateTransaction): voters = b.get_recipients_list()
b_mock.validate_election(duplicate_election) duplicate_election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign(
[node_key.private_key]
)
voters = b.get_recipients_list()
fixed_seed_election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign(
[node_key.private_key]
)
# Try creating an election with incomplete voter set with pytest.raises(DuplicateTransaction):
invalid_election = ValidatorElection.generate([node_key.public_key], voters[1:], new_validator, None).sign( b.validate_election(fixed_seed_election, [duplicate_election])
[node_key.private_key]
)
with pytest.raises(UnequalValidatorSet): b.models.store_bulk_transactions([fixed_seed_election])
b_mock.validate_election(invalid_election)
recipients = b_mock.get_recipients_list() with pytest.raises(DuplicateTransaction):
altered_recipients = [] b.validate_election(duplicate_election)
for r in recipients:
([r_public_key], voting_power) = r
altered_recipients.append(([r_public_key], voting_power - 1))
# Create a transaction which doesn't enfore the network power # Try creating an election with incomplete voter set
tx_election = ValidatorElection.generate([node_key.public_key], altered_recipients, new_validator, None).sign( invalid_election = ValidatorElection.generate([node_key.public_key], voters[1:], new_validator, None).sign(
[node_key.private_key] [node_key.private_key]
) )
with pytest.raises(UnequalValidatorSet): with pytest.raises(UnequalValidatorSet):
b_mock.validate_election(tx_election) b.validate_election(invalid_election)
recipients = b.get_recipients_list()
altered_recipients = []
for r in recipients:
([r_public_key], voting_power) = r
altered_recipients.append(([r_public_key], voting_power - 1))
# Create a transaction which doesn't enfore the network power
tx_election = ValidatorElection.generate([node_key.public_key], altered_recipients, new_validator, None).sign(
[node_key.private_key]
)
with pytest.raises(UnequalValidatorSet):
b.validate_election(tx_election)
m.undo()
def test_get_status_ongoing(b, ongoing_validator_election, new_validator): def test_get_status_ongoing(monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys):
status = ValidatorElection.ONGOING def mock_get_validators(self, height):
resp = b.get_election_status(ongoing_validator_election) _validators = []
assert resp == status for public_key, power in network_validators.items():
_validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return _validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
from planetmint.backend import schema, query
from planetmint.abci.block import Block
m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
valid_upsert_validator_election = ValidatorElection.generate(
[node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
validators = b.models.get_validators(height=1)
genesis_validators = {"validators": validators, "height": 0}
query.store_validator_set(b.models.connection, genesis_validators)
b.models.store_bulk_transactions([valid_upsert_validator_election])
query.store_election(b.models.connection, valid_upsert_validator_election.id, 1, is_concluded=False)
block_1 = Block(app_hash="hash_1", height=1, transactions=[valid_upsert_validator_election.id])
b.models.store_block(block_1._asdict())
status = ValidatorElection.ONGOING
resp = b.get_election_status(valid_upsert_validator_election)
assert resp == status
m.undo()
def test_get_status_concluded(b, concluded_election, new_validator): def test_get_status_concluded(monkeypatch, b, network_validators, node_key, new_validator, ed25519_node_keys):
status = ValidatorElection.CONCLUDED def mock_get_validators(self, height):
resp = b.get_election_status(concluded_election) _validators = []
assert resp == status for public_key, power in network_validators.items():
_validators.append(
{
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return _validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
from planetmint.backend import schema, query
from planetmint.abci.block import Block
m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
valid_upsert_validator_election = ValidatorElection.generate(
[node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
validators = b.models.get_validators(height=1)
genesis_validators = {"validators": validators, "height": 0}
query.store_validator_set(b.models.connection, genesis_validators)
b.models.store_bulk_transactions([valid_upsert_validator_election])
query.store_election(b.models.connection, valid_upsert_validator_election.id, 1, is_concluded=False)
block_1 = Block(app_hash="hash_1", height=1, transactions=[valid_upsert_validator_election.id])
b.models.store_block(block_1._asdict())
query.store_election(b.models.connection, valid_upsert_validator_election.id, 2, is_concluded=True)
status = ValidatorElection.CONCLUDED
resp = b.get_election_status(valid_upsert_validator_election)
assert resp == status
m.undo()
def test_get_status_inconclusive(b, inconclusive_election, new_validator): def test_get_status_inconclusive(monkeypatch, b, network_validators, node_key, new_validator):
def set_block_height_to_3(): def set_block_height_to_3(self):
return {"height": 3} return {"height": 3}
def custom_mock_get_validators(height): def custom_mock_get_validators(height):
@ -167,24 +337,94 @@ def test_get_status_inconclusive(b, inconclusive_election, new_validator):
}, },
] ]
b.models.get_validators = custom_mock_get_validators def mock_get_validators(self, height):
b.models.get_latest_block = set_block_height_to_3 _validators = []
status = ValidatorElection.INCONCLUSIVE for public_key, power in network_validators.items():
resp = b.get_election_status(inconclusive_election) _validators.append(
assert resp == status {
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return _validators
with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
from planetmint.backend import schema, query
from planetmint.abci.block import Block
m.setattr(DataAccessor, "get_validators", mock_get_validators)
voters = b.get_recipients_list()
valid_upsert_validator_election = ValidatorElection.generate(
[node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
validators = b.models.get_validators(height=1)
genesis_validators = {"validators": validators, "height": 0}
query.store_validator_set(b.models.connection, genesis_validators)
b.models.store_bulk_transactions([valid_upsert_validator_election])
query.store_election(b.models.connection, valid_upsert_validator_election.id, 1, is_concluded=False)
block_1 = Block(app_hash="hash_1", height=1, transactions=[valid_upsert_validator_election.id])
b.models.store_block(block_1._asdict())
validators = b.models.get_validators(height=1)
validators[0]["voting_power"] = 15
validator_update = {"validators": validators, "height": 2, "election_id": "some_other_election"}
query.store_validator_set(b.models.connection, validator_update)
m.undo()
with monkeypatch.context() as m2:
m2.setattr(DataAccessor, "get_validators", custom_mock_get_validators)
m2.setattr(DataAccessor, "get_latest_block", set_block_height_to_3)
status = ValidatorElection.INCONCLUSIVE
resp = b.get_election_status(valid_upsert_validator_election)
assert resp == status
m2.undo()
def test_upsert_validator_show(caplog, ongoing_validator_election, b): def test_upsert_validator_show(monkeypatch, caplog, b, node_key, new_validator, network_validators):
from planetmint.commands.planetmint import run_election_show from planetmint.commands.planetmint import run_election_show
election_id = ongoing_validator_election.id def mock_get_validators(self, height):
public_key = public_key_to_base64(ongoing_validator_election.assets[0]["data"]["public_key"]["value"]) _validators = []
power = ongoing_validator_election.assets[0]["data"]["power"] for public_key, power in network_validators.items():
node_id = ongoing_validator_election.assets[0]["data"]["node_id"] _validators.append(
status = ValidatorElection.ONGOING {
"public_key": {"type": "ed25519-base64", "value": public_key},
"voting_power": power,
}
)
return _validators
show_args = Namespace(action="show", election_id=election_id) with monkeypatch.context() as m:
from planetmint.model.dataaccessor import DataAccessor
from planetmint.backend import schema, query
from planetmint.abci.block import Block
msg = run_election_show(show_args, b) m.setattr(DataAccessor, "get_validators", mock_get_validators)
assert msg == f"public_key={public_key}\npower={power}\nnode_id={node_id}\nstatus={status}" voters = b.get_recipients_list()
valid_upsert_validator_election = ValidatorElection.generate(
[node_key.public_key], voters, new_validator, None
).sign([node_key.private_key])
validators = b.models.get_validators(height=1)
genesis_validators = {"validators": validators, "height": 0}
query.store_validator_set(b.models.connection, genesis_validators)
b.models.store_bulk_transactions([valid_upsert_validator_election])
query.store_election(b.models.connection, valid_upsert_validator_election.id, 1, is_concluded=False)
block_1 = Block(app_hash="hash_1", height=1, transactions=[valid_upsert_validator_election.id])
b.models.store_block(block_1._asdict())
election_id = valid_upsert_validator_election.id
public_key = public_key_to_base64(valid_upsert_validator_election.assets[0]["data"]["public_key"]["value"])
power = valid_upsert_validator_election.assets[0]["data"]["power"]
node_id = valid_upsert_validator_election.assets[0]["data"]["node_id"]
status = ValidatorElection.ONGOING
show_args = Namespace(action="show", election_id=election_id)
msg = run_election_show(show_args, b)
assert msg == f"public_key={public_key}\npower={power}\nnode_id={node_id}\nstatus={status}"
m.undo()

View File

@ -8,6 +8,16 @@ import pytest
BLOCKS_ENDPOINT = "/api/v1/blocks/" BLOCKS_ENDPOINT = "/api/v1/blocks/"
@pytest.mark.bdb
@pytest.mark.usefixtures("inputs")
def test_get_latest_block(client):
res = client.get(BLOCKS_ENDPOINT + "latest")
assert res.status_code == 200
assert len(res.json["transaction_ids"]) == 10
assert res.json["app_hash"] == "hash3"
assert res.json["height"] == 3
@pytest.mark.bdb @pytest.mark.bdb
@pytest.mark.usefixtures("inputs") @pytest.mark.usefixtures("inputs")
def test_get_block_returns_404_if_not_found(client): def test_get_block_returns_404_if_not_found(client):
@ -55,16 +65,6 @@ def test_get_blocks_by_txid_endpoint_returns_400_bad_query_params(client):
assert res.json == {"message": "Unknown arguments: status"} assert res.json == {"message": "Unknown arguments: status"}
@pytest.mark.bdb
@pytest.mark.usefixtures("inputs")
def test_get_latest_block(client):
res = client.get(BLOCKS_ENDPOINT + "latest")
assert res.status_code == 200
assert len(res.json["transaction_ids"]) == 10
assert res.json["app_hash"] == "hash3"
assert res.json["height"] == 3
@pytest.mark.bdb @pytest.mark.bdb
@pytest.mark.usefixtures("inputs") @pytest.mark.usefixtures("inputs")
def test_get_block_by_height(client): def test_get_block_by_height(client):