mirror of https://github.com/nucypher/nucypher.git
Introduce MiningAdjudicator deployer & agent; Deployment entry points and integration testing.
parent
0f0841c0a5
commit
a0bfb22c05
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue