""" This file is part of nucypher. nucypher is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. nucypher is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with nucypher. If not, see . """ import os import tempfile import datetime import maya import pytest from sqlalchemy.engine import create_engine from constant_sorrow.constants import NON_PAYMENT from nucypher.blockchain.eth.constants import DISPATCHER_SECRET_LENGTH from nucypher.blockchain.eth.deployers import PolicyManagerDeployer, NucypherTokenDeployer, MinerEscrowDeployer from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface from nucypher.blockchain.eth.registry import InMemoryEthereumContractRegistry from nucypher.blockchain.eth.sol.compile import SolidityCompiler from nucypher.characters.lawful import Bob, Enrico from nucypher.config.characters import UrsulaConfiguration, AliceConfiguration, BobConfiguration from nucypher.config.constants import BASE_DIR from nucypher.config.node import NodeConfiguration from nucypher.keystore import keystore from nucypher.keystore.db import Base from nucypher.utilities.sandbox.blockchain import TesterBlockchain, token_airdrop from nucypher.utilities.sandbox.constants import (NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK, DEVELOPMENT_TOKEN_AIRDROP_AMOUNT, MOCK_URSULA_STARTING_PORT, MOCK_POLICY_DEFAULT_M) from nucypher.utilities.sandbox.middleware import MockRestMiddleware from nucypher.utilities.sandbox.ursula import make_federated_ursulas, make_decentralized_ursulas TEST_CONTRACTS_DIR = os.path.join(BASE_DIR, 'tests', 'blockchain', 'eth', 'contracts', 'contracts') # # Temporary # @pytest.fixture(scope="function") def tempfile_path(): fd, path = tempfile.mkstemp() yield path os.close(fd) os.remove(path) @pytest.fixture(scope="module") def temp_dir_path(): temp_dir = tempfile.TemporaryDirectory(prefix='nucypher-test-') yield temp_dir.name temp_dir.cleanup() @pytest.fixture(scope="module") def temp_config_root(temp_dir_path): """ User is responsible for closing the file given at the path. """ default_node_config = NodeConfiguration(dev_mode=True, config_root=temp_dir_path, import_seed_registry=False) yield default_node_config.config_root default_node_config.cleanup() @pytest.fixture(scope="module") def test_keystore(): engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) test_keystore = keystore.KeyStore(engine) yield test_keystore @pytest.fixture(scope='function') def certificates_tempdir(): custom_filepath = '/tmp/nucypher-test-certificates-' cert_tmpdir = tempfile.TemporaryDirectory(prefix=custom_filepath) yield cert_tmpdir.name cert_tmpdir.cleanup() # # Configuration # @pytest.fixture(scope="module") def ursula_federated_test_config(): ursula_config = UrsulaConfiguration(dev_mode=True, rest_port=MOCK_URSULA_STARTING_PORT, is_me=True, start_learning_now=False, abort_on_learning_error=True, federated_only=True, network_middleware=MockRestMiddleware(), save_metadata=False, reload_metadata=False) yield ursula_config ursula_config.cleanup() @pytest.fixture(scope="module") @pytest.mark.usefixtures('three_agents') def ursula_decentralized_test_config(three_agents): ursula_config = UrsulaConfiguration(dev_mode=True, is_me=True, provider_uri="tester://pyevm", rest_port=MOCK_URSULA_STARTING_PORT, start_learning_now=False, abort_on_learning_error=True, federated_only=False, network_middleware=MockRestMiddleware(), import_seed_registry=False, save_metadata=False, reload_metadata=False) yield ursula_config ursula_config.cleanup() @pytest.fixture(scope="module") def alice_federated_test_config(federated_ursulas): config = AliceConfiguration(dev_mode=True, is_me=True, network_middleware=MockRestMiddleware(), known_nodes=federated_ursulas, federated_only=True, abort_on_learning_error=True, save_metadata=False, reload_metadata=False) yield config config.cleanup() @pytest.fixture(scope="module") def alice_blockchain_test_config(blockchain_ursulas, three_agents): token_agent, miner_agent, policy_agent = three_agents etherbase, alice_address, bob_address, *everyone_else = token_agent.blockchain.interface.w3.eth.accounts config = AliceConfiguration(dev_mode=True, is_me=True, provider_uri="tester://pyevm", checksum_public_address=alice_address, network_middleware=MockRestMiddleware(), known_nodes=blockchain_ursulas, abort_on_learning_error=True, import_seed_registry=False, save_metadata=False, reload_metadata=False) yield config config.cleanup() @pytest.fixture(scope="module") def bob_federated_test_config(): config = BobConfiguration(dev_mode=True, network_middleware=MockRestMiddleware(), start_learning_now=False, abort_on_learning_error=True, federated_only=True, save_metadata=False, reload_metadata=False) yield config config.cleanup() @pytest.fixture(scope="module") def bob_blockchain_test_config(blockchain_ursulas, three_agents): token_agent, miner_agent, policy_agent = three_agents etherbase, alice_address, bob_address, *everyone_else = token_agent.blockchain.interface.w3.eth.accounts config = BobConfiguration(dev_mode=True, provider_uri="tester://pyevm", checksum_public_address=bob_address, network_middleware=MockRestMiddleware(), known_nodes=blockchain_ursulas, start_learning_now=False, abort_on_learning_error=True, federated_only=False, import_seed_registry=False, save_metadata=False, reload_metadata=False) yield config config.cleanup() # # Policies # @pytest.fixture(scope="module") def idle_federated_policy(federated_alice, federated_bob): """ Creates a Policy, in a manner typical of how Alice might do it, with a unique label """ m = MOCK_POLICY_DEFAULT_M n = NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK random_label = b'label://' + os.urandom(32) policy = federated_alice.create_policy(federated_bob, label=random_label, m=m, n=n, federated=True) return policy @pytest.fixture(scope="module") def enacted_federated_policy(idle_federated_policy, federated_ursulas): # Alice has a policy in mind and knows of enough qualifies Ursulas; she crafts an offer for them. deposit = NON_PAYMENT contract_end_datetime = maya.now() + datetime.timedelta(days=5) network_middleware = MockRestMiddleware() idle_federated_policy.make_arrangements(network_middleware, deposit=deposit, expiration=contract_end_datetime, handpicked_ursulas=federated_ursulas) responses = idle_federated_policy.enact( network_middleware) # REST call happens here, as does population of TreasureMap. return idle_federated_policy @pytest.fixture(scope="module") def idle_blockchain_policy(blockchain_alice, blockchain_bob): """ Creates a Policy, in a manner typical of how Alice might do it, with a unique label """ random_label = b'label://' + os.urandom(32) policy = blockchain_alice.create_policy(blockchain_bob, label=random_label, m=2, n=3) return policy @pytest.fixture(scope="module") def enacted_blockchain_policy(idle_blockchain_policy, blockchain_ursulas): # Alice has a policy in mind and knows of enough qualifies Ursulas; she crafts an offer for them. deposit = NON_PAYMENT(b"0000000") contract_end_datetime = maya.now() + datetime.timedelta(days=5) network_middleware = MockRestMiddleware() idle_blockchain_policy.make_arrangements(network_middleware, deposit=deposit, expiration=contract_end_datetime, ursulas=list(blockchain_ursulas)) idle_blockchain_policy.enact(network_middleware) # REST call happens here, as does population of TreasureMap. return idle_blockchain_policy @pytest.fixture(scope="module") def capsule_side_channel(enacted_federated_policy): enrico = Enrico(policy_pubkey_enc=enacted_federated_policy.public_key, label=enacted_federated_policy.label) message_kit, _signature = enrico.encrypt_message(b"Welcome to the flippering.") return message_kit, enrico # # Alice, Bob, and Ursula # @pytest.fixture(scope="module") def federated_alice(alice_federated_test_config): _alice = alice_federated_test_config.produce() return _alice @pytest.fixture(scope="module") def blockchain_alice(alice_blockchain_test_config): _alice = alice_blockchain_test_config.produce() return _alice @pytest.fixture(scope="module") def federated_bob(bob_federated_test_config): _bob = bob_federated_test_config.produce() return _bob @pytest.fixture(scope="module") def blockchain_bob(bob_blockchain_test_config): _bob = bob_blockchain_test_config.produce() return _bob @pytest.fixture(scope="module") def federated_ursulas(ursula_federated_test_config): _ursulas = make_federated_ursulas(ursula_config=ursula_federated_test_config, quantity=NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK) yield _ursulas @pytest.fixture(scope="module") def blockchain_ursulas(three_agents, ursula_decentralized_test_config): token_agent, miner_agent, policy_agent = three_agents etherbase, alice, bob, *all_yall = token_agent.blockchain.interface.w3.eth.accounts ursula_addresses = all_yall[:NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK] token_airdrop(origin=etherbase, addresses=ursula_addresses, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) _ursulas = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, ether_addresses=ursula_addresses, stake=True) token_agent.blockchain.time_travel(periods=1) yield _ursulas @pytest.fixture(scope='module') def alice_control(federated_alice, federated_ursulas): teacher_node = list(federated_ursulas)[0] alice_control = federated_alice.make_wsgi_app(teacher_node) alice_control.config['DEBUG'] = True alice_control.config['TESTING'] = True yield alice_control.test_client() @pytest.fixture(scope='module') def bob_control(federated_bob, federated_ursulas): teacher_node = list(federated_ursulas)[0] bob_control = federated_bob.make_wsgi_app(teacher_node) bob_control.config['DEBUG'] = True bob_control.config['TESTING'] = True yield bob_control.test_client() @pytest.fixture(scope='module') def enrico_control(capsule_side_channel): _, data_source = capsule_side_channel message_kit, enrico = capsule_side_channel enrico_control = enrico.make_wsgi_app() enrico_control.config['DEBUG'] = True enrico_control.config['TESTING'] = True yield enrico_control.test_client() @pytest.fixture(scope='module') def enrico_control_from_alice(federated_alice): enrico = Enrico.from_alice(federated_alice, b'test') enrico_control = enrico.make_wsgi_app() enrico_control.config['DEBUG'] = True enrico_control.config['TESTING'] = True yield enrico_control.test_client() # # Blockchain # @pytest.fixture(scope='session') def solidity_compiler(): """Doing this more than once per session will result in slower test run times.""" compiler = SolidityCompiler(test_contract_dir=TEST_CONTRACTS_DIR) yield compiler @pytest.fixture(scope='module') def testerchain(solidity_compiler): """ https: // github.com / ethereum / eth - tester # available-backends """ memory_registry = InMemoryEthereumContractRegistry() # Use the the custom provider and registrar to init an interface deployer_interface = BlockchainDeployerInterface(compiler=solidity_compiler, # freshly recompile if not None registry=memory_registry, provider_uri='tester://pyevm') # Create the blockchain testerchain = TesterBlockchain(interface=deployer_interface, test_accounts=NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK, airdrop=False) origin, *everyone = testerchain.interface.w3.eth.accounts deployer_interface.deployer_address = origin # Set the deployer address from a freshly created test account testerchain.ether_airdrop(amount=1000000000) # TODO: Use test constant yield testerchain testerchain.sever_connection() @pytest.fixture(scope='module') def three_agents(testerchain): """ Musketeers, if you will. Launch the big three contracts on provided chain, make agents for each and return them. """ """Launch all Nucypher ethereum contracts""" origin, *everybody_else = testerchain.interface.w3.eth.accounts token_deployer = NucypherTokenDeployer(blockchain=testerchain, deployer_address=origin) token_deployer.deploy() token_agent = token_deployer.make_agent() # 1: Token miners_escrow_secret = os.urandom(DISPATCHER_SECRET_LENGTH) miner_escrow_deployer = MinerEscrowDeployer( deployer_address=origin, secret_hash=testerchain.interface.w3.keccak(miners_escrow_secret)) miner_escrow_deployer.deploy() miner_agent = miner_escrow_deployer.make_agent() # 2 Miner Escrow policy_manager_secret = os.urandom(DISPATCHER_SECRET_LENGTH) policy_manager_deployer = PolicyManagerDeployer( deployer_address=origin, secret_hash=testerchain.interface.w3.keccak(policy_manager_secret)) policy_manager_deployer.deploy() policy_agent = policy_manager_deployer.make_agent() # 3 Policy Agent return token_agent, miner_agent, policy_agent