Introduce MiningAdjudicator deployer & agent; Deployment entry points and integration testing.

pull/866/head
Kieran Prasch 2019-03-19 20:41:26 -07:00
parent 0f0841c0a5
commit a0bfb22c05
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
7 changed files with 162 additions and 19 deletions

View File

@ -100,6 +100,8 @@ class NucypherTokenActor:
class Deployer(NucypherTokenActor):
contract_names = tuple(a.registry_contract_name for a in EthereumContractAgent.__subclasses__())
__interface_class = BlockchainDeployerInterface
def __init__(self,
@ -117,6 +119,7 @@ class Deployer(NucypherTokenActor):
self.token_agent = NucypherTokenAgent(blockchain=blockchain)
self.miner_agent = MinerAgent(blockchain=blockchain)
self.policy_agent = PolicyAgent(blockchain=blockchain)
self.adjudicator_agent = MiningAdjudicatorAgent(blockchain=blockchain)
self.user_escrow_deployers = dict()
@ -125,6 +128,7 @@ class Deployer(NucypherTokenActor):
MinerEscrowDeployer.contract_name: self.deploy_miner_contract,
PolicyManagerDeployer.contract_name: self.deploy_policy_contract,
UserEscrowProxyDeployer.contract_name: self.deploy_escrow_proxy,
MiningAdjudicatorDeployer.contract_name: self.deploy_mining_adjudicator_contract,
}
def __repr__(self):
@ -182,6 +186,16 @@ class Deployer(NucypherTokenActor):
self.policy_agent = policy_manager_deployer.make_agent()
return txhashes
def deploy_mining_adjudicator_contract(self, secret: bytes):
secret = self.blockchain.interface.w3.keccak(secret)
mining_adjudicator_deployer = MiningAdjudicatorDeployer(blockchain=self.blockchain,
deployer_address=self.deployer_address,
secret_hash=secret)
txhashes = mining_adjudicator_deployer.deploy()
self.adjudicator_agent = mining_adjudicator_deployer.make_agent()
return txhashes
def deploy_escrow_proxy(self, secret: bytes):
secret = self.blockchain.interface.w3.keccak(secret)
escrow_proxy_deployer = UserEscrowProxyDeployer(blockchain=self.blockchain,
@ -201,24 +215,31 @@ class Deployer(NucypherTokenActor):
self.user_escrow_deployers[principal_address] = user_escrow_deployer
return user_escrow_deployer
def deploy_network_contracts(self, miner_secret: bytes, policy_secret: bytes) -> Tuple[dict, dict]:
def deploy_network_contracts(self,
miner_secret: bytes,
policy_secret: bytes,
adjudicator_secret: bytes
) -> Tuple[dict, dict]:
"""
Musketeers, if you will; Deploy the "big three" contracts to the blockchain.
"""
token_txhashes = self.deploy_token_contract()
miner_txhashes = self.deploy_miner_contract(secret=miner_secret)
policy_txhashes = self.deploy_policy_contract(secret=policy_secret)
adjudicator_txhashes = self.deploy_mining_adjudicator_contract(secret=adjudicator_secret)
txhashes = {
NucypherTokenDeployer.contract_name: token_txhashes,
MinerEscrowDeployer.contract_name: miner_txhashes,
PolicyManagerDeployer.contract_name: policy_txhashes
PolicyManagerDeployer.contract_name: policy_txhashes,
MiningAdjudicatorDeployer.contract_name: adjudicator_txhashes
}
agents = {
NucypherTokenDeployer.contract_name: self.token_agent,
MinerEscrowDeployer.contract_name: self.miner_agent,
PolicyManagerDeployer.contract_name: self.policy_agent
PolicyManagerDeployer.contract_name: self.policy_agent,
MiningAdjudicatorDeployer.contract_name: self.adjudicator_agent
}
return txhashes, agents

View File

@ -451,3 +451,22 @@ class UserEscrowAgent(EthereumContractAgent):
txhash = self.__proxy_contract.functions.setMinRewardRate(rate).transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash
class MiningAdjudicatorAgent(EthereumContractAgent):
"""TODO"""
registry_contract_name = "MiningAdjudicator"
_proxy_name = "Dispatcher"
def evaluate_cfrag(self,
capsule: bytes,
capsule_signature_by_requester: bytes,
capsule_signature_by_requester_and_miner: bytes,
cfrag: bytes,
cfrag_signature_by_miner: bytes,
requester_public_key: bytes,
miner_public_key: bytes,
miner_piblc_key_signature: bytes,
precomputed_data: bytes):
pass

View File

@ -53,6 +53,7 @@ class ContractDeployer:
self.blockchain = blockchain or Blockchain.connect()
self.deployment_transactions = CONTRACT_NOT_DEPLOYED
self.deployment_receipt = CONTRACT_NOT_DEPLOYED
self._contract = CONTRACT_NOT_DEPLOYED
self.__proxy_contract = NotImplemented
@ -509,3 +510,60 @@ class UserEscrowDeployer(ContractDeployer):
self._contract = user_escrow_contract
return deployment_transactions
class MiningAdjudicatorDeployer(ContractDeployer):
agency = MiningAdjudicatorAgent
contract_name = agency.registry_contract_name
__upgradeable = True
__proxy_deployer = DispatcherDeployer
def __init__(self,
secret_hash,
economics: SlashingEconomics = None,
*args, **kwargs):
super().__init__(*args, **kwargs)
self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
self.miner_agent = MinerAgent(blockchain=self.blockchain)
self.secret_hash = secret_hash
if not economics:
economics = SlashingEconomics()
self.__economics = economics
def deploy(self) -> Dict[str, str]:
self.check_deployment_readiness()
mining_adjudicator_contract, deploy_txhash = self.blockchain.interface \
.deploy_contract(self.contract_name,
self.miner_agent.contract_address,
*self.__economics.deployment_parameters)
proxy_deployer = self.__proxy_deployer(blockchain=self.blockchain,
target_contract=mining_adjudicator_contract,
deployer_address=self.deployer_address,
secret_hash=self.secret_hash)
proxy_deploy_txhashes = proxy_deployer.deploy()
# Cache the dispatcher contract
proxy_contract = proxy_deployer.contract
self.__proxy_contract = proxy_contract
# Wrap the escrow contract
wrapped_mining_adjudicator_contract = self.blockchain.interface._wrap_contract(proxy_contract, target_contract=mining_adjudicator_contract)
# Switch the contract for the wrapped one
mining_adjudicator_contract = wrapped_mining_adjudicator_contract
# Gather the transaction hashes
deployment_transactions = {'deployment': deploy_txhash,
'dispatcher_deployment': proxy_deploy_txhashes['txhash']}
self.deployment_transactions = deployment_transactions
self._contract = mining_adjudicator_contract
return deployment_transactions

View File

@ -33,13 +33,10 @@ from nucypher.utilities.logging import (
logToSentry,
getTextFileObserver,
initialize_sentry,
getJsonFileObserver)
getJsonFileObserver
)
#
# Click CLI Config
#
class NucypherClickConfig:
# Output Sinks
@ -118,7 +115,14 @@ class NucypherClickConfig:
class NucypherDeployerClickConfig(NucypherClickConfig):
Secrets = collections.namedtuple('Secrets', ('miner_secret', 'policy_secret', 'escrow_proxy_secret'))
# Deploy Environment Variables
miner_escrow_deployment_secret = os.environ.get("NUCYPHER_MINER_ESCROW_SECRET", None)
policy_manager_deployment_secret = os.environ.get("NUCYPHER_POLICY_MANAGER_SECRET", None)
user_escrow_proxy_deployment_secret = os.environ.get("NUCYPHER_USER_ESCROW_PROXY_SECRET", None)
mining_adjudicator_deployment_secret = os.environ.get("NUCYPHER_MINING_ADJUDICATOR_SECRET", None)
__secrets = ('miner_secret', 'policy_secret', 'escrow_proxy_secret', 'mining_adjudicator_secret')
Secrets = collections.namedtuple('Secrets', __secrets)
def collect_deployment_secrets(self) -> Secrets:
@ -137,9 +141,15 @@ class NucypherDeployerClickConfig(NucypherClickConfig):
escrow_proxy_secret = click.prompt('Enter UserEscrowProxy Deployment Secret', hide_input=True,
confirmation_prompt=True)
mining_adjudicator_secret = self.user_escrow_proxy_deployment_secret
if not mining_adjudicator_secret:
mining_adjudicator_secret = click.prompt('Enter MiningAdjudicator Deployment Secret', hide_input=True,
confirmation_prompt=True)
secrets = self.Secrets(miner_secret=miner_secret, # type: str
policy_secret=policy_secret, # type: str
escrow_proxy_secret=escrow_proxy_secret # type: str
escrow_proxy_secret=escrow_proxy_secret, # type: str
mining_adjudicator_secret=mining_adjudicator_secret
)
return secrets

View File

@ -101,7 +101,8 @@ def deploy(click_config,
try:
txhashes, agents = deployer.deploy_network_contracts(miner_secret=bytes(secrets.miner_secret, encoding='utf-8'),
policy_secret=bytes(secrets.policy_secret, encoding='utf-8'))
policy_secret=bytes(secrets.policy_secret, encoding='utf-8'),
adjudicator_secret=bytes(secrets.mining_adjudicator_secret, encoding='utf-8'))
except BlockchainInterface.InterfaceError:
raise # TODO: Handle registry management here (contract may already exist)
else:

View File

@ -20,11 +20,10 @@ import pytest
from constant_sorrow import constants
from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent
from nucypher.blockchain.eth.constants import DISPATCHER_SECRET_LENGTH
from nucypher.blockchain.eth.deployers import (NucypherTokenDeployer,
MinerEscrowDeployer,
PolicyManagerDeployer,
ContractDeployer)
ContractDeployer, DispatcherDeployer)
@pytest.mark.slow()
@ -57,7 +56,7 @@ def test_deploy_ethereum_contracts(testerchain):
#
# Miner Escrow
#
miners_escrow_secret = os.urandom(DISPATCHER_SECRET_LENGTH)
miners_escrow_secret = os.urandom(DispatcherDeployer.DISPATCHER_SECRET_LENGTH)
miner_escrow_deployer = MinerEscrowDeployer(
blockchain=testerchain,
deployer_address=origin,

View File

@ -1,7 +1,14 @@
import json
import os
from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent, UserEscrowAgent
from nucypher.blockchain.eth.constants import MAX_ALLOWED_LOCKED
from nucypher.blockchain.eth.actors import Deployer
from nucypher.blockchain.eth.agents import (
NucypherTokenAgent,
MinerAgent,
UserEscrowAgent,
PolicyAgent,
MiningAdjudicatorAgent
)
from nucypher.blockchain.eth.registry import AllocationRegistry
from nucypher.cli.deploy import deploy
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
@ -31,22 +38,50 @@ def test_nucypher_deploy_contracts(testerchain, click_runner, mock_primary_regis
'--provider-uri', TEST_PROVIDER_URI,
'--poa')
user_input = 'Y\n'+f'{INSECURE_DEVELOPMENT_PASSWORD}\n'*6
user_input = 'Y\n'+f'{INSECURE_DEVELOPMENT_PASSWORD}\n'*8
result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False)
assert result.exit_code == 0
# Ensure there is a report on each contract
for registry_name in Deployer.contract_names:
assert registry_name in result.output
# Check that the primary contract registry was written
# and peek at some of the registered entries
assert os.path.isfile(mock_primary_registry_filepath)
with open(mock_primary_registry_filepath, 'r') as file:
# Ensure every contract's name was written to the file, somehow
raw_registry_data = file.read()
for registry_name in Deployer.contract_names:
assert registry_name in raw_registry_data
# Ensure the Registry is JSON deserializable
registry_data = json.loads(raw_registry_data)
# and that is has the correct number of entries
assert len(registry_data) == 9
# Read several records
token_record, escrow_record, dispatcher_record, *other_records = registry_data
registered_name, registered_address, registered_abi = token_record
token_agent = NucypherTokenAgent()
assert token_agent.contract_name == registered_name
assert token_agent.registry_contract_name == registered_name
assert token_agent.contract_address == registered_address
# Now show that we can use contract Agency and read from the blockchain
token_agent = NucypherTokenAgent()
assert token_agent.get_balance() == 0
miner_agent = MinerAgent()
assert miner_agent.get_current_period()
# and at least the others can be instantiated
assert PolicyAgent()
assert MiningAdjudicatorAgent()
testerchain.sever_connection()
def test_nucypher_deploy_allocations(testerchain, click_runner, mock_allocation_infile):
def test_nucypher_deploy_allocations(testerchain, click_runner, mock_allocation_infile, token_economics):
deploy_command = ('allocations',
'--registry-infile', MOCK_REGISTRY_FILEPATH,