mirror of https://github.com/nucypher/nucypher.git
Merge pull request #276 from KPrasch/actor-integration
Character + TokenActor integration and configurationpull/284/head
commit
a97f720b24
|
@ -3,6 +3,7 @@ cache: pip
|
|||
python:
|
||||
- '3.5'
|
||||
- '3.6'
|
||||
- '3.7-dev'
|
||||
install:
|
||||
- pip install pipenv --upgrade
|
||||
- pipenv install --dev --three --skip-lock
|
||||
|
@ -11,4 +12,7 @@ before_script:
|
|||
- chmod +x "${VIRTUAL_ENV}/bin/solc"
|
||||
script:
|
||||
- pipenv run -- pytest --runslow --cov=nucypher -v tests
|
||||
- codecov
|
||||
- codecov
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: '3.7-dev'
|
|
@ -1,17 +1,19 @@
|
|||
from abc import ABC
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from typing import Tuple, List, Union
|
||||
|
||||
from nucypher.blockchain.eth.agents import NucypherTokenAgent
|
||||
from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent, PolicyAgent
|
||||
|
||||
|
||||
class TokenActor(ABC):
|
||||
class NucypherTokenActor:
|
||||
|
||||
class ActorError(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, token_agent: NucypherTokenAgent, address: Union[bytes, str]):
|
||||
def __init__(self, address: Union[str, bytes], token_agent: NucypherTokenAgent=None, *args, **kwargs):
|
||||
|
||||
if token_agent is None:
|
||||
token_agent = NucypherTokenAgent()
|
||||
self.token_agent = token_agent
|
||||
|
||||
if isinstance(address, bytes):
|
||||
|
@ -28,32 +30,27 @@ class TokenActor(ABC):
|
|||
|
||||
def eth_balance(self):
|
||||
"""Return this actors's current ETH balance"""
|
||||
|
||||
balance = self.token_agent.blockchain._chain.web3.eth.getBalance(self.address)
|
||||
balance = self.token_agent.blockchain.interface.w3.eth.getBalance(self.address)
|
||||
return balance
|
||||
|
||||
def token_balance(self):
|
||||
"""Return this actors's current token balance"""
|
||||
|
||||
balance = self.token_agent.get_balance(address=self.address)
|
||||
return balance
|
||||
|
||||
|
||||
class Miner(TokenActor):
|
||||
class Miner(NucypherTokenActor):
|
||||
"""
|
||||
Ursula - practically carrying a pickaxe.
|
||||
|
||||
Accepts a running blockchain, deployed token contract, and deployed escrow contract.
|
||||
If the provided token and escrow contracts are not deployed,
|
||||
ContractDeploymentError will be raised.
|
||||
|
||||
"""
|
||||
|
||||
class StakingError(TokenActor.ActorError):
|
||||
class StakingError(NucypherTokenActor.ActorError):
|
||||
pass
|
||||
|
||||
def __init__(self, miner_agent, address):
|
||||
super().__init__(token_agent=miner_agent.token_agent, address=address)
|
||||
def __init__(self, miner_agent: MinerAgent=None, *args, **kwargs):
|
||||
if miner_agent is None:
|
||||
miner_agent = MinerAgent(token_agent=NucypherTokenAgent())
|
||||
super().__init__(token_agent=miner_agent.token_agent, *args, **kwargs)
|
||||
|
||||
self.miner_agent = miner_agent
|
||||
miner_agent.miners.append(self) # Track Miners
|
||||
|
@ -186,7 +183,7 @@ class Miner(TokenActor):
|
|||
if entire_balance is True:
|
||||
amount = self.miner_agent.contract.functions.getMinerInfo(self.miner_agent.MinerInfo.VALUE.value,
|
||||
self.address, 0).call()
|
||||
amount = self.blockchain.provider.w3.toInt(amount)
|
||||
amount = self.blockchain.interface.w3.toInt(amount)
|
||||
|
||||
assert self.__validate_stake(amount=amount, lock_periods=lock_periods)
|
||||
|
||||
|
@ -210,7 +207,7 @@ class Miner(TokenActor):
|
|||
|
||||
count_bytes = self.miner_agent.contract.functions.getMinerIdsLength(self.address).call()
|
||||
|
||||
count = self.blockchain.provider.w3.toInt(count_bytes)
|
||||
count = self.blockchain.interface.w3.toInt(count_bytes)
|
||||
|
||||
miner_ids = list()
|
||||
for index in range(count):
|
||||
|
@ -219,12 +216,19 @@ class Miner(TokenActor):
|
|||
return tuple(miner_ids)
|
||||
|
||||
|
||||
class PolicyAuthor(TokenActor):
|
||||
class PolicyAuthor(NucypherTokenActor):
|
||||
"""Alice"""
|
||||
|
||||
def __init__(self, address: bytes, policy_agent):
|
||||
super().__init__(token_agent=policy_agent._token, address=address)
|
||||
def __init__(self, policy_agent: PolicyAgent=None, *args, **kwargs):
|
||||
|
||||
if policy_agent is None:
|
||||
# all defaults
|
||||
token_agent = NucypherTokenAgent()
|
||||
miner_agent = MinerAgent(token_agent=token_agent)
|
||||
policy_agent = PolicyAgent(miner_agent=miner_agent)
|
||||
|
||||
self.policy_agent = policy_agent
|
||||
super().__init__(token_agent=self.policy_agent.token_agent, *args, **kwargs)
|
||||
|
||||
self._arrangements = OrderedDict() # Track authored policies by id
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import random
|
||||
from abc import ABC
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from typing import Set, Generator, List
|
||||
|
||||
from nucypher.blockchain.eth import constants
|
||||
from nucypher.blockchain.eth.constants import NucypherTokenConfig, NucypherMinerConfig
|
||||
from web3.contract import Contract
|
||||
|
||||
from nucypher.blockchain.eth import constants
|
||||
from nucypher.blockchain.eth.chains import Blockchain
|
||||
from nucypher.blockchain.eth.constants import NucypherTokenConstants, NucypherMinerConstants
|
||||
|
||||
|
||||
class EthereumContractAgent(ABC):
|
||||
"""
|
||||
|
@ -20,14 +21,19 @@ class EthereumContractAgent(ABC):
|
|||
class ContractNotDeployed(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, blockchain, contract: Contract=None, *args, **kwargs):
|
||||
def __init__(self, blockchain: Blockchain=None, contract: Contract=None, *args, **kwargs):
|
||||
|
||||
if blockchain is None:
|
||||
blockchain = Blockchain.connect()
|
||||
self.blockchain = blockchain
|
||||
|
||||
if contract is None:
|
||||
address = blockchain.provider.get_contract_address(contract_name=self._principal_contract_name)[-1] # TODO
|
||||
contract = blockchain.provider.get_contract(address)
|
||||
address = blockchain.interface.get_contract_address(contract_name=self._principal_contract_name)[-1] # TODO: Handle multiple
|
||||
contract = blockchain.interface.get_contract(address)
|
||||
self.__contract = contract
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
class_name = self.__class__.__name__
|
||||
r = "{}(blockchain={}, contract={})"
|
||||
|
@ -50,7 +56,7 @@ class EthereumContractAgent(ABC):
|
|||
|
||||
@property
|
||||
def origin(self) -> str:
|
||||
return self.blockchain.provider.w3.eth.coinbase # TODO: make swappable
|
||||
return self.blockchain.interface.w3.eth.coinbase # TODO: make swappable
|
||||
|
||||
def get_balance(self, address: str=None) -> int:
|
||||
"""Get the balance of a token address, or of this contract address"""
|
||||
|
@ -59,11 +65,11 @@ class EthereumContractAgent(ABC):
|
|||
return self.contract.functions.balanceOf(address).call()
|
||||
|
||||
|
||||
class NucypherTokenAgent(EthereumContractAgent, NucypherTokenConfig):
|
||||
class NucypherTokenAgent(EthereumContractAgent, NucypherTokenConstants):
|
||||
_principal_contract_name = "NuCypherToken"
|
||||
|
||||
|
||||
class MinerAgent(EthereumContractAgent, NucypherMinerConfig):
|
||||
class MinerAgent(EthereumContractAgent, NucypherMinerConstants):
|
||||
"""
|
||||
Wraps NuCypher's Escrow solidity smart contract
|
||||
|
||||
|
@ -106,7 +112,7 @@ class MinerAgent(EthereumContractAgent, NucypherMinerConfig):
|
|||
count = self.contract.functions.getMinersLength().call()
|
||||
for index in range(count):
|
||||
addr = self.contract.functions.miners(index).call()
|
||||
yield self.blockchain.provider.w3.toChecksumAddress(addr)
|
||||
yield self.blockchain.interface.w3.toChecksumAddress(addr)
|
||||
|
||||
def sample(self, quantity: int=10, additional_ursulas: float=1.7, attempts: int=5, duration: int=10) -> List[str]:
|
||||
"""
|
||||
|
@ -157,6 +163,11 @@ class PolicyAgent(EthereumContractAgent):
|
|||
|
||||
_principal_contract_name = "PolicyManager"
|
||||
|
||||
def __init__(self, miner_agent: MinerAgent, *args, **kwargs):
|
||||
super().__init__(blockchain=miner_agent.blockchain, *args, **kwargs)
|
||||
self.miner_agent = miner_agent
|
||||
self.token_agent = miner_agent.token_agent
|
||||
|
||||
def fetch_arrangement_data(self, arrangement_id: bytes) -> list:
|
||||
blockchain_record = self.contract.functions.policies(arrangement_id).call()
|
||||
return blockchain_record
|
||||
|
|
|
@ -1,88 +1,74 @@
|
|||
import random
|
||||
from abc import ABC
|
||||
from typing import List
|
||||
from typing import List, Union
|
||||
|
||||
from nucypher.blockchain.eth.constants import NucypherMinerConfig
|
||||
from nucypher.blockchain.eth.interfaces import ContractProvider
|
||||
from nucypher.blockchain.eth.constants import NucypherMinerConstants
|
||||
from nucypher.blockchain.eth.interfaces import ContractInterface, DeployerInterface
|
||||
|
||||
|
||||
class TheBlockchain(ABC):
|
||||
"""
|
||||
http://populus.readthedocs.io/en/latest/config.html#chains
|
||||
class Blockchain:
|
||||
"""A view of a blockchain through a provided interface"""
|
||||
|
||||
mainnet: Connects to the public ethereum mainnet via geth.
|
||||
ropsten: Connects to the public ethereum ropsten testnet via geth.
|
||||
tester: Uses an ephemeral in-memory chain backed by pyethereum.
|
||||
testrpc: Uses an ephemeral in-memory chain backed by pyethereum.
|
||||
temp: Local private chain whos data directory is removed when the chain is shutdown. Runs via geth.
|
||||
"""
|
||||
|
||||
_network = NotImplemented
|
||||
_default_timeout = 120
|
||||
__instance = None
|
||||
_instance = None
|
||||
__default_interface_class = ContractInterface
|
||||
|
||||
test_chains = ('tester', )
|
||||
transient_chains = test_chains + ('testrpc', 'temp')
|
||||
public_chains = ('mainnet', 'ropsten')
|
||||
|
||||
class IsAlreadyRunning(RuntimeError):
|
||||
pass
|
||||
def __init__(self, interface: Union[ContractInterface, DeployerInterface]=None):
|
||||
|
||||
def __init__(self, contract_provider: ContractProvider):
|
||||
if interface is None:
|
||||
interface = self.__default_interface_class(blockchain_config=interface.config)
|
||||
|
||||
"""
|
||||
Configures a populus project and connects to blockchain.network.
|
||||
Transaction timeouts specified measured in seconds.
|
||||
self.__interface = interface
|
||||
self.config = interface.blockchain_config
|
||||
|
||||
http://populus.readthedocs.io/en/latest/chain.wait.html
|
||||
"""
|
||||
|
||||
# Singleton #
|
||||
if TheBlockchain.__instance is not None:
|
||||
message = '{} is already running on {}. Use .get() to retrieve'.format(self.__class__.__name__,
|
||||
self._network)
|
||||
raise TheBlockchain.IsAlreadyRunning(message)
|
||||
TheBlockchain.__instance = self
|
||||
|
||||
self.provider = contract_provider
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
if cls.__instance is None:
|
||||
class_name = cls.__name__
|
||||
raise Exception('{} has not been created.'.format(class_name))
|
||||
return cls.__instance
|
||||
if self._instance is not None:
|
||||
raise RuntimeError("Local chain already running")
|
||||
else:
|
||||
Blockchain._instance = self
|
||||
|
||||
def __repr__(self):
|
||||
class_name = self.__class__.__name__
|
||||
r = "{}(network={})"
|
||||
return r.format(class_name, self._network)
|
||||
r = "{}(interface={})"
|
||||
return r.format(class_name, self.__interface)
|
||||
|
||||
@classmethod
|
||||
def connect(cls):
|
||||
if cls._instance is None:
|
||||
raise RuntimeError('{} not running'.format(cls.__name__))
|
||||
return cls._instance
|
||||
|
||||
@property
|
||||
def interface(self):
|
||||
return self.__interface
|
||||
|
||||
@classmethod
|
||||
def sever(cls) -> None:
|
||||
cls._instance = None
|
||||
|
||||
def get_contract(self, name):
|
||||
"""
|
||||
Gets an existing contract from the registrar,
|
||||
or raises populus.contracts.exceptions.UnknownContract
|
||||
Gets an existing contract from the registrar, or raises UnknownContract
|
||||
if there is no contract data available for the name/identifier.
|
||||
"""
|
||||
return self.provider.get_contract(name)
|
||||
return self.__interface.get_contract(name)
|
||||
|
||||
def wait_for_receipt(self, txhash, timeout=None) -> None:
|
||||
timeout = timeout if timeout is not None else self._default_timeout
|
||||
result = self.provider.w3.eth.waitForTransactionReceipt(txhash, timeout=timeout)
|
||||
def wait_for_receipt(self, txhash, timeout=None) -> dict:
|
||||
"""Wait for a receipt and return it"""
|
||||
timeout = timeout if timeout is not None else self.config.timeout
|
||||
result = self.__interface.w3.eth.waitForTransactionReceipt(txhash, timeout=timeout)
|
||||
return result
|
||||
|
||||
|
||||
class TesterBlockchain(TheBlockchain, NucypherMinerConfig):
|
||||
"""Transient, in-memory, local, private chain"""
|
||||
|
||||
_network = 'tester'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
class TesterBlockchain(Blockchain, NucypherMinerConstants):
|
||||
"""
|
||||
Blockchain subclass with additional test utility methods
|
||||
and singleton-style instance caching to preserve the local blockchain state.
|
||||
"""
|
||||
|
||||
def wait_for_receipt(self, txhash, timeout=None) -> None:
|
||||
timeout = timeout if timeout is not None else self._default_timeout
|
||||
result = self.provider.w3.eth.waitForTransactionReceipt(txhash, timeout=timeout)
|
||||
timeout = timeout if timeout is not None else self.config.timeout
|
||||
result = self.interface.w3.eth.waitForTransactionReceipt(txhash, timeout=timeout)
|
||||
return result
|
||||
|
||||
def time_travel(self, hours: int=None, seconds: int=None, periods: int=None):
|
||||
|
@ -107,27 +93,22 @@ class TesterBlockchain(TheBlockchain, NucypherMinerConfig):
|
|||
else:
|
||||
raise ValueError("Specify either hours, seconds, or lock_periods.")
|
||||
|
||||
end_timestamp = ((self.provider.w3.eth.getBlock(block_identifier='latest').timestamp + duration) // base) * base
|
||||
self.provider.w3.eth.web3.testing.timeTravel(timestamp=end_timestamp)
|
||||
self.provider.w3.eth.web3.testing.mine(1)
|
||||
end_timestamp = ((self.interface.w3.eth.getBlock(block_identifier='latest').timestamp + duration) // base) * base
|
||||
self.interface.w3.eth.web3.testing.timeTravel(timestamp=end_timestamp)
|
||||
self.interface.w3.eth.web3.testing.mine(1)
|
||||
|
||||
def _global_airdrop(self, amount: int) -> List[str]:
|
||||
"""Airdrops from creator address to all other addresses!"""
|
||||
coinbase, *addresses = self.provider.w3.eth.accounts
|
||||
def ether_airdrop(self, amount: int) -> List[str]:
|
||||
"""Airdrops tokens from creator address to all other addresses!"""
|
||||
|
||||
coinbase, *addresses = self.__interface.w3.eth.accounts
|
||||
|
||||
tx_hashes = list()
|
||||
for address in addresses:
|
||||
tx = {'to': address, 'from': coinbase, 'value': amount}
|
||||
txhash = self.provider.w3.eth.sendTransaction(tx)
|
||||
_receipt = self.provider.w3.eth.waitForTransactionReceipt(txhash)
|
||||
tx_hashes.append(txhash)
|
||||
for txhash in tx_hashes:
|
||||
self.wait_for_receipt(txhash)
|
||||
return tx_hashes
|
||||
|
||||
#
|
||||
# class TestRPCBlockchain:
|
||||
#
|
||||
# _network = 'testrpc'
|
||||
# _default_timeout = 60
|
||||
#
|
||||
tx = {'to': address, 'from': coinbase, 'value': amount}
|
||||
txhash = self.interface.w3.eth.sendTransaction(tx)
|
||||
|
||||
_receipt = self.wait_for_receipt(txhash)
|
||||
tx_hashes.append(txhash)
|
||||
|
||||
return tx_hashes
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
NULL_ADDRESS = '0x' + '0' * 40
|
||||
|
||||
|
||||
class NucypherTokenConfig:
|
||||
class NucypherTokenConstants:
|
||||
|
||||
class TokenConfigError(ValueError):
|
||||
pass
|
||||
|
||||
__subdigits = 18
|
||||
_M = 10 ** __subdigits # Unit designation
|
||||
__initial_supply = int(1e9) * _M # Initial token supply
|
||||
__saturation = int(3.89e9) * _M # Token supply cap
|
||||
M = 10 ** __subdigits # Unit designation
|
||||
__initial_supply = int(1e9) * M # Initial token supply
|
||||
__saturation = int(3.89e9) * M # Token supply cap
|
||||
_remaining_supply = __saturation - __initial_supply # Remaining supply
|
||||
|
||||
@property
|
||||
|
@ -17,7 +17,7 @@ class NucypherTokenConfig:
|
|||
return self.__saturation
|
||||
|
||||
|
||||
class NucypherMinerConfig:
|
||||
class NucypherMinerConstants:
|
||||
|
||||
class MinerConfigError(ValueError):
|
||||
pass
|
||||
|
@ -26,10 +26,10 @@ class NucypherMinerConfig:
|
|||
min_locked_periods = 30 # 720 Hours minimum
|
||||
max_minting_periods = 365 # Maximum number of periods
|
||||
|
||||
min_allowed_locked = 15000 * NucypherTokenConfig._M
|
||||
max_allowed_locked = int(4e6) * NucypherTokenConfig._M
|
||||
min_allowed_locked = 15000 * NucypherTokenConstants.M
|
||||
max_allowed_locked = int(4e6) * NucypherTokenConstants.M
|
||||
|
||||
__remaining_supply = NucypherTokenConfig._remaining_supply
|
||||
__remaining_supply = NucypherTokenConstants._remaining_supply
|
||||
|
||||
__mining_coeff = [ # TODO
|
||||
_hours_per_period,
|
||||
|
|
|
@ -3,12 +3,14 @@ from typing import Tuple, Dict
|
|||
from web3.contract import Contract
|
||||
|
||||
from nucypher.blockchain.eth.agents import EthereumContractAgent, MinerAgent, NucypherTokenAgent, PolicyAgent
|
||||
from nucypher.blockchain.eth.constants import NucypherTokenConfig, NucypherMinerConfig
|
||||
from .chains import TheBlockchain
|
||||
from nucypher.blockchain.eth.constants import NucypherTokenConstants, NucypherMinerConstants
|
||||
from nucypher.blockchain.eth.interfaces import ContractInterface, DeployerInterface
|
||||
from .chains import Blockchain
|
||||
|
||||
|
||||
class ContractDeployer:
|
||||
|
||||
_interface_class = DeployerInterface
|
||||
agency = NotImplemented
|
||||
_contract_name = NotImplemented
|
||||
_arming_word = "I UNDERSTAND"
|
||||
|
@ -16,14 +18,14 @@ class ContractDeployer:
|
|||
class ContractDeploymentError(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, blockchain: TheBlockchain):
|
||||
def __init__(self, blockchain: Blockchain):
|
||||
self.__armed = False
|
||||
self._contract = None
|
||||
self.deployment_receipt = None
|
||||
self.__dispatcher = NotImplemented
|
||||
|
||||
# Sanity check
|
||||
if not isinstance(blockchain, TheBlockchain):
|
||||
if not isinstance(blockchain, Blockchain):
|
||||
error = 'Only TheBlockchain can be used to create a deployer, got {}.'
|
||||
raise ValueError(error.format(type(blockchain)))
|
||||
self.blockchain = blockchain
|
||||
|
@ -38,6 +40,10 @@ class ContractDeployer:
|
|||
else:
|
||||
return address
|
||||
|
||||
@property
|
||||
def contract(self):
|
||||
return self._contract
|
||||
|
||||
@property
|
||||
def dispatcher(self):
|
||||
return self.__dispatcher
|
||||
|
@ -65,9 +71,6 @@ class ContractDeployer:
|
|||
rules = (
|
||||
(self.is_armed is True, 'Contract not armed'),
|
||||
(self.is_deployed is not True, 'Contract already deployed'),
|
||||
# (self.blockchain.provider.are_contract_dependencies_available(self._contract_name),
|
||||
# 'Blockchain contract dependencies unmet'),
|
||||
|
||||
)
|
||||
|
||||
disqualifications = list()
|
||||
|
@ -90,19 +93,14 @@ class ContractDeployer:
|
|||
message = '{} contract is not deployed. Arm, then deploy.'.format(class_name)
|
||||
raise self.ContractDeploymentError(message)
|
||||
|
||||
# http: // populus.readthedocs.io / en / latest / chain.contracts.html # checking-availability-of-contracts
|
||||
available = bool(self.blockchain.provider.are_contract_dependencies_available(self._contract_name))
|
||||
if not available:
|
||||
raise self.ContractDeploymentError('Contract is not available')
|
||||
|
||||
return True
|
||||
|
||||
def _wrap_government(self, dispatcher_contract: Contract, target_contract: Contract) -> Contract:
|
||||
|
||||
# Wrap the contract
|
||||
wrapped_contract = self.blockchain.provider.w3.eth.contract(abi=target_contract.abi,
|
||||
address=dispatcher_contract.address,
|
||||
ContractFactoryClass=Contract)
|
||||
wrapped_contract = self.blockchain.interface.w3.eth.contract(abi=target_contract.abi,
|
||||
address=dispatcher_contract.address,
|
||||
ContractFactoryClass=Contract)
|
||||
return wrapped_contract
|
||||
|
||||
def arm(self, fail_on_abort=True) -> None:
|
||||
|
@ -120,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:
|
||||
|
@ -156,14 +154,18 @@ class ContractDeployer:
|
|||
return agent
|
||||
|
||||
|
||||
class NucypherTokenDeployer(ContractDeployer, NucypherTokenConfig):
|
||||
class NucypherTokenDeployer(ContractDeployer, NucypherTokenConstants):
|
||||
|
||||
_contract_name = 'NuCypherToken'
|
||||
agency = NucypherTokenAgent
|
||||
|
||||
def __init__(self, blockchain):
|
||||
def __init__(self, blockchain, deployer_address=None):
|
||||
if not type(blockchain.interface) is self._interface_class:
|
||||
raise ValueError("{} must be used to create a {}".format(self._interface_class.__name__,
|
||||
self.__class__.__name__))
|
||||
|
||||
super().__init__(blockchain=blockchain)
|
||||
self._creator = self.blockchain.provider.w3.eth.accounts[0] # TODO: make swappable
|
||||
self._creator = deployer_address
|
||||
|
||||
def deploy(self) -> str:
|
||||
"""
|
||||
|
@ -176,7 +178,7 @@ class NucypherTokenDeployer(ContractDeployer, NucypherTokenConfig):
|
|||
is_ready, _disqualifications = self.check_ready_to_deploy(fail=True)
|
||||
assert is_ready
|
||||
|
||||
_contract, deployment_txhash = self.blockchain.provider.deploy_contract(
|
||||
_contract, deployment_txhash = self.blockchain.interface.deploy_contract(
|
||||
self._contract_name,
|
||||
self.saturation)
|
||||
|
||||
|
@ -199,14 +201,14 @@ class DispatcherDeployer(ContractDeployer):
|
|||
|
||||
def deploy(self) -> str:
|
||||
|
||||
dispatcher_contract, txhash = self.blockchain.provider.deploy_contract(
|
||||
dispatcher_contract, txhash = self.blockchain.interface.deploy_contract(
|
||||
'Dispatcher', self.target_contract.address)
|
||||
|
||||
self._contract = dispatcher_contract
|
||||
return txhash
|
||||
|
||||
|
||||
class MinerEscrowDeployer(ContractDeployer, NucypherMinerConfig):
|
||||
class MinerEscrowDeployer(ContractDeployer, NucypherMinerConstants):
|
||||
"""
|
||||
Deploys the MinerEscrow ethereum contract to the blockchain. Depends on NucypherTokenAgent
|
||||
"""
|
||||
|
@ -244,9 +246,9 @@ class MinerEscrowDeployer(ContractDeployer, NucypherMinerConfig):
|
|||
|
||||
# 1 - Deploy #
|
||||
the_escrow_contract, deploy_txhash, = \
|
||||
self.blockchain.provider.deploy_contract(self._contract_name,
|
||||
self.token_agent.contract_address,
|
||||
*self.mining_coefficient)
|
||||
self.blockchain.interface.deploy_contract(self._contract_name,
|
||||
self.token_agent.contract_address,
|
||||
*self.mining_coefficient)
|
||||
|
||||
# 2 - Deploy the dispatcher used for updating this contract #
|
||||
dispatcher_deployer = DispatcherDeployer(token_agent=self.token_agent, target_contract=the_escrow_contract)
|
||||
|
@ -254,7 +256,7 @@ class MinerEscrowDeployer(ContractDeployer, NucypherMinerConfig):
|
|||
dispatcher_deploy_txhash = dispatcher_deployer.deploy()
|
||||
|
||||
# Cache the dispatcher contract
|
||||
dispatcher_contract = dispatcher_deployer._contract
|
||||
dispatcher_contract = dispatcher_deployer.contract
|
||||
self.__dispatcher_contract = dispatcher_contract
|
||||
|
||||
# Wrap the escrow contract (Govern)
|
||||
|
@ -296,9 +298,11 @@ class PolicyManagerDeployer(ContractDeployer):
|
|||
agency = PolicyAgent
|
||||
_contract_name = 'PolicyManager'
|
||||
|
||||
def make_agent(self) -> EthereumContractAgent:
|
||||
agent = self.agency(miner_agent=self.miner_agent, contract=self._contract)
|
||||
return agent
|
||||
|
||||
def __init__(self, miner_agent):
|
||||
# self.token_deployer = miner_escrow_deployer.token_agent
|
||||
# self.miner_escrow_deployer = miner_escrow_deployer
|
||||
self.token_agent = miner_agent.token_agent
|
||||
self.miner_agent = miner_agent
|
||||
super().__init__(blockchain=self.miner_agent.blockchain)
|
||||
|
@ -308,7 +312,7 @@ class PolicyManagerDeployer(ContractDeployer):
|
|||
assert is_ready
|
||||
|
||||
# Creator deploys the policy manager
|
||||
the_policy_manager_contract, deploy_txhash = self.blockchain.provider.deploy_contract(
|
||||
the_policy_manager_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
|
||||
self._contract_name, self.miner_agent.contract_address)
|
||||
|
||||
dispatcher_deployer = DispatcherDeployer(token_agent=self.token_agent, target_contract=the_policy_manager_contract)
|
||||
|
@ -316,7 +320,7 @@ class PolicyManagerDeployer(ContractDeployer):
|
|||
dispatcher_deploy_txhash = dispatcher_deployer.deploy()
|
||||
|
||||
# Cache the dispatcher contract
|
||||
dispatcher_contract = dispatcher_deployer._contract
|
||||
dispatcher_contract = dispatcher_deployer.contract
|
||||
self.__dispatcher_contract = dispatcher_contract
|
||||
|
||||
# Wrap the escrow contract (Govern)
|
||||
|
@ -366,7 +370,7 @@ class UserEscrowDeployer(ContractDeployer):
|
|||
self.policy_deployer.contract_address],
|
||||
deploy_transaction = {'from': self.token_deployer.contract_address}
|
||||
|
||||
the_user_escrow_contract, deploy_txhash = self.blockchain.provider.deploy_contract(
|
||||
the_user_escrow_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
|
||||
self._contract_name,
|
||||
*deployment_args)
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ class Registrar:
|
|||
WARNING: Unless you are developing NuCypher, you most
|
||||
likely won't ever need to use this.
|
||||
"""
|
||||
__DEFAULT_REGISTRAR_FILEPATH = os.path.join(_DEFAULT_CONFIGURATION_DIR, 'registrar.json')
|
||||
__DEFAULT_CHAIN_NAME = 'tester'
|
||||
__default_registrar_path = os.path.join(_DEFAULT_CONFIGURATION_DIR, 'registrar.json')
|
||||
__default_chain_name = 'tester'
|
||||
|
||||
class UnknownContract(KeyError):
|
||||
pass
|
||||
|
@ -29,8 +29,8 @@ class Registrar:
|
|||
pass
|
||||
|
||||
def __init__(self, chain_name: str=None, registrar_filepath: str=None):
|
||||
self._chain_name = chain_name or self.__DEFAULT_CHAIN_NAME
|
||||
self.__registrar_filepath = registrar_filepath or self.__DEFAULT_REGISTRAR_FILEPATH
|
||||
self._chain_name = chain_name or self.__default_chain_name
|
||||
self.__registrar_filepath = registrar_filepath or self.__default_registrar_path
|
||||
|
||||
def __write(self, registrar_data: dict) -> None:
|
||||
"""
|
||||
|
@ -69,7 +69,7 @@ class Registrar:
|
|||
the value is the Registrar object for that chain.
|
||||
Optionally, accepts a registrar filepath.
|
||||
"""
|
||||
filepath = registrar_filepath or cls.__DEFAULT_REGISTRAR_FILEPATH
|
||||
filepath = registrar_filepath or cls.__default_registrar_path
|
||||
instance = cls(registrar_filepath=filepath)
|
||||
|
||||
registrar_data = instance.__read()
|
||||
|
@ -135,7 +135,7 @@ class Registrar:
|
|||
if len(contracts) > 0:
|
||||
return contracts
|
||||
else:
|
||||
message = "Could not identify a contract name or address with {}".format(contract_name)
|
||||
message = 'Contract name or address: "{}" for chain: "{}" was not found in the registrar'.format(contract_name, self._chain_name)
|
||||
raise self.UnknownContract(message)
|
||||
|
||||
def dump_contract(self, address: str=None) -> dict:
|
||||
|
@ -155,26 +155,25 @@ class Registrar:
|
|||
if contract_data['name'] == address:
|
||||
return contract_data
|
||||
else:
|
||||
raise self.UnknownContract('No known contract with address {}'.format(address))
|
||||
raise self.UnknownContract('No known contract with address: {}'.format(address))
|
||||
|
||||
|
||||
class ContractProvider:
|
||||
class ContractInterface:
|
||||
"""
|
||||
Interacts with a solidity compiler and a registrar in order to instantiate compiled
|
||||
ethereum contracts with the given web3 provider backend.
|
||||
"""
|
||||
|
||||
def __init__(self, provider_backend: Web3,
|
||||
registrar: Registrar,
|
||||
deployer_address: str=None,
|
||||
sol_compiler: SolidityCompiler=None):
|
||||
class ContractInterfaceError(Exception):
|
||||
pass
|
||||
|
||||
self.w3 = provider_backend
|
||||
def __init__(self, blockchain_config=None, registrar: Registrar=None, sol_compiler: SolidityCompiler=None):
|
||||
"""Contracts are re-compiled if an instance is passed"""
|
||||
|
||||
# TODO: Move to deployers?
|
||||
if deployer_address is None:
|
||||
deployer_address = self.w3.eth.coinbase # coinbase / etherbase
|
||||
self.deployer_address = deployer_address
|
||||
self.blockchain_config = blockchain_config
|
||||
|
||||
web3_instance = Web3(providers=self.blockchain_config.providers)
|
||||
self.w3 = web3_instance
|
||||
|
||||
# if a SolidityCompiler class instance was passed, compile from sources
|
||||
if sol_compiler is not None:
|
||||
|
@ -184,24 +183,24 @@ class ContractProvider:
|
|||
self.__recompile = recompile
|
||||
self.__sol_compiler = sol_compiler
|
||||
|
||||
# Setup the registrar and base contract factory cache
|
||||
if registrar is None:
|
||||
registrar = Registrar(chain_name=self.blockchain_config.network)
|
||||
self._registrar = registrar
|
||||
|
||||
if self.__recompile is True:
|
||||
interfaces = self.__sol_compiler.compile()
|
||||
else:
|
||||
interfaces = self.__registrar.dump_chain()
|
||||
interfaces = self._registrar.dump_chain()
|
||||
|
||||
# Setup the registrar and base contract factory cahche
|
||||
self.__registrar = registrar
|
||||
self.__raw_contract_cache = interfaces
|
||||
|
||||
class ProviderError(Exception):
|
||||
pass
|
||||
|
||||
def get_contract_factory(self, contract_name):
|
||||
"""Retrieve compiled interface data from the cache and return web3 contract"""
|
||||
try:
|
||||
interface = self.__raw_contract_cache[contract_name]
|
||||
except KeyError:
|
||||
raise self.ProviderError('{} is not a compiled contract.'.format(contract_name))
|
||||
raise self.ContractInterfaceError('{} is not a compiled contract.'.format(contract_name))
|
||||
|
||||
contract = self.w3.eth.contract(abi=interface['abi'],
|
||||
bytecode=interface['bin'],
|
||||
|
@ -211,10 +210,26 @@ class ContractProvider:
|
|||
|
||||
def get_contract_address(self, contract_name: str) -> List[str]:
|
||||
"""Retrieve all known addresses for this contract"""
|
||||
contracts = self.__registrar.lookup_contract(contract_name=contract_name)
|
||||
contracts = self._registrar.lookup_contract(contract_name=contract_name)
|
||||
addresses = [c['addr'] for c in contracts]
|
||||
return addresses
|
||||
|
||||
def get_contract(self, address: str) -> Contract:
|
||||
"""Instantiate a deployed contract from registrar data"""
|
||||
contract_data = self._registrar.dump_contract(address=address)
|
||||
contract = self.w3.eth.contract(abi=contract_data['abi'], address=contract_data['addr'])
|
||||
return contract
|
||||
|
||||
|
||||
class DeployerInterface(ContractInterface):
|
||||
|
||||
def __init__(self, deployer_address:str=None, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if deployer_address is None:
|
||||
deployer_address = self.w3.eth.coinbase # coinbase / etherbase
|
||||
self.deployer_address = deployer_address
|
||||
|
||||
def deploy_contract(self, contract_name: str, *args, **kwargs) -> Tuple[Contract, str]:
|
||||
"""
|
||||
Retrieve compiled interface data from the cache and
|
||||
|
@ -246,14 +261,8 @@ class ContractProvider:
|
|||
# Instantiate & enroll contract
|
||||
#
|
||||
contract = contract_factory(address=address)
|
||||
self.__registrar.enroll(contract_name=contract_name,
|
||||
contract_addr=contract.address,
|
||||
contract_abi=contract_factory.abi)
|
||||
self._registrar.enroll(contract_name=contract_name,
|
||||
contract_addr=contract.address,
|
||||
contract_abi=contract_factory.abi)
|
||||
|
||||
return contract, txhash
|
||||
|
||||
def get_contract(self, address: str) -> Contract:
|
||||
"""Instantiate a deployed contract from registrar data"""
|
||||
contract_data = self.__registrar.dump_contract(address=address)
|
||||
contract = self.w3.eth.contract(abi=contract_data['abi'], address=contract_data['addr'])
|
||||
return contract
|
||||
|
|
|
@ -21,7 +21,7 @@ class BlockchainArrangement:
|
|||
self._rate = rate
|
||||
|
||||
self.value = value
|
||||
self.lock_periods = lock_periods # TODO: datetime -> duration in blocks
|
||||
self.lock_periods = lock_periods # TODO: <datetime> -> lock_periods
|
||||
|
||||
self.is_published = False
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ def main():
|
|||
escrow.deploy()
|
||||
|
||||
# Creator deploys the policy manager
|
||||
policy_manager, txhash = chain.provider.get_or_deploy_contract(
|
||||
policy_manager, txhash = chain.interface.get_or_deploy_contract(
|
||||
'PolicyManager', deploy_args=[escrow.contract.address],
|
||||
deploy_transaction={'from': creator})
|
||||
tx = escrow.transact({'from': creator}).setPolicyManager(policy_manager.address)
|
||||
|
|
|
@ -27,7 +27,7 @@ def main():
|
|||
# alice = web3.eth.accounts[2]
|
||||
|
||||
# Create an ERC20 token
|
||||
token, tx = chain.provider.get_or_deploy_contract(
|
||||
token, tx = chain.interface.get_or_deploy_contract(
|
||||
'HumanStandardToken', deploy_args=[
|
||||
int(1e9) * M, int(1e10) * M, 'NuCypher', 6, 'NU'],
|
||||
deploy_transaction={
|
||||
|
@ -35,7 +35,7 @@ def main():
|
|||
chain.wait.for_receipt(tx, timeout=TIMEOUT)
|
||||
print("Deployed HumanStandardToken, tx hash is", tx)
|
||||
|
||||
escrow, tx = chain.provider.get_or_deploy_contract(
|
||||
escrow, tx = chain.interface.get_or_deploy_contract(
|
||||
'Escrow', deploy_args=[token.address] + MINING_COEFF,
|
||||
deploy_transaction={'from': creator})
|
||||
chain.wait.for_receipt(tx, timeout=TIMEOUT)
|
||||
|
|
|
@ -9,11 +9,13 @@ from typing import Dict, ClassVar
|
|||
from typing import Union, List
|
||||
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
|
||||
from nucypher.blockchain.eth.agents import PolicyAgent
|
||||
from nucypher.network.node import NetworkyStuff
|
||||
from umbral.keys import UmbralPublicKey
|
||||
from constant_sorrow import constants, default_constant_splitter
|
||||
|
||||
from nucypher.blockchain.eth.actors import PolicyAuthor
|
||||
from nucypher.blockchain.eth.actors import PolicyAuthor, Miner
|
||||
from nucypher.config.configs import NucypherConfig
|
||||
from nucypher.crypto.api import secure_random, keccak_digest, encrypt_and_sign
|
||||
from nucypher.crypto.constants import PUBLIC_KEY_LENGTH
|
||||
|
@ -38,7 +40,8 @@ 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.
|
||||
|
@ -60,7 +63,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")
|
||||
|
||||
|
@ -319,17 +322,13 @@ class Character(object):
|
|||
self.known_nodes.update(new_nodes)
|
||||
|
||||
|
||||
class FakePolicyAgent: # TODO: #192
|
||||
_token = "fake token"
|
||||
|
||||
|
||||
class Alice(Character, PolicyAuthor):
|
||||
_server_class = NucypherSeedOnlyDHTServer
|
||||
_default_crypto_powerups = [SigningPower, EncryptingPower, DelegatingPower]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
PolicyAuthor.__init__(self, self.address, policy_agent=FakePolicyAgent())
|
||||
PolicyAuthor.__init__(self, address=self.address, *args, **kwargs)
|
||||
|
||||
def generate_kfrags(self, bob, label, m, n) -> List:
|
||||
"""
|
||||
|
@ -597,17 +596,18 @@ class Bob(Character):
|
|||
raise RuntimeError("Not verified - replace this with real message.")
|
||||
|
||||
|
||||
class Ursula(Character, ProxyRESTServer):
|
||||
class Ursula(Character, ProxyRESTServer, Miner):
|
||||
_server_class = NucypherDHTServer
|
||||
_alice_class = Alice
|
||||
_default_crypto_powerups = [SigningPower, EncryptingPower]
|
||||
|
||||
def __init__(self, dht_port=None, ip_address=None, dht_ttl=0,
|
||||
rest_port=None, db_name=None,
|
||||
*args, **kwargs):
|
||||
def __init__(self, dht_port=None, ip_address=None, dht_ttl=0, rest_port=None, db_name=None, *args, **kwargs):
|
||||
|
||||
self.dht_port = dht_port
|
||||
self.dht_ttl = dht_ttl
|
||||
self.ip_address = ip_address
|
||||
self._work_orders = []
|
||||
|
||||
ProxyRESTServer.__init__(self, rest_port, db_name)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -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,109 @@ class NetworkConfig:
|
|||
return self.__db_path
|
||||
|
||||
|
||||
class BlockchainConfig:
|
||||
|
||||
__default_providers = (IPCProvider(ipc_path='/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 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
|
||||
|
|
|
@ -7,9 +7,13 @@ from nucypher.network.capabilities import ServerCapability
|
|||
from umbral.fragments import CapsuleFrag
|
||||
|
||||
|
||||
class NucypherNode(Node):
|
||||
class NucypherDHTNode(Node):
|
||||
|
||||
def __init__(self, id, ip=None, port=None, capabilities=None, capabilities_as_strings=None, *args, **kwargs):
|
||||
|
||||
if capabilities_as_strings is None:
|
||||
capabilities_as_strings = []
|
||||
|
||||
def __init__(self, id, ip=None, port=None, capabilities=None, capabilities_as_strings=[], *args, **kwargs):
|
||||
self.id = id
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
|
@ -20,6 +24,8 @@ class NucypherNode(Node):
|
|||
for capability_name in capabilities_as_strings:
|
||||
self.capabilities.append(ServerCapability.from_name(capability_name))
|
||||
|
||||
super().__init__(id, ip, port, *args, **kwargs)
|
||||
|
||||
def can_store(self):
|
||||
for c in self.capabilities:
|
||||
if c.prohibits_storage:
|
||||
|
|
|
@ -7,7 +7,7 @@ from nucypher.crypto.api import keccak_digest
|
|||
from nucypher.crypto.constants import PUBLIC_KEY_LENGTH, KECCAK_DIGEST_LENGTH
|
||||
from nucypher.crypto.signing import Signature
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
from nucypher.network.node import NucypherNode
|
||||
from nucypher.network.node import NucypherDHTNode
|
||||
from nucypher.network.routing import NucypherRoutingTable
|
||||
from umbral.keys import UmbralPublicKey
|
||||
|
||||
|
@ -31,8 +31,8 @@ class NucypherHashProtocol(KademliaProtocol):
|
|||
return True
|
||||
|
||||
def rpc_ping(self, sender, nodeid, node_capabilities=[]):
|
||||
source = NucypherNode(nodeid, sender[0], sender[1],
|
||||
capabilities_as_strings=node_capabilities)
|
||||
source = NucypherDHTNode(nodeid, sender[0], sender[1],
|
||||
capabilities_as_strings=node_capabilities)
|
||||
self.welcomeIfNewNode(source)
|
||||
return self.sourceNode.id
|
||||
|
||||
|
@ -72,7 +72,7 @@ class NucypherHashProtocol(KademliaProtocol):
|
|||
return True
|
||||
|
||||
def rpc_store(self, sender, nodeid, key, value):
|
||||
source = NucypherNode(nodeid, sender[0], sender[1])
|
||||
source = NucypherDHTNode(nodeid, sender[0], sender[1])
|
||||
self.welcomeIfNewNode(source)
|
||||
self.log.debug("got a store request from %s" % str(sender))
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ from nucypher.crypto.kits import UmbralMessageKit
|
|||
from nucypher.crypto.powers import EncryptingPower, SigningPower
|
||||
from nucypher.keystore.threading import ThreadedSession
|
||||
from nucypher.network.capabilities import SeedOnly, ServerCapability
|
||||
from nucypher.network.node import NucypherNode
|
||||
from nucypher.network.node import NucypherDHTNode
|
||||
from nucypher.network.protocols import NucypherSeedOnlyProtocol, NucypherHashProtocol, \
|
||||
dht_value_splitter, dht_with_hrac_splitter
|
||||
from nucypher.network.storage import SeedOnlyStorage
|
||||
|
@ -30,7 +30,7 @@ class NucypherDHTServer(Server):
|
|||
|
||||
def __init__(self, ksize=20, alpha=3, id=None, storage=None, *args, **kwargs):
|
||||
super().__init__(ksize=20, alpha=3, id=None, storage=None, *args, **kwargs)
|
||||
self.node = NucypherNode(id or digest(
|
||||
self.node = NucypherDHTNode(id or digest(
|
||||
random.getrandbits(255))) # TODO: Assume that this can be attacked to get closer to desired kFrags.
|
||||
|
||||
def serialize_capabilities(self):
|
||||
|
@ -41,7 +41,7 @@ class NucypherDHTServer(Server):
|
|||
Announce node including capabilities
|
||||
"""
|
||||
result = await self.protocol.ping(addr, self.node.id, self.serialize_capabilities())
|
||||
return NucypherNode(result[1], addr[0], addr[1]) if result[0] else None
|
||||
return NucypherDHTNode(result[1], addr[0], addr[1]) if result[0] else None
|
||||
|
||||
async def set_digest(self, dkey, value):
|
||||
"""
|
||||
|
|
|
@ -232,11 +232,9 @@ class Policy(object):
|
|||
self.treasure_map.add_ursula(arrangement.ursula)
|
||||
|
||||
def make_arrangement(self, deposit, expiration):
|
||||
return Arrangement(self.alice, self.hrac(), expiration=expiration,
|
||||
deposit=deposit)
|
||||
return Arrangement(self.alice, self.hrac(), expiration=expiration, deposit=deposit)
|
||||
|
||||
def find_ursulas(self, networky_stuff, deposit, expiration,
|
||||
num_ursulas=None):
|
||||
def find_ursulas(self, networky_stuff, deposit, expiration, num_ursulas=None):
|
||||
"""
|
||||
:param networky_stuff: A compliant interface (maybe a Client instance) to be used to engage the DHT swarm.
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -24,11 +24,11 @@ def escrow(web3, chain):
|
|||
node3 = web3.eth.accounts[3]
|
||||
|
||||
# Creator deploys the escrow
|
||||
escrow_library, _ = chain.provider.deploy_contract(
|
||||
escrow_library, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrowV1Mock', [node1, node2, node3], [1, 2, 3]
|
||||
)
|
||||
|
||||
escrow_dispatcher, _ = chain.provider.deploy_contract(
|
||||
escrow_dispatcher, _ = chain.interface.deploy_contract(
|
||||
'Dispatcher', escrow_library.address
|
||||
)
|
||||
contract = web3.eth.contract(
|
||||
|
@ -41,8 +41,8 @@ def escrow(web3, chain):
|
|||
@pytest.fixture()
|
||||
def policy_manager(web3, chain):
|
||||
# Creator deploys the escrow
|
||||
contract, _ = chain.provider.deploy_contract('PolicyManagerV1Mock')
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
contract, _ = chain.interface.deploy_contract('PolicyManagerV1Mock')
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
contract = web3.eth.contract(
|
||||
abi=contract.abi,
|
||||
address=dispatcher.address,
|
||||
|
@ -55,10 +55,10 @@ def test_voting(web3, chain, escrow, policy_manager):
|
|||
creator, node1, node2, node3, *everyone_else = web3.eth.accounts
|
||||
|
||||
# Deploy contract
|
||||
government_library, _ = chain.provider.deploy_contract(
|
||||
government_library, _ = chain.interface.deploy_contract(
|
||||
'Government', escrow.address, policy_manager.address, 1,
|
||||
)
|
||||
government_dispatcher, _ = chain.provider.deploy_contract(
|
||||
government_dispatcher, _ = chain.interface.deploy_contract(
|
||||
'Dispatcher', government_library.address
|
||||
)
|
||||
government = web3.eth.contract(
|
||||
|
@ -84,7 +84,7 @@ def test_voting(web3, chain, escrow, policy_manager):
|
|||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Deploy second version of the government contract
|
||||
government_library_v2, _ = chain.provider.deploy_contract(
|
||||
government_library_v2, _ = chain.interface.deploy_contract(
|
||||
'Government', escrow.address, policy_manager.address, 1,
|
||||
)
|
||||
assert government_library.address != government_library_v2.address
|
||||
|
@ -231,10 +231,10 @@ def test_upgrade(web3, chain, escrow, policy_manager):
|
|||
node1 = web3.eth.accounts[1]
|
||||
|
||||
# Deploy contract
|
||||
government_library_v1, _ = chain.provider.deploy_contract(
|
||||
government_library_v1, _ = chain.interface.deploy_contract(
|
||||
'Government', escrow.address, policy_manager.address, 1,
|
||||
)
|
||||
government_dispatcher, _ = chain.provider.deploy_contract(
|
||||
government_dispatcher, _ = chain.interface.deploy_contract(
|
||||
'Dispatcher', government_library_v1.address,
|
||||
)
|
||||
government = web3.eth.contract(
|
||||
|
@ -247,20 +247,20 @@ def test_upgrade(web3, chain, escrow, policy_manager):
|
|||
upgrade_committed_log = government.events.UpgradeCommitted.createFilter(fromBlock='latest')
|
||||
|
||||
# Deploy second version of the government contract
|
||||
government_library_v2, _ = chain.provider.deploy_contract(
|
||||
government_library_v2, _ = chain.interface.deploy_contract(
|
||||
'Government', escrow.address, policy_manager.address, 1,
|
||||
)
|
||||
# Get first version of the escrow contract
|
||||
escrow_library_v1 = escrow.functions.target().call()
|
||||
# Deploy second version of the escrow contract
|
||||
escrow_library_v2, _ = chain.provider.deploy_contract(
|
||||
escrow_library_v2, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrowV1Mock', [node1], [1]
|
||||
)
|
||||
escrow_library_v2 = escrow_library_v2.address
|
||||
# Get first version of the policy manager contract
|
||||
policy_manager_library_v1 = policy_manager.functions.target().call()
|
||||
# Deploy second version of the policy manager contract
|
||||
policy_manager_library_v2, _ = chain.provider.deploy_contract('PolicyManagerV1Mock')
|
||||
policy_manager_library_v2, _ = chain.interface.deploy_contract('PolicyManagerV1Mock')
|
||||
policy_manager_library_v2 = policy_manager_library_v2.address
|
||||
|
||||
# Transfer ownership
|
||||
|
@ -450,15 +450,16 @@ def test_upgrade(web3, chain, escrow, policy_manager):
|
|||
assert event_args['successful']
|
||||
|
||||
|
||||
@pytest.mark.slow()
|
||||
def test_cancel_upgrading(web3, chain, escrow, policy_manager):
|
||||
creator = web3.eth.accounts[0]
|
||||
node1 = web3.eth.accounts[1]
|
||||
|
||||
# Deploy contract
|
||||
government_library, _ = chain.provider.deploy_contract(
|
||||
government_library, _ = chain.interface.deploy_contract(
|
||||
'GovernmentV2Mock', escrow.address, policy_manager.address, 1,
|
||||
)
|
||||
government_dispatcher, _ = chain.provider.deploy_contract(
|
||||
government_dispatcher, _ = chain.interface.deploy_contract(
|
||||
'Dispatcher', government_library.address
|
||||
)
|
||||
government = web3.eth.contract(
|
||||
|
@ -468,7 +469,7 @@ def test_cancel_upgrading(web3, chain, escrow, policy_manager):
|
|||
)
|
||||
escrow_library = escrow.functions.target().call()
|
||||
policy_manager_library = policy_manager.functions.target().call()
|
||||
upgradeable_bad, _ = chain.provider.deploy_contract('UpgradeableBad')
|
||||
upgradeable_bad, _ = chain.interface.deploy_contract('UpgradeableBad')
|
||||
upgrade_committed_log = government.events.UpgradeCommitted.createFilter(fromBlock=0)
|
||||
tx = government.functions.transferOwnership(government.address).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
@ -610,15 +611,15 @@ def test_verifying_state(web3, chain):
|
|||
address2 = web3.eth.accounts[2]
|
||||
|
||||
# Deploy contract
|
||||
government_library_v1, _ = chain.provider.deploy_contract(
|
||||
government_library_v1, _ = chain.interface.deploy_contract(
|
||||
'Government', address1, address2, 1,
|
||||
)
|
||||
government_dispatcher, _ = chain.provider.deploy_contract(
|
||||
government_dispatcher, _ = chain.interface.deploy_contract(
|
||||
'Dispatcher', government_library_v1.address
|
||||
)
|
||||
|
||||
# Deploy second version of the government contract
|
||||
government_library_v2, _ = chain.provider.deploy_contract(
|
||||
government_library_v2, _ = chain.interface.deploy_contract(
|
||||
'GovernmentV2Mock', address2, address1, 2,
|
||||
)
|
||||
government = web3.eth.contract(
|
||||
|
@ -638,7 +639,7 @@ def test_verifying_state(web3, chain):
|
|||
assert 3 == government.functions.valueToCheck().call()
|
||||
|
||||
# Can't upgrade to the previous version or to the bad version
|
||||
government_library_bad, _ = chain.provider.deploy_contract('GovernmentBad')
|
||||
government_library_bad, _ = chain.interface.deploy_contract('GovernmentBad')
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = government_dispatcher.functions.upgrade(government_library_v1.address).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
|
|
@ -40,14 +40,14 @@ ROLLBACK_POLICY_MANAGER = 5
|
|||
@pytest.fixture()
|
||||
def token(chain):
|
||||
# Create an ERC20 token
|
||||
contract, _ = chain.provider.deploy_contract('NuCypherToken', 2 * 10 ** 9)
|
||||
contract, _ = chain.interface.deploy_contract('NuCypherToken', 2 * 10 ** 9)
|
||||
return contract
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def escrow(web3, chain, token):
|
||||
# Creator deploys the escrow
|
||||
contract, _ = chain.provider.deploy_contract(
|
||||
contract, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrow',
|
||||
token.address,
|
||||
1,
|
||||
|
@ -58,7 +58,7 @@ def escrow(web3, chain, token):
|
|||
100,
|
||||
2000)
|
||||
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
|
||||
# Wrap dispatcher contract
|
||||
contract = web3.eth.contract(abi=contract.abi, address=dispatcher.address, ContractFactoryClass=Contract)
|
||||
|
@ -70,8 +70,8 @@ def policy_manager(web3, chain, escrow):
|
|||
creator = web3.eth.accounts[0]
|
||||
|
||||
# Creator deploys the policy manager
|
||||
contract, _ = chain.provider.deploy_contract('PolicyManager', escrow.address)
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
contract, _ = chain.interface.deploy_contract('PolicyManager', escrow.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
|
||||
# Wrap dispatcher contract
|
||||
contract = web3.eth.contract(abi=contract.abi, address=dispatcher.address, ContractFactoryClass=Contract)
|
||||
|
@ -87,8 +87,8 @@ def government(web3, chain, escrow, policy_manager):
|
|||
creator = web3.eth.accounts[0]
|
||||
|
||||
# Creator deploys the government
|
||||
contract, _ = chain.provider.deploy_contract('Government', escrow.address, policy_manager.address, 1)
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
contract, _ = chain.interface.deploy_contract('Government', escrow.address, policy_manager.address, 1)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
|
||||
# Wrap dispatcher contract
|
||||
contract = web3.eth.contract(abi=contract.abi, address=dispatcher.address, ContractFactoryClass=Contract)
|
||||
|
@ -144,14 +144,16 @@ def test_all(web3, chain, token, escrow, policy_manager, government):
|
|||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Deposit some tokens to the user escrow and lock them
|
||||
user_escrow_1, _ = chain.provider.deploy_contract('UserEscrow', token.address, escrow.address, policy_manager.address, government.address)
|
||||
user_escrow_1, _ = chain.interface.deploy_contract('UserEscrow', token.address, escrow.address, policy_manager.address, government.address)
|
||||
|
||||
tx = user_escrow_1.functions.transferOwnership(ursula3).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
tx = token.functions.approve(user_escrow_1.address, 10000).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
tx = user_escrow_1.functions.initialDeposit(10000, 20 * 60 * 60).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
user_escrow_2, _ = chain.provider.deploy_contract('UserEscrow', token.address, escrow.address, policy_manager.address, government.address)
|
||||
user_escrow_2, _ = chain.interface.deploy_contract('UserEscrow', token.address, escrow.address, policy_manager.address, government.address)
|
||||
|
||||
tx = user_escrow_2.functions.transferOwnership(ursula4).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
tx = token.functions.approve(user_escrow_2.address, 10000).transact({'from': creator})
|
||||
|
@ -403,7 +405,7 @@ def test_all(web3, chain, token, escrow, policy_manager, government):
|
|||
policy_manager_v1 = policy_manager.functions.target().call()
|
||||
government_v1 = government.functions.target().call()
|
||||
# Creator deploys the contracts as the second versions
|
||||
escrow_v2, _ = chain.provider.deploy_contract(
|
||||
escrow_v2, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrow',
|
||||
token.address,
|
||||
1,
|
||||
|
@ -413,8 +415,8 @@ def test_all(web3, chain, token, escrow, policy_manager, government):
|
|||
2,
|
||||
100,
|
||||
2000)
|
||||
policy_manager_v2, _ = chain.provider.deploy_contract('PolicyManager', escrow.address)
|
||||
government_v2, _ = chain.provider.deploy_contract('Government', escrow.address, policy_manager.address, 1)
|
||||
policy_manager_v2, _ = chain.interface.deploy_contract('PolicyManager', escrow.address)
|
||||
government_v2, _ = chain.interface.deploy_contract('Government', escrow.address, policy_manager.address, 1)
|
||||
assert FINISHED_STATE == government.functions.getVotingState().call()
|
||||
|
||||
# Alice can't create voting
|
||||
|
|
|
@ -6,7 +6,7 @@ from eth_tester.exceptions import TransactionFailed
|
|||
@pytest.fixture()
|
||||
def token(chain):
|
||||
# Create an ERC20 token
|
||||
token, _ = chain.provider.deploy_contract('NuCypherToken', 2 * 10 ** 40)
|
||||
token, _ = chain.interface.deploy_contract('NuCypherToken', 2 * 10 ** 40)
|
||||
return token
|
||||
|
||||
@pytest.mark.slow
|
||||
|
@ -15,7 +15,7 @@ def test_issuer(web3, chain, token):
|
|||
ursula = web3.eth.accounts[1]
|
||||
|
||||
# Creator deploys the issuer
|
||||
issuer, _ = chain.provider.deploy_contract(
|
||||
issuer, _ = chain.interface.deploy_contract(
|
||||
'IssuerMock', token.address, 1, 10 ** 46, int(1e7), int(1e7)
|
||||
)
|
||||
|
||||
|
@ -68,7 +68,7 @@ def test_inflation_rate(web3, chain, token):
|
|||
ursula = web3.eth.accounts[1]
|
||||
|
||||
# Creator deploys the miner
|
||||
issuer, _ = chain.provider.deploy_contract(
|
||||
issuer, _ = chain.interface.deploy_contract(
|
||||
'IssuerMock', token.address, 1, 2 * 10 ** 19, 1, 1
|
||||
)
|
||||
|
||||
|
@ -111,13 +111,13 @@ def test_verifying_state(web3, chain, token):
|
|||
creator = web3.eth.accounts[0]
|
||||
|
||||
# Deploy contract
|
||||
contract_library_v1, _ = chain.provider.deploy_contract(
|
||||
contract_library_v1, _ = chain.interface.deploy_contract(
|
||||
'Issuer', token.address, 1, 1, 1, 1
|
||||
)
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
|
||||
# Deploy second version of the contract
|
||||
contract_library_v2, _ = chain.provider.deploy_contract('IssuerV2Mock', token.address, 2, 2, 2, 2)
|
||||
contract_library_v2, _ = chain.interface.deploy_contract('IssuerV2Mock', token.address, 2, 2, 2, 2)
|
||||
contract = web3.eth.contract(
|
||||
abi=contract_library_v2.abi,
|
||||
address=dispatcher.address,
|
||||
|
@ -146,7 +146,7 @@ def test_verifying_state(web3, chain, token):
|
|||
assert 3 == contract.functions.valueToCheck().call()
|
||||
|
||||
# Can't upgrade to the previous version or to the bad version
|
||||
contract_library_bad, _ = chain.provider.deploy_contract('IssuerBad', token.address, 2, 2, 2, 2)
|
||||
contract_library_bad, _ = chain.interface.deploy_contract('IssuerBad', token.address, 2, 2, 2, 2)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = dispatcher.functions.upgrade(contract_library_v1.address).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
|
|
@ -14,7 +14,7 @@ LAST_ACTIVE_PERIOD_FIELD = 4
|
|||
@pytest.fixture()
|
||||
def token(chain):
|
||||
# Create an ERC20 token
|
||||
token, _ = chain.provider.deploy_contract('NuCypherToken', 2 * 10 ** 9)
|
||||
token, _ = chain.interface.deploy_contract('NuCypherToken', 2 * 10 ** 9)
|
||||
return token
|
||||
|
||||
|
||||
|
@ -22,11 +22,11 @@ def token(chain):
|
|||
def escrow_contract(web3, chain, token, request):
|
||||
def make_escrow(max_allowed_locked_tokens):
|
||||
# Creator deploys the escrow
|
||||
contract, _ = chain.provider.deploy_contract(
|
||||
contract, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrow', token.address, 1, 4 * 2 * 10 ** 7, 4, 4, 2, 100, max_allowed_locked_tokens)
|
||||
|
||||
if request.param:
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
contract = web3.eth.contract(
|
||||
abi=contract.abi,
|
||||
address=dispatcher.address,
|
||||
|
@ -48,7 +48,7 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
divides_log = escrow.events.Divided.createFilter(fromBlock='latest')
|
||||
withdraw_log = escrow.events.Withdrawn.createFilter(fromBlock='latest')
|
||||
|
||||
policy_manager, _ = chain.provider.deploy_contract(
|
||||
policy_manager, _ = chain.interface.deploy_contract(
|
||||
'PolicyManagerForMinersEscrowMock', token.address, escrow.address
|
||||
)
|
||||
tx = escrow.functions.setPolicyManager(policy_manager.address).transact()
|
||||
|
@ -498,7 +498,7 @@ def test_mining(web3, chain, token, escrow_contract):
|
|||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
policy_manager, _ = chain.provider.deploy_contract(
|
||||
policy_manager, _ = chain.interface.deploy_contract(
|
||||
'PolicyManagerForMinersEscrowMock', token.address, escrow.address
|
||||
)
|
||||
tx = escrow.functions.setPolicyManager(policy_manager.address).transact({'from': creator})
|
||||
|
@ -828,13 +828,13 @@ def test_verifying_state(web3, chain, token):
|
|||
miner = web3.eth.accounts[1]
|
||||
|
||||
# Deploy contract
|
||||
contract_library_v1, _ = chain.provider.deploy_contract(
|
||||
contract_library_v1, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrow', token.address, 1, int(8e7), 4, 4, 2, 100, 1500
|
||||
)
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
|
||||
# Deploy second version of the contract
|
||||
contract_library_v2, _ = chain.provider.deploy_contract(
|
||||
contract_library_v2, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrowV2Mock', token.address, 2, 2, 2, 2, 2, 2, 2, 2
|
||||
)
|
||||
|
||||
|
@ -845,7 +845,7 @@ def test_verifying_state(web3, chain, token):
|
|||
assert 1500 == contract.functions.maxAllowableLockedTokens().call()
|
||||
|
||||
# Initialize contract and miner
|
||||
policy_manager, _ = chain.provider.deploy_contract('PolicyManagerForMinersEscrowMock', token.address, contract.address)
|
||||
policy_manager, _ = chain.interface.deploy_contract('PolicyManagerForMinersEscrowMock', token.address, contract.address)
|
||||
|
||||
tx = contract.functions.setPolicyManager(policy_manager.address).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
@ -872,7 +872,7 @@ def test_verifying_state(web3, chain, token):
|
|||
assert 3 == contract.functions.valueToCheck().call()
|
||||
|
||||
# Can't upgrade to the previous version or to the bad version
|
||||
contract_library_bad, _ = chain.provider.deploy_contract(
|
||||
contract_library_bad, _ = chain.interface.deploy_contract(
|
||||
'MinersEscrowBad', token.address, 2, 2, 2, 2, 2, 2, 2
|
||||
)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ def escrow(web3, chain):
|
|||
node2 = web3.eth.accounts[4]
|
||||
node3 = web3.eth.accounts[5]
|
||||
# Creator deploys the escrow
|
||||
escrow, _ = chain.provider.deploy_contract('MinersEscrowForPolicyMock', [node1, node2, node3], 1)
|
||||
escrow, _ = chain.interface.deploy_contract('MinersEscrowForPolicyMock', [node1, node2, node3], 1)
|
||||
return escrow
|
||||
|
||||
|
||||
|
@ -33,14 +33,14 @@ def policy_manager(web3, chain, escrow, request):
|
|||
client = web3.eth.accounts[1]
|
||||
|
||||
# Creator deploys the policy manager
|
||||
contract, _ = chain.provider.deploy_contract('PolicyManager', escrow.address)
|
||||
contract, _ = chain.interface.deploy_contract('PolicyManager', escrow.address)
|
||||
|
||||
# Give client some ether
|
||||
tx = web3.eth.sendTransaction({'from': web3.eth.coinbase, 'to': client, 'value': 10000})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
if request.param:
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract.address)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract.address)
|
||||
|
||||
# Deploy second version of the government contract
|
||||
contract = web3.eth.contract(
|
||||
|
@ -679,11 +679,11 @@ def test_verifying_state(web3, chain):
|
|||
address2 = web3.eth.accounts[2]
|
||||
|
||||
# Deploy contract
|
||||
contract_library_v1, _ = chain.provider.deploy_contract('PolicyManager', address1)
|
||||
dispatcher, _ = chain.provider.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
contract_library_v1, _ = chain.interface.deploy_contract('PolicyManager', address1)
|
||||
dispatcher, _ = chain.interface.deploy_contract('Dispatcher', contract_library_v1.address)
|
||||
|
||||
# Deploy second version of the contract
|
||||
contract_library_v2, _ = chain.provider.deploy_contract('PolicyManagerV2Mock', address2)
|
||||
contract_library_v2, _ = chain.interface.deploy_contract('PolicyManagerV2Mock', address2)
|
||||
contract = web3.eth.contract(
|
||||
abi=contract_library_v2.abi,
|
||||
address=dispatcher.address,
|
||||
|
@ -700,7 +700,7 @@ def test_verifying_state(web3, chain):
|
|||
assert 3 == contract.functions.valueToCheck().call()
|
||||
|
||||
# Can't upgrade to the previous version or to the bad version
|
||||
contract_library_bad, _ = chain.provider.deploy_contract('PolicyManagerBad', address2)
|
||||
contract_library_bad, _ = chain.interface.deploy_contract('PolicyManagerBad', address2)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = dispatcher.functions.upgrade(contract_library_v1.address).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
|
|
@ -14,7 +14,7 @@ def test_create_token(web3, chain):
|
|||
account2 = web3.eth.accounts[2]
|
||||
|
||||
# Create an ERC20 token
|
||||
token, txhash = chain.provider.deploy_contract('NuCypherToken', 10 ** 9)
|
||||
token, txhash = chain.interface.deploy_contract('NuCypherToken', 10 ** 9)
|
||||
assert txhash is not None
|
||||
|
||||
# Account balances
|
||||
|
@ -58,8 +58,8 @@ def test_approve_and_call(web3, chain):
|
|||
account1 = web3.eth.accounts[1]
|
||||
account2 = web3.eth.accounts[2]
|
||||
|
||||
token, _ = chain.provider.deploy_contract('NuCypherToken', 10 ** 9)
|
||||
mock, _ = chain.provider.deploy_contract('ReceiveApprovalMethodMock')
|
||||
token, _ = chain.interface.deploy_contract('NuCypherToken', 10 ** 9)
|
||||
mock, _ = chain.interface.deploy_contract('ReceiveApprovalMethodMock')
|
||||
|
||||
tx = token.functions.approve(account1, 100).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
|
|
@ -5,7 +5,7 @@ from eth_tester.exceptions import TransactionFailed
|
|||
@pytest.fixture()
|
||||
def token(chain):
|
||||
# Create an ERC20 token
|
||||
token, _ = chain.provider.deploy_contract('NuCypherToken', int(2e9))
|
||||
token, _ = chain.interface.deploy_contract('NuCypherToken', int(2e9))
|
||||
return token
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@ def token(chain):
|
|||
def escrow(web3, chain, token):
|
||||
creator = web3.eth.accounts[0]
|
||||
# Creator deploys the escrow
|
||||
contract, _ = chain.provider.deploy_contract('MinersEscrowForUserEscrowMock', token.address)
|
||||
contract, _ = chain.interface.deploy_contract('MinersEscrowForUserEscrowMock', token.address)
|
||||
|
||||
# Give escrow some coins
|
||||
tx = token.functions.transfer(contract.address, 10000).transact({'from': creator})
|
||||
|
@ -24,13 +24,13 @@ def escrow(web3, chain, token):
|
|||
|
||||
@pytest.fixture()
|
||||
def policy_manager(chain):
|
||||
contract, _ = chain.provider.deploy_contract('PolicyManagerForUserEscrowMock')
|
||||
contract, _ = chain.interface.deploy_contract('PolicyManagerForUserEscrowMock')
|
||||
return contract
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def government(chain):
|
||||
contract, _ = chain.provider.deploy_contract('GovernmentForUserEscrowMock')
|
||||
contract, _ = chain.interface.deploy_contract('GovernmentForUserEscrowMock')
|
||||
return contract
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ def user_escrow(web3, chain, token, escrow, policy_manager, government):
|
|||
user = web3.eth.accounts[1]
|
||||
|
||||
# Creator deploys the user escrow
|
||||
contract, _ = chain.provider.deploy_contract(
|
||||
contract, _ = chain.interface.deploy_contract(
|
||||
'UserEscrow', token.address, escrow.address, policy_manager.address, government.address)
|
||||
|
||||
# Transfer ownership
|
||||
|
|
|
@ -2,98 +2,99 @@ import os
|
|||
|
||||
import pytest
|
||||
|
||||
from nucypher.blockchain.eth.actors import Miner
|
||||
from nucypher.blockchain.eth.agents import MinerAgent
|
||||
from nucypher.blockchain.eth.actors import Miner, PolicyAuthor
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def miner(chain, mock_token_agent, mock_miner_agent):
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent._M)
|
||||
_origin, ursula, *everybody_else = chain.provider.w3.eth.accounts
|
||||
miner = Miner(miner_agent=mock_miner_agent, address=ursula)
|
||||
return miner
|
||||
class TestMiner:
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def miner(self, chain, mock_token_agent, mock_miner_agent):
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent.M)
|
||||
_origin, ursula, *everybody_else = chain.interface.w3.eth.accounts
|
||||
miner = Miner(miner_agent=mock_miner_agent, address=ursula)
|
||||
return miner
|
||||
|
||||
def test_miner_locking_tokens(chain, miner, mock_miner_agent):
|
||||
def test_miner_locking_tokens(self, chain, miner, mock_miner_agent):
|
||||
|
||||
assert mock_miner_agent.min_allowed_locked < miner.token_balance(), "Insufficient miner balance"
|
||||
assert mock_miner_agent.min_allowed_locked < miner.token_balance(), "Insufficient miner balance"
|
||||
|
||||
miner.stake(amount=mock_miner_agent.min_allowed_locked, # Lock the minimum amount of tokens
|
||||
lock_periods=mock_miner_agent.min_locked_periods) # ... for the fewest number of periods
|
||||
miner.stake(amount=mock_miner_agent.min_allowed_locked, # Lock the minimum amount of tokens
|
||||
lock_periods=mock_miner_agent.min_locked_periods) # ... for the fewest number of periods
|
||||
|
||||
# Verify that the escrow is "approved" to receive tokens
|
||||
assert mock_miner_agent.token_agent.contract.functions.allowance(miner.address, mock_miner_agent.contract_address).call() == 0
|
||||
# Verify that the escrow is "approved" to receive tokens
|
||||
assert mock_miner_agent.token_agent.contract.functions.allowance(miner.address, mock_miner_agent.contract_address).call() == 0
|
||||
|
||||
# Staking starts after one period
|
||||
assert mock_miner_agent.contract.functions.getLockedTokens(miner.address).call() == 0
|
||||
# Staking starts after one period
|
||||
assert mock_miner_agent.contract.functions.getLockedTokens(miner.address).call() == 0
|
||||
|
||||
# Wait for it...
|
||||
chain.time_travel(periods=1)
|
||||
assert mock_miner_agent.contract.functions.getLockedTokens(miner.address).call() == mock_miner_agent.min_allowed_locked
|
||||
|
||||
|
||||
def test_miner_collects_staking_reward_tokens(chain, miner, mock_token_agent, mock_miner_agent, mock_policy_agent):
|
||||
|
||||
# Capture the current token balance of the miner
|
||||
initial_balance = miner.token_balance()
|
||||
assert mock_token_agent.get_balance(miner.address) == miner.token_balance()
|
||||
|
||||
# Have other address lock tokens
|
||||
_origin, *everybody_else = chain.provider.w3.eth.accounts
|
||||
mock_miner_agent.spawn_random_miners(addresses=everybody_else)
|
||||
|
||||
# ...wait out the lock period...
|
||||
for _ in range(28):
|
||||
# Wait for it...
|
||||
chain.time_travel(periods=1)
|
||||
miner.confirm_activity()
|
||||
assert mock_miner_agent.contract.functions.getLockedTokens(miner.address).call() == mock_miner_agent.min_allowed_locked
|
||||
|
||||
# ...wait more...
|
||||
chain.time_travel(periods=2)
|
||||
miner.mint()
|
||||
miner.collect_staking_reward()
|
||||
@pytest.mark.slow()
|
||||
@pytest.mark.usefixtures("mock_policy_agent")
|
||||
def test_miner_collects_staking_reward_tokens(self, chain, miner, mock_token_agent, mock_miner_agent):
|
||||
|
||||
final_balance = mock_token_agent.get_balance(miner.address)
|
||||
assert final_balance > initial_balance
|
||||
# Capture the current token balance of the miner
|
||||
initial_balance = miner.token_balance()
|
||||
assert mock_token_agent.get_balance(miner.address) == miner.token_balance()
|
||||
|
||||
miner.stake(amount=mock_miner_agent.min_allowed_locked, # Lock the minimum amount of tokens
|
||||
lock_periods=mock_miner_agent.min_locked_periods) # ... for the fewest number of periods
|
||||
|
||||
# Have other address lock tokens
|
||||
_origin, ursula, *everybody_else = chain.interface.w3.eth.accounts
|
||||
mock_miner_agent.spawn_random_miners(addresses=everybody_else)
|
||||
|
||||
# ...wait out the lock period...
|
||||
for _ in range(28):
|
||||
chain.time_travel(periods=1)
|
||||
miner.confirm_activity()
|
||||
|
||||
# ...wait more...
|
||||
chain.time_travel(periods=2)
|
||||
miner.mint()
|
||||
miner.collect_staking_reward()
|
||||
|
||||
final_balance = mock_token_agent.get_balance(miner.address)
|
||||
assert final_balance > initial_balance
|
||||
|
||||
def test_publish_miner_datastore(self, miner):
|
||||
|
||||
# Publish Miner IDs to the DHT
|
||||
some_data = os.urandom(32)
|
||||
_txhash = miner.publish_data(some_data)
|
||||
|
||||
# Fetch the miner Ids
|
||||
stored_miner_ids = miner.fetch_data()
|
||||
|
||||
assert len(stored_miner_ids) == 1
|
||||
assert some_data == stored_miner_ids[0]
|
||||
|
||||
# Repeat, with another miner ID
|
||||
another_mock_miner_id = os.urandom(32)
|
||||
_txhash = miner.publish_data(another_mock_miner_id)
|
||||
|
||||
stored_miner_ids = miner.fetch_data()
|
||||
|
||||
assert len(stored_miner_ids) == 2
|
||||
assert another_mock_miner_id == stored_miner_ids[1]
|
||||
|
||||
supposedly_the_same_miner_id = miner.miner_agent.contract.functions.getMinerId(miner.address, 1).call()
|
||||
assert another_mock_miner_id == supposedly_the_same_miner_id
|
||||
|
||||
|
||||
@pytest.mark.slow()
|
||||
def test_sample_miners(chain, mock_miner_agent, mock_token_agent):
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent._M)
|
||||
class TestPolicyAuthor:
|
||||
|
||||
# Have other address lock tokens
|
||||
_origin, ursula, *everybody_else = chain.provider.w3.eth.accounts
|
||||
mock_miner_agent.spawn_random_miners(addresses=everybody_else)
|
||||
@pytest.fixture(scope='class')
|
||||
def author(self, chain, mock_token_agent, mock_policy_agent):
|
||||
mock_token_agent.ether_airdrop(amount=100000 * mock_token_agent.M)
|
||||
_origin, ursula, alice, *everybody_else = chain.interface.w3.eth.accounts
|
||||
miner = PolicyAuthor(address=alice, policy_agent=mock_policy_agent)
|
||||
return miner
|
||||
|
||||
chain.time_travel(periods=1)
|
||||
def test_create_policy_author(self, chain, mock_policy_agent):
|
||||
_origin, ursula, alice, *everybody_else = chain.interface.w3.eth.accounts
|
||||
|
||||
with pytest.raises(MinerAgent.NotEnoughUrsulas):
|
||||
mock_miner_agent.sample(quantity=100) # Waay more than we have deployed
|
||||
|
||||
miners = mock_miner_agent.sample(quantity=3)
|
||||
assert len(miners) == 3
|
||||
assert len(set(miners)) == 3
|
||||
|
||||
|
||||
def test_publish_miner_datastore(miner):
|
||||
|
||||
# Publish Miner IDs to the DHT
|
||||
some_data = os.urandom(32)
|
||||
_txhash = miner.publish_data(some_data)
|
||||
|
||||
# Fetch the miner Ids
|
||||
stored_miner_ids = miner.fetch_data()
|
||||
|
||||
assert len(stored_miner_ids) == 1
|
||||
assert some_data == stored_miner_ids[0]
|
||||
|
||||
# Repeat, with another miner ID
|
||||
another_mock_miner_id = os.urandom(32)
|
||||
_txhash = miner.publish_data(another_mock_miner_id)
|
||||
|
||||
stored_miner_ids = miner.fetch_data()
|
||||
|
||||
assert len(stored_miner_ids) == 2
|
||||
assert another_mock_miner_id == stored_miner_ids[1]
|
||||
|
||||
supposedly_the_same_miner_id = miner.miner_agent.contract.functions.getMinerId(miner.address, 1).call()
|
||||
assert another_mock_miner_id == supposedly_the_same_miner_id
|
||||
policy_author = PolicyAuthor(policy_agent=mock_policy_agent, address=alice)
|
||||
assert policy_author.address == alice
|
|
@ -1,14 +1,15 @@
|
|||
import pytest
|
||||
|
||||
from nucypher.blockchain.eth.agents import MinerAgent
|
||||
|
||||
M = 10 ** 6
|
||||
|
||||
|
||||
@pytest.mark.slow()
|
||||
def test_get_swarm(chain, mock_token_agent, mock_miner_agent):
|
||||
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent._M)
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent.M)
|
||||
|
||||
creator, *addresses = chain.provider.w3.eth.accounts
|
||||
creator, *addresses = chain.interface.w3.eth.accounts
|
||||
|
||||
mock_miner_agent.spawn_random_miners(addresses=addresses)
|
||||
|
||||
|
@ -28,3 +29,20 @@ def test_get_swarm(chain, mock_token_agent, mock_miner_agent):
|
|||
except ValueError:
|
||||
pytest.fail()
|
||||
|
||||
|
||||
@pytest.mark.slow()
|
||||
def test_sample_miners(chain, mock_miner_agent, mock_token_agent):
|
||||
mock_token_agent.token_airdrop(amount=100000 * mock_token_agent.M)
|
||||
|
||||
# Have other address lock tokens
|
||||
_origin, ursula, *everybody_else = chain.interface.w3.eth.accounts
|
||||
mock_miner_agent.spawn_random_miners(addresses=everybody_else)
|
||||
|
||||
chain.time_travel(periods=1)
|
||||
|
||||
with pytest.raises(MinerAgent.NotEnoughUrsulas):
|
||||
mock_miner_agent.sample(quantity=100) # Waay more than we have deployed
|
||||
|
||||
miners = mock_miner_agent.sample(quantity=3)
|
||||
assert len(miners) == 3
|
||||
assert len(set(miners)) == 3
|
||||
|
|
|
@ -3,15 +3,13 @@ from nucypher.blockchain.eth.deployers import NucypherTokenDeployer
|
|||
|
||||
def test_chain_creation(chain):
|
||||
# Ensure we are testing on the correct network...
|
||||
assert chain._network == 'tester'
|
||||
assert chain.config.network == 'tester'
|
||||
|
||||
# ... and that there are already some blocks mined
|
||||
assert chain.provider.w3.eth.blockNumber >= 0
|
||||
assert chain.interface.w3.eth.blockNumber >= 0
|
||||
|
||||
|
||||
def test_nucypher_contract_compiled(chain):
|
||||
# Check that populus paths are set...
|
||||
|
||||
# Ensure that solidity smart contacts are available, post-compile.
|
||||
token_contract_identifier = NucypherTokenDeployer(blockchain=chain)._contract_name
|
||||
assert token_contract_identifier in chain.provider._ContractProvider__raw_contract_cache
|
||||
assert token_contract_identifier in chain.interface._ContractInterface__raw_contract_cache
|
||||
|
|
|
@ -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
|
||||
|
@ -24,7 +24,7 @@ class MockTokenAgent(NucypherTokenAgent):
|
|||
"""Airdrops tokens from creator address to all other addresses!"""
|
||||
|
||||
if addresses is None:
|
||||
_creator, *addresses = self.blockchain.provider.w3.eth.accounts
|
||||
_creator, *addresses = self.blockchain.interface.w3.eth.accounts
|
||||
|
||||
def txs():
|
||||
for address in addresses:
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -12,12 +12,11 @@ from umbral.keys import UmbralPublicKey
|
|||
import maya
|
||||
|
||||
|
||||
def test_grant(alice, bob):
|
||||
def test_grant(alice, bob, nucypher_test_config):
|
||||
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
|
||||
n = 5
|
||||
uri = b"this_is_the_path_to_which_access_is_being_granted"
|
||||
policy = alice.grant(bob, uri, m=3, n=n,
|
||||
expiration=policy_end_datetime)
|
||||
policy = alice.grant(bob, uri, m=3, n=n, expiration=policy_end_datetime)
|
||||
|
||||
# The number of policies is equal to the number of Ursulas we're using (n)
|
||||
assert len(policy._accepted_arrangements) == n
|
||||
|
|
|
@ -49,7 +49,7 @@ def test_actor_with_signing_power_can_sign():
|
|||
assert verification is True
|
||||
|
||||
|
||||
def test_anybody_can_verify():
|
||||
def test_anybody_can_verify(nucypher_test_config, mock_policy_agent):
|
||||
"""
|
||||
In the last example, we used the lower-level Crypto API to verify the signature.
|
||||
|
||||
|
@ -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."
|
||||
|
@ -71,6 +71,7 @@ def test_anybody_can_verify():
|
|||
assert verification is True
|
||||
assert cleartext is constants.NO_DECRYPTION_PERFORMED
|
||||
|
||||
|
||||
"""
|
||||
Chapter 2: ENCRYPTION
|
||||
"""
|
||||
|
@ -90,10 +91,12 @@ def test_anybody_can_encrypt():
|
|||
assert signature == constants.NOT_SIGNED
|
||||
assert ciphertext is not None
|
||||
|
||||
|
||||
"""
|
||||
What follows are various combinations of signing and encrypting, to match real-world scenarios.
|
||||
"""
|
||||
|
||||
|
||||
def test_sign_cleartext_and_encrypt(alice, bob):
|
||||
"""
|
||||
Exhibit One: Alice signs the cleartext and encrypts her signature inside the ciphertext.
|
||||
|
@ -140,7 +143,6 @@ def test_encrypt_and_sign_including_signature_in_both_places(alice, bob):
|
|||
assert cleartext == message
|
||||
|
||||
|
||||
|
||||
def test_encrypt_but_do_not_sign(alice, bob):
|
||||
"""
|
||||
Finally, Alice encrypts but declines to 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,21 @@
|
|||
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 os.path import abspath, dirname
|
||||
from web3 import EthereumTesterProvider, IPCProvider
|
||||
from web3.middleware import geth_poa_middleware
|
||||
|
||||
from nucypher.blockchain.eth.chains import TheBlockchain, TesterBlockchain
|
||||
from nucypher.blockchain.eth.deployers import PolicyManagerDeployer
|
||||
from nucypher.blockchain.eth.interfaces import Registrar, ContractProvider
|
||||
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
|
||||
|
||||
|
@ -31,7 +31,7 @@ def manual_geth_ipc_provider():
|
|||
Provider backend
|
||||
https:// github.com/ethereum/eth-tester
|
||||
"""
|
||||
ipc_provider = IPCProvider(ipc_path=os.path.join('/tmp/geth.ipc'))
|
||||
ipc_provider = IPCProvider(ipc_path='/tmp/geth.ipc')
|
||||
yield ipc_provider
|
||||
|
||||
|
||||
|
@ -98,12 +98,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 +125,53 @@ 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, poa=False):
|
||||
"""Compatibility fixture"""
|
||||
if poa is True:
|
||||
w3 = deployer_interface.interface.w3
|
||||
w3.middleware_stack.inject(geth_poa_middleware, layer=0)
|
||||
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 #
|
||||
#
|
||||
|
@ -170,7 +179,8 @@ def chain(contract_provider, airdrop=False):
|
|||
|
||||
@pytest.fixture(scope='module')
|
||||
def mock_token_deployer(chain):
|
||||
token_deployer = MockNucypherTokenDeployer(blockchain=chain)
|
||||
origin, *everyone = chain.interface.w3.eth.coinbase
|
||||
token_deployer = MockNucypherTokenDeployer(blockchain=chain, deployer_address=origin)
|
||||
token_deployer.arm()
|
||||
token_deployer.deploy()
|
||||
yield token_deployer
|
||||
|
@ -194,28 +204,26 @@ def mock_policy_manager_deployer(mock_miner_agent):
|
|||
|
||||
#
|
||||
# Agents #
|
||||
# Unused args preserve fixture dependency order #
|
||||
#
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mock_token_agent(mock_token_deployer):
|
||||
token_agent = mock_token_deployer.make_agent()
|
||||
|
||||
assert mock_token_deployer._contract.address == token_agent.contract_address
|
||||
assert mock_token_deployer.contract.address == token_agent.contract_address
|
||||
yield token_agent
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.mark.usefixtures("mock_token_agent")
|
||||
def mock_miner_agent(mock_miner_escrow_deployer):
|
||||
miner_agent = mock_miner_escrow_deployer.make_agent()
|
||||
|
||||
assert mock_miner_escrow_deployer._contract.address == miner_agent.contract_address
|
||||
assert mock_miner_escrow_deployer.contract.address == miner_agent.contract_address
|
||||
yield miner_agent
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.mark.usefixtures("mock_miner_agent")
|
||||
def mock_policy_agent(mock_policy_manager_deployer):
|
||||
policy_agent = mock_policy_manager_deployer.make_agent()
|
||||
|
||||
assert mock_policy_manager_deployer._contract.address == policy_agent.contract_address
|
||||
assert mock_policy_manager_deployer.contract.address == policy_agent.contract_address
|
||||
yield policy_agent
|
||||
|
|
|
@ -7,11 +7,15 @@ 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.config.configs import NucypherConfig
|
||||
from nucypher.crypto.signature import SignatureStamp
|
||||
|
||||
from nucypher.keystore import keystore
|
||||
from nucypher.keystore.db import Base
|
||||
|
||||
from nucypher.crypto.signing import SignatureStamp
|
||||
from nucypher.data_sources import DataSource
|
||||
from nucypher.keystore import keystore
|
||||
from nucypher.keystore.db import Base
|
||||
|
@ -21,6 +25,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 +68,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 +84,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