nucypher/tests/fixtures.py

308 lines
11 KiB
Python
Raw Normal View History

import contextlib
import os
import tempfile
from os.path import abspath, dirname
2018-06-29 00:23:42 +00:00
import datetime
import maya
import pytest
2018-06-29 00:23:42 +00:00
from constant_sorrow import constants
from eth_tester import EthereumTester
from eth_utils import to_checksum_address
from sqlalchemy.engine import create_engine
2018-06-29 00:23:42 +00:00
from web3 import EthereumTesterProvider
import nucypher
2018-06-29 00:23:42 +00:00
from nucypher.blockchain.eth.chains import TesterBlockchain
from nucypher.blockchain.eth.deployers import PolicyManagerDeployer, NucypherTokenDeployer, MinerEscrowDeployer
from nucypher.blockchain.eth.interfaces import DeployerCircumflex
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
from nucypher.blockchain.eth.utilities import OverridablePyEVMBackend, TemporaryEthereumContractRegistry
2018-05-08 19:35:34 +00:00
from nucypher.characters import Alice, Bob
from nucypher.data_sources import DataSource
from nucypher.keystore import keystore
from nucypher.keystore.db import Base
from nucypher.keystore.keypairs import SigningKeypair
from nucypher.utilities.blockchain import make_ursulas, token_airdrop
from nucypher.utilities.network import MockRestMiddleware
2018-06-29 00:23:42 +00:00
#
# Setup
#
test_contract_dir = os.path.join(BASE_DIR, 'tests', 'blockchain', 'eth', 'contracts', 'contracts')
constants.TEST_CONTRACTS_DIR(test_contract_dir)
2018-06-29 00:23:42 +00:00
constants.NUMBER_OF_TEST_ETH_ACCOUNTS(10)
@pytest.fixture(scope="function")
def tempfile_path():
"""
2018-06-29 00:23:42 +00:00
User is responsible for closing the file given at the path.
"""
fd, path = tempfile.mkstemp()
2018-06-29 00:23:42 +00:00
yield path
os.close(fd)
2018-06-29 00:23:42 +00:00
os.remove(path)
@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
#
# Policies
#
@pytest.fixture(scope="module")
def idle_federated_policy(alice, bob):
"""
Creates a Policy, in a manner typical of how Alice might do it, with a unique uri (soon to be "label" - see #183)
"""
n = int(constants.NUMBER_OF_URSULAS_IN_NETWORK)
random_label = b'label://' + os.urandom(32)
policy = alice.create_policy(bob, label=random_label, m=3, n=n, federated=True)
return policy
@pytest.fixture(scope="module")
2018-06-29 00:23:42 +00:00
def enacted_federated_policy(idle_federated_policy, ursulas):
# Alice has a policy in mind and knows of enough qualifies Ursulas; she crafts an offer for them.
deposit = constants.NON_PAYMENT(b"0000000")
contract_end_datetime = maya.now() + datetime.timedelta(days=5)
network_middleware = MockRestMiddleware()
2018-06-29 00:23:42 +00:00
idle_federated_policy.make_arrangements(network_middleware,
deposit=deposit,
expiration=contract_end_datetime,
handpicked_ursulas=ursulas)
2018-06-29 00:23:42 +00:00
idle_federated_policy.enact(network_middleware) # REST call happens here, as does population of TreasureMap.
2018-06-29 00:23:42 +00:00
return idle_federated_policy
@pytest.fixture(scope="module")
def idle_blockchain_policy(blockchain_alice, bob):
2018-06-29 00:23:42 +00:00
"""
Creates a Policy, in a manner typical of how Alice might do it, with a unique uri (soon to be "label" - see #183)
"""
random_label = b'label://' + os.urandom(32)
policy = blockchain_alice.create_policy(bob, label=random_label, m=2, n=3)
2018-06-29 00:23:42 +00:00
return policy
@pytest.fixture(scope="module")
def enacted_blockchain_policy(idle_blockchain_policy, ursulas):
# Alice has a policy in mind and knows of enough qualifies Ursulas; she crafts an offer for them.
deposit = constants.NON_PAYMENT(b"0000000")
2018-04-07 02:26:13 +00:00
contract_end_datetime = maya.now() + datetime.timedelta(days=5)
2018-06-06 08:32:25 +00:00
network_middleware = MockRestMiddleware()
2018-06-29 00:23:42 +00:00
idle_blockchain_policy.make_arrangements(network_middleware, deposit=deposit, expiration=contract_end_datetime,
ursulas=list(ursulas))
idle_blockchain_policy.enact(network_middleware) # REST call happens here, as does population of TreasureMap.
return idle_blockchain_policy
2018-06-29 00:23:42 +00:00
#
# Alice, Bob, and Capsule
#
@pytest.fixture(scope="module")
def alice(ursulas):
alice = Alice(network_middleware=MockRestMiddleware(),
known_nodes=ursulas,
federated_only=True,
abort_on_learning_error=True)
alice.recruit = lambda *args, **kwargs: [u._ether_address for u in ursulas]
return alice
@pytest.fixture(scope="module")
def blockchain_alice(mining_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
alice = Alice(network_middleware=MockRestMiddleware(),
policy_agent=policy_agent,
known_nodes=mining_ursulas,
abort_on_learning_error=True,
checksum_address=alice_address)
# alice.recruit = lambda *args, **kwargs: [u._ether_address for u in ursulas]
return alice
@pytest.fixture(scope="module")
def bob():
_bob = Bob(network_middleware=MockRestMiddleware(),
always_be_learning=False,
abort_on_learning_error=True,
federated_only=True)
return _bob
2018-06-29 00:23:42 +00:00
@pytest.fixture(scope="module")
def capsule_side_channel(enacted_federated_policy):
signing_keypair = SigningKeypair()
data_source = DataSource(policy_pubkey_enc=enacted_federated_policy.public_key,
signing_keypair=signing_keypair)
message_kit, _signature = data_source.encapsulate_single_message(b"Welcome to the flippering.")
return message_kit, data_source
#
# Ursulas
#
@pytest.fixture(scope="module")
def ursulas(three_agents):
token_agent, miner_agent, policy_agent = three_agents
ether_addresses = [to_checksum_address(os.urandom(20)) for _ in range(constants.NUMBER_OF_URSULAS_IN_NETWORK)]
_ursulas = make_ursulas(ether_addresses=ether_addresses,
miner_agent=miner_agent,
ursula_starting_port=int(constants.URSULA_PORT_SEED))
try:
yield _ursulas
finally:
# Remove the DBs that have been sprayed hither and yon.
with contextlib.suppress(FileNotFoundError):
for port, ursula in enumerate(_ursulas, start=int(constants.URSULA_PORT_SEED)):
os.remove("test-{}".format(port))
@pytest.fixture(scope="module")
def mining_ursulas(three_agents):
starting_point = constants.URSULA_PORT_SEED + 500
token_agent, miner_agent, policy_agent = three_agents
etherbase, alice, bob, *all_yall = token_agent.blockchain.interface.w3.eth.accounts
_receipts = token_airdrop(token_agent=token_agent, origin=etherbase, addresses=all_yall,
amount=1000000 * constants.M)
ursula_addresses = all_yall[:int(constants.NUMBER_OF_URSULAS_IN_NETWORK)]
2018-07-21 05:05:29 +00:00
_ursulas = make_ursulas(ursula_starting_port=starting_point,
ether_addresses=ursula_addresses,
miner_agent=miner_agent,
miners=True,
ursula_starting_port=starting_point)
try:
yield _ursulas
finally:
# Remove the DBs that have been sprayed hither and yon.
with contextlib.suppress(FileNotFoundError):
for port, ursula in enumerate(_ursulas, start=int(starting_point)):
os.remove("test-{}".format(port))
@pytest.fixture(scope="module")
2018-06-29 00:23:42 +00:00
def non_ursula_miners(three_agents):
token_agent, miner_agent, policy_agent = three_agents
etherbase, alice, bob, *all_yall = token_agent.blockchain.interface.w3.eth.accounts
2018-06-29 00:23:42 +00:00
ursula_addresses = all_yall[:int(constants.NUMBER_OF_URSULAS_IN_NETWORK)]
2018-07-19 18:49:41 +00:00
_receipts = token_airdrop(token_agent=token_agent,
origin=etherbase,
addresses=all_yall,
amount=1000000*constants.M)
2018-06-29 00:23:42 +00:00
starting_point = constants.URSULA_PORT_SEED + 500
2018-06-29 00:23:42 +00:00
_ursulas = make_ursulas(ether_addresses=ursula_addresses,
miner_agent=miner_agent,
miners=True,
bare=True,
ursula_starting_port=starting_point)
2018-06-29 00:23:42 +00:00
try:
yield _ursulas
finally:
# Remove the DBs that have been sprayed hither and yon.
with contextlib.suppress(FileNotFoundError):
for port, ursula in enumerate(_ursulas, start=int(starting_point)):
os.remove("test-{}".format(port))
#
# 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=str(constants.TEST_CONTRACTS_DIR))
2018-06-29 00:23:42 +00:00
yield compiler
@pytest.fixture(scope='module')
def testerchain(solidity_compiler):
2018-04-13 00:24:55 +00:00
"""
2018-06-29 00:23:42 +00:00
https: // github.com / ethereum / eth - tester # available-backends
2018-04-13 00:24:55 +00:00
"""
2018-06-29 00:23:42 +00:00
temp_registrar = TemporaryEthereumContractRegistry()
# Configure a custom provider
overrides = {'gas_limit': 4626271}
pyevm_backend = OverridablePyEVMBackend(genesis_overrides=overrides)
eth_tester = EthereumTester(backend=pyevm_backend, auto_mine_transactions=True)
pyevm_provider = EthereumTesterProvider(ethereum_tester=eth_tester)
2018-07-19 18:49:41 +00:00
test_providers = (pyevm_provider, )
2018-06-29 00:23:42 +00:00
# Use the the custom provider and registrar to init an interface
2018-07-19 18:49:41 +00:00
circumflex = DeployerCircumflex(compiler=solidity_compiler, # freshly recompile if not None
registry=temp_registrar,
providers=test_providers)
2018-06-29 00:23:42 +00:00
# Create the blockchain
testerchain = TesterBlockchain(interface=circumflex, test_accounts=10)
origin, *everyone = testerchain.interface.w3.eth.accounts
circumflex.deployer_address = origin # Set the deployer address from a freshly created test account
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.arm()
token_deployer.deploy()
token_agent = token_deployer.make_agent()
miner_escrow_deployer = MinerEscrowDeployer(token_agent=token_agent, deployer_address=origin)
miner_escrow_deployer.arm()
miner_escrow_deployer.deploy()
miner_agent = miner_escrow_deployer.make_agent()
policy_manager_deployer = PolicyManagerDeployer(miner_agent=miner_agent, deployer_address=origin)
policy_manager_deployer.arm()
policy_manager_deployer.deploy()
policy_agent = policy_manager_deployer.make_agent()
return token_agent, miner_agent, policy_agent