mirror of https://github.com/nucypher/nucypher.git
Nucypher and BlockchainConfig and it's tenticles; Related NucypherConstants and ContractInterface updates.
parent
ea6ceba6c4
commit
722cf9918f
|
@ -118,12 +118,12 @@ class ContractDeployer:
|
|||
raise self.ContractDeploymentError('{} deployer is already armed.'.format(self._contract_name))
|
||||
|
||||
# If the blockchain network is public, prompt the user
|
||||
if self.blockchain._network not in self.blockchain.test_chains:
|
||||
if self.blockchain.config.network not in self.blockchain.test_chains:
|
||||
message = """
|
||||
Are you sure you want to deploy {contract} on the {network} network?
|
||||
|
||||
Type {word} to arm the deployer.
|
||||
""".format(contract=self._contract_name, network=self.blockchain._network, word=self._arming_word)
|
||||
""".format(contract=self._contract_name, network=self.blockchain.config.network, word=self._arming_word)
|
||||
|
||||
answer = input(message)
|
||||
if answer == self._arming_word:
|
||||
|
|
|
@ -40,7 +40,7 @@ class Character(object):
|
|||
|
||||
def __init__(self, attach_server=True, crypto_power: CryptoPower=None,
|
||||
crypto_power_ups=None, is_me=True, network_middleware=None,
|
||||
config: "NucypherConfig"=None) -> None:
|
||||
config: "NucypherConfig"=None, *args, **kwargs):
|
||||
"""
|
||||
:param attach_server: Whether to attach a Server when this Character is
|
||||
born.
|
||||
|
@ -62,7 +62,7 @@ class Character(object):
|
|||
Character, but there are scenarios in which its imaginable to be
|
||||
represented by zero Characters or by more than one Character.
|
||||
"""
|
||||
# self.config = config if config is not None else NucypherConfig.get_config()
|
||||
self.config = config if config is not None else NucypherConfig.get() # default
|
||||
self.known_nodes = {}
|
||||
self.log = getLogger("characters")
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import json
|
||||
import os
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
import maya
|
||||
from web3 import IPCProvider
|
||||
from web3.middleware import geth_poa_middleware
|
||||
|
||||
from nucypher.blockchain.eth.chains import Blockchain, TesterBlockchain
|
||||
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
|
||||
|
||||
_DEFAULT_CONFIGURATION_DIR = os.path.join(str(Path.home()), '.nucypher')
|
||||
|
||||
|
@ -11,32 +16,6 @@ class NucypherConfigurationError(RuntimeError):
|
|||
pass
|
||||
|
||||
|
||||
class StakeConfig:
|
||||
# __minimum_stake_amount = 0 # TODO
|
||||
# __minimum_stake_duration = 0
|
||||
|
||||
def __init__(self, amount: int, periods: int, start_datetime):
|
||||
|
||||
assert StakeConfig.validate_stake(amount, periods, start_datetime)
|
||||
self.amount = amount
|
||||
self.start = start_datetime
|
||||
self.periods = periods
|
||||
|
||||
@classmethod
|
||||
def validate_stake(cls, amount: int, periods: int, start_datetime) -> bool:
|
||||
rules = (
|
||||
# (amount > cls.__minimum_stake_amount, 'Staking aount must be at least {min_amount}'), # TODO
|
||||
(start_datetime < maya.now(), 'Start date/time must not be in the past.'),
|
||||
# (periods > cls.__minimum_stake_duration, 'Staking duration must be at least {}'.format(cls.__minimum_stake_duration))
|
||||
)
|
||||
|
||||
for rule, failure_message in rules:
|
||||
if rule is False:
|
||||
raise NucypherConfigurationError(failure_message)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class PolicyConfig:
|
||||
__default_m = 6 # TODO!!!
|
||||
__default_n = 10
|
||||
|
@ -64,34 +43,113 @@ class NetworkConfig:
|
|||
return self.__db_path
|
||||
|
||||
|
||||
class BlockchainConfig:
|
||||
|
||||
__default_providers = (IPCProvider(ipc_path=os.path.join('/tmp/geth.ipc')),
|
||||
# user-managed geth over IPC assumed
|
||||
)
|
||||
|
||||
__default_network = 'tester'
|
||||
__default_timeout = 120 # seconds
|
||||
__configured_providers = list() # tracks active providers
|
||||
|
||||
def __init__(self, network: str=None, timeout: int=None,
|
||||
compiler=None, registrar=None, deploy=False,
|
||||
geth=True, tester=False):
|
||||
|
||||
# Parse configuration
|
||||
|
||||
if len(self.__configured_providers) == 0:
|
||||
warnings.warn("No blockchain provider backends are configured, using default.", RuntimeWarning)
|
||||
self.__providers = BlockchainConfig.__default_providers
|
||||
|
||||
self._providers = self.__configured_providers
|
||||
self.__network = network if network is not None else self.__default_network
|
||||
self.__timeout = timeout if timeout is not None else self.__default_timeout
|
||||
|
||||
if deploy is False:
|
||||
from nucypher.blockchain.eth.interfaces import ContractInterface
|
||||
interface_class = ContractInterface
|
||||
else:
|
||||
from nucypher.blockchain.eth.interfaces import DeployerInterface
|
||||
interface_class = DeployerInterface
|
||||
|
||||
interface = interface_class(blockchain_config=self, sol_compiler=compiler, registrar=registrar)
|
||||
|
||||
if geth is True:
|
||||
w3 = interface.w3
|
||||
w3.middleware_stack.inject(geth_poa_middleware, layer=0)
|
||||
|
||||
if tester is True:
|
||||
blockchain_class = TesterBlockchain
|
||||
else:
|
||||
blockchain_class = Blockchain
|
||||
|
||||
# Initial connection to blockchain via provider
|
||||
self.chain = blockchain_class(interface=interface)
|
||||
|
||||
@classmethod
|
||||
def add_provider(cls, provider):
|
||||
cls.__configured_providers.append(provider)
|
||||
|
||||
@property
|
||||
def providers(self) -> list:
|
||||
return self._providers
|
||||
|
||||
@property
|
||||
def network(self):
|
||||
return self.__network
|
||||
|
||||
@property
|
||||
def timeout(self):
|
||||
return self.__timeout
|
||||
|
||||
|
||||
class NucypherConfig:
|
||||
|
||||
__instance = None
|
||||
__default_configuration_root = _DEFAULT_CONFIGURATION_DIR
|
||||
__default_json_config_filepath = os.path.join(__default_configuration_root, 'conf.json')
|
||||
|
||||
def __init__(self,
|
||||
keyring,
|
||||
keyring=None,
|
||||
blockchain_config: BlockchainConfig=None,
|
||||
network_config: NetworkConfig=None,
|
||||
policy_config: PolicyConfig=None,
|
||||
stake_config: StakeConfig=None,
|
||||
configuration_root: str=None,
|
||||
json_config_filepath: str=None):
|
||||
|
||||
# Check for custom paths
|
||||
self.__configuration_root = configuration_root or self.__default_configuration_root
|
||||
self.__json_config_filepath = json_config_filepath or self.__json_config_filepath
|
||||
self.__json_config_filepath = json_config_filepath or self.__default_json_config_filepath
|
||||
|
||||
# Subconfigurations
|
||||
self.keyring = keyring # Everyone
|
||||
self.stake = stake_config # Ursula
|
||||
self.policy = policy_config # Alice / Ursula
|
||||
self.network = network_config # Ursula
|
||||
if blockchain_config is None:
|
||||
blockchain_config = BlockchainConfig()
|
||||
|
||||
# Sub-configurations
|
||||
self.keyring = keyring # Everyone
|
||||
self.blockchain = blockchain_config # Everyone
|
||||
self.policy = policy_config # Alice / Ursula
|
||||
self.network = network_config # Ursula
|
||||
|
||||
if self.__instance is not None:
|
||||
raise RuntimeError('Configuration not started')
|
||||
else:
|
||||
self.__instance = self
|
||||
|
||||
@classmethod
|
||||
def from_json_config(cls, path: str=None):
|
||||
def get(cls):
|
||||
return cls.__instance
|
||||
|
||||
@classmethod
|
||||
def reset(cls) -> None:
|
||||
cls.__instance = None
|
||||
|
||||
def __read(cls, path: str=None):
|
||||
"""TODO: Reads the config file and creates a NuCypherConfig instance"""
|
||||
with open(cls.__default_json_config_filepath, 'r') as config_file:
|
||||
data = json.loads(config_file.read())
|
||||
|
||||
def to_json_config(self, path: str=None):
|
||||
def __write(self, path: str=None):
|
||||
"""TODO: Serializes a configuration and saves it to the local filesystem."""
|
||||
path = path or self.__default_json_config_filepath
|
||||
|
|
|
@ -9,14 +9,14 @@ def test_dispatcher(web3, chain):
|
|||
account = web3.eth.accounts[1]
|
||||
|
||||
# Load contract interface
|
||||
contract_interface = chain.provider.get_contract_factory('ContractInterface')
|
||||
contract_interface = chain.interface.get_contract_factory('ContractInterface')
|
||||
|
||||
# Deploy contracts and dispatcher for them
|
||||
contract1_lib, _ = chain.provider.deploy_contract('ContractV1', 1)
|
||||
contract2_lib, _ = chain.provider.deploy_contract('ContractV2', 1)
|
||||
contract3_lib, _ = chain.provider.deploy_contract('ContractV3', 2)
|
||||
contract2_bad_lib, _ = chain.provider.deploy_contract('ContractV2Bad')
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract1_lib.address)
|
||||
contract1_lib, _ = chain.interface.deploy_contract('ContractV1', 1)
|
||||
contract2_lib, _ = chain.interface.deploy_contract('ContractV2', 1)
|
||||
contract3_lib, _ = chain.interface.deploy_contract('ContractV3', 2)
|
||||
contract2_bad_lib, _ = chain.interface.deploy_contract('ContractV2Bad')
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract1_lib.address)
|
||||
|
||||
upgrades = dispatcher.events.Upgraded.createFilter(fromBlock=0)
|
||||
assert dispatcher.functions.target().call() == contract1_lib.address
|
||||
|
|
|
@ -8,11 +8,11 @@ from eth_tester.backends.pyevm.main import get_default_genesis_params, get_defau
|
|||
from web3 import Web3
|
||||
|
||||
from nucypher.blockchain.eth.agents import MinerAgent, NucypherTokenAgent
|
||||
from nucypher.blockchain.eth.constants import NucypherMinerConfig
|
||||
from nucypher.blockchain.eth.constants import NucypherMinerConstants
|
||||
from nucypher.blockchain.eth.deployers import MinerEscrowDeployer, NucypherTokenDeployer
|
||||
|
||||
|
||||
class MockNucypherMinerConfig(NucypherMinerConfig):
|
||||
class MockNucypherMinerConstants(NucypherMinerConstants):
|
||||
"""Speed things up a bit"""
|
||||
# _hours_per_period = 24 # Hours
|
||||
# min_locked_periods = 1 # Minimum locked periods
|
||||
|
@ -38,7 +38,7 @@ class MockTokenAgent(NucypherTokenAgent):
|
|||
return receipts
|
||||
|
||||
|
||||
class MockMinerAgent(MinerAgent, MockNucypherMinerConfig):
|
||||
class MockMinerAgent(MinerAgent, MockNucypherMinerConstants):
|
||||
"""MinerAgent with faked config subclass"""
|
||||
|
||||
def spawn_random_miners(self, addresses: list) -> list:
|
||||
|
@ -71,7 +71,7 @@ class MockNucypherTokenDeployer(NucypherTokenDeployer):
|
|||
agency = MockTokenAgent
|
||||
|
||||
|
||||
class MockMinerEscrowDeployer(MinerEscrowDeployer, MockNucypherMinerConfig):
|
||||
class MockMinerEscrowDeployer(MinerEscrowDeployer, MockNucypherMinerConstants):
|
||||
"""Helper class for MockMinerAgent, using a mock miner config"""
|
||||
agency = MockMinerAgent
|
||||
|
||||
|
|
|
@ -57,10 +57,10 @@ def test_anybody_can_verify():
|
|||
"""
|
||||
|
||||
# Alice can sign by default, by dint of her _default_crypto_powerups.
|
||||
alice = Alice()
|
||||
alice = Alice(config=nucypher_test_config, policy_agent=mock_policy_agent)
|
||||
|
||||
# So, our story is fairly simple: an everyman meets Alice.
|
||||
somebody = Character()
|
||||
somebody = Character(config=nucypher_test_config)
|
||||
|
||||
# Alice signs a message.
|
||||
message = b"A message for all my friends who can only verify and not sign."
|
||||
|
|
|
@ -2,8 +2,8 @@ from nucypher.characters import Ursula
|
|||
from nucypher.crypto.powers import SigningPower
|
||||
|
||||
|
||||
def test_ursula_generates_self_signed_cert():
|
||||
ursula = Ursula(attach_server=False)
|
||||
def test_ursula_generates_self_signed_cert(nucypher_test_config):
|
||||
ursula = Ursula(attach_server=False, config=nucypher_test_config)
|
||||
cert, cert_private_key = ursula.generate_self_signed_certificate()
|
||||
public_key_numbers = ursula.public_key(SigningPower).to_cryptography_pubkey().public_numbers()
|
||||
assert cert.public_key().public_numbers() == public_key_numbers
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
import os
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
from os.path import abspath, dirname
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import time
|
||||
from eth_tester import EthereumTester, PyEVMBackend
|
||||
from eth_tester import EthereumTester
|
||||
from geth import LoggingMixin, DevGethProcess
|
||||
from web3 import EthereumTesterProvider, IPCProvider, Web3
|
||||
from web3.middleware import geth_poa_middleware
|
||||
from os.path import abspath, dirname
|
||||
from web3 import EthereumTesterProvider, IPCProvider
|
||||
|
||||
from nucypher.blockchain.eth.chains import TheBlockchain, TesterBlockchain
|
||||
from nucypher.blockchain.eth.deployers import PolicyManagerDeployer
|
||||
from nucypher.blockchain.eth.interfaces import Registrar, DeployerInterface
|
||||
from nucypher.blockchain.eth.interfaces import Registrar
|
||||
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
|
||||
from nucypher.config.configs import BlockchainConfig
|
||||
from tests.blockchain.eth import contracts, utilities
|
||||
from tests.blockchain.eth.utilities import MockMinerEscrowDeployer, TesterPyEVMBackend, MockNucypherTokenDeployer
|
||||
|
||||
|
@ -98,12 +97,14 @@ def auto_geth_ipc_provider():
|
|||
@pytest.fixture(scope='module')
|
||||
def pyevm_provider():
|
||||
"""
|
||||
Provider backend
|
||||
Test provider backend
|
||||
https: // github.com / ethereum / eth - tester # available-backends
|
||||
"""
|
||||
overrides = {'gas_limit': 4626271}
|
||||
pyevm_backend = TesterPyEVMBackend(genesis_overrides=overrides)
|
||||
|
||||
# pyevm_backend = PyEVMBackend()
|
||||
|
||||
eth_tester = EthereumTester(backend=pyevm_backend, auto_mine_transactions=True)
|
||||
pyevm_provider = EthereumTesterProvider(ethereum_tester=eth_tester)
|
||||
|
||||
|
@ -123,46 +124,50 @@ def solidity_compiler():
|
|||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def web3(pyevm_provider):
|
||||
def registrar():
|
||||
_, filepath = tempfile.mkstemp()
|
||||
test_registrar = Registrar(chain_name='tester', registrar_filepath=filepath)
|
||||
yield test_registrar
|
||||
os.remove(filepath)
|
||||
|
||||
w3 = Web3(providers=pyevm_provider)
|
||||
w3.middleware_stack.inject(geth_poa_middleware, layer=0)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def blockchain_config(pyevm_provider, solidity_compiler, registrar):
|
||||
BlockchainConfig.add_provider(pyevm_provider)
|
||||
config = BlockchainConfig(compiler=solidity_compiler, registrar=registrar, deploy=True, tester=True) # TODO: pass in address
|
||||
yield config
|
||||
config.chain.sever()
|
||||
del config
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def deployer_interface(blockchain_config):
|
||||
interface = blockchain_config.chain.interface
|
||||
w3 = interface.w3
|
||||
|
||||
if len(w3.eth.accounts) == 1:
|
||||
utilities.generate_accounts(w3=w3, quantity=9)
|
||||
assert len(w3.eth.accounts) == 10
|
||||
|
||||
yield w3
|
||||
yield interface
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def contract_provider(web3, registrar, solidity_compiler):
|
||||
tester_provider = ContractProvider(provider_backend=web3, registrar=registrar, sol_compiler=solidity_compiler)
|
||||
yield tester_provider
|
||||
def web3(deployer_interface):
|
||||
"""Compadibility fixture"""
|
||||
return deployer_interface.w3
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def registrar():
|
||||
_, filepath = tempfile.mkstemp()
|
||||
registrar = Registrar(chain_name='tester', registrar_filepath=filepath)
|
||||
yield registrar
|
||||
os.remove(filepath)
|
||||
def chain(deployer_interface, airdrop_ether=False):
|
||||
chain = deployer_interface.blockchain_config.chain
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def chain(contract_provider, airdrop=False):
|
||||
chain = TesterBlockchain(contract_provider=contract_provider)
|
||||
|
||||
if airdrop:
|
||||
if airdrop_ether:
|
||||
one_million_ether = 10 ** 6 * 10 ** 18 # wei -> ether
|
||||
chain._global_airdrop(amount=one_million_ether)
|
||||
chain.ether_airdrop(amount=one_million_ether)
|
||||
|
||||
yield chain
|
||||
|
||||
del chain
|
||||
TheBlockchain._TheBlockchain__instance = None
|
||||
|
||||
|
||||
#
|
||||
# Deployers #
|
||||
#
|
||||
|
|
|
@ -7,10 +7,9 @@ import pytest
|
|||
from constant_sorrow import constants
|
||||
from sqlalchemy.engine import create_engine
|
||||
|
||||
from nucypher.blockchain.eth.chains import Blockchain
|
||||
from nucypher.characters import Alice, Bob
|
||||
from nucypher.keystore import keystore
|
||||
from nucypher.keystore.db import Base
|
||||
|
||||
from nucypher.config.configs import NucypherConfig
|
||||
from nucypher.crypto.signature import SignatureStamp
|
||||
from nucypher.data_sources import DataSource
|
||||
from nucypher.keystore import keystore
|
||||
|
@ -21,6 +20,17 @@ from tests.utilities import NUMBER_OF_URSULAS_IN_NETWORK, MockNetworkyStuff, mak
|
|||
URSULA_PORT, EVENT_LOOP
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def nucypher_test_config(blockchain_config):
|
||||
|
||||
config = NucypherConfig(keyring="this is the most secure password in the world.",
|
||||
blockchain_config=blockchain_config)
|
||||
yield config
|
||||
NucypherConfig.reset()
|
||||
Blockchain.sever()
|
||||
del config
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def idle_policy(alice, bob):
|
||||
"""
|
||||
|
@ -53,8 +63,8 @@ def enacted_policy(idle_policy, ursulas):
|
|||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def alice(ursulas):
|
||||
ALICE = Alice(network_middleware=MockNetworkyStuff(ursulas))
|
||||
def alice(ursulas, mock_policy_agent, nucypher_test_config):
|
||||
ALICE = Alice(network_middleware=MockNetworkyStuff(ursulas), policy_agent=mock_policy_agent, config=nucypher_test_config)
|
||||
ALICE.server.listen(8471)
|
||||
ALICE.__resource_id = b"some_resource_id"
|
||||
EVENT_LOOP.run_until_complete(ALICE.server.bootstrap([("127.0.0.1", u.dht_port) for u in ursulas]))
|
||||
|
@ -69,8 +79,8 @@ def bob(ursulas):
|
|||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ursulas():
|
||||
URSULAS = make_ursulas(NUMBER_OF_URSULAS_IN_NETWORK, URSULA_PORT)
|
||||
def ursulas(nucypher_test_config):
|
||||
URSULAS = make_ursulas(NUMBER_OF_URSULAS_IN_NETWORK, URSULA_PORT, config=nucypher_test_config)
|
||||
yield URSULAS
|
||||
# Remove the DBs that have been sprayed hither and yon.
|
||||
for _u in range(NUMBER_OF_URSULAS_IN_NETWORK):
|
||||
|
|
|
@ -3,6 +3,7 @@ import asyncio
|
|||
from apistar.test import TestClient
|
||||
|
||||
from nucypher.characters import Ursula
|
||||
from nucypher.config.configs import NucypherConfig
|
||||
from nucypher.network.node import NetworkyStuff
|
||||
from nucypher.policy.models import ArrangementResponse
|
||||
|
||||
|
@ -15,7 +16,7 @@ URSULA_PORT = 7468
|
|||
NUMBER_OF_URSULAS_IN_NETWORK = 6
|
||||
|
||||
|
||||
def make_ursulas(how_many_ursulas: int, ursula_starting_port: int) -> list:
|
||||
def make_ursulas(how_many_ursulas: int, ursula_starting_port: int, config: NucypherConfig) -> list:
|
||||
"""
|
||||
:param how_many_ursulas: How many Ursulas to create.
|
||||
:param ursula_starting_port: The port of the first created Ursula; subsequent Ursulas will increment the port number by 1.
|
||||
|
@ -26,7 +27,7 @@ def make_ursulas(how_many_ursulas: int, ursula_starting_port: int) -> list:
|
|||
URSULAS = []
|
||||
for _u in range(how_many_ursulas):
|
||||
port = ursula_starting_port + _u
|
||||
_URSULA = Ursula(dht_port=port, ip_address="127.0.0.1", db_name="test-{}".format(port), rest_port=port+100) # TODO: Make ports unstupid and more clear.
|
||||
_URSULA = Ursula(dht_port=port, ip_address="127.0.0.1", db_name="test-{}".format(port), rest_port=port+100, config=config) # TODO: Make ports unstupid and more clear.
|
||||
|
||||
class MockDatastoreThreadPool(object):
|
||||
def callInThread(self, f, *args, **kwargs):
|
||||
|
|
Loading…
Reference in New Issue