More general deployment modes: Meet Bare, Idle and Full

Idle = Deploy contract in 'idle' state, without activation
pull/1738/head
David Núñez 2020-02-21 16:15:54 +01:00
parent 5968b519d8
commit e55ccf2341
4 changed files with 83 additions and 36 deletions

View File

@ -28,6 +28,9 @@ import maya
from constant_sorrow.constants import (
WORKER_NOT_RUNNING,
NO_WORKER_ASSIGNED,
BARE,
IDLE,
FULL
)
from eth_tester.exceptions import TransactionFailed
from eth_utils import keccak, is_checksum_address, to_checksum_address
@ -265,7 +268,7 @@ class ContractAdministrator(NucypherTokenActor):
contract_name: str,
gas_limit: int = None,
plaintext_secret: str = None,
bare: bool = False,
deployment_mode=FULL,
ignore_deployed: bool = False,
progress=None,
confirmations: int = 0,
@ -286,7 +289,7 @@ class ContractAdministrator(NucypherTokenActor):
self.transacting_power.activate() # Activate the TransactingPower in case too much time has passed
if Deployer._upgradeable:
is_initial_deployment = not bare
is_initial_deployment = deployment_mode != BARE # i.e., we also deploy a dispatcher
if is_initial_deployment and not plaintext_secret:
raise ValueError("An upgrade secret must be passed to perform initial deployment of a Dispatcher.")
secret_hash = None
@ -294,14 +297,16 @@ class ContractAdministrator(NucypherTokenActor):
secret_hash = keccak(bytes(plaintext_secret, encoding='utf-8'))
receipts = deployer.deploy(secret_hash=secret_hash,
gas_limit=gas_limit,
initial_deployment=is_initial_deployment,
progress=progress,
ignore_deployed=ignore_deployed,
confirmations=confirmations)
confirmations=confirmations,
deployment_mode=deployment_mode,
**deployment_parameters)
else:
receipts = deployer.deploy(gas_limit=gas_limit,
progress=progress,
confirmations=confirmations,
deployment_mode=deployment_mode,
**deployment_parameters)
return receipts, deployer

View File

@ -19,7 +19,14 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
from collections import OrderedDict
from typing import Tuple, Dict, List
from constant_sorrow.constants import CONTRACT_NOT_DEPLOYED, NO_DEPLOYER_CONFIGURED, NO_BENEFICIARY
from constant_sorrow.constants import (
CONTRACT_NOT_DEPLOYED,
NO_DEPLOYER_CONFIGURED,
NO_BENEFICIARY,
BARE,
IDLE,
FULL
)
from web3 import Web3
from web3.contract import Contract
@ -36,11 +43,11 @@ from nucypher.blockchain.eth.agents import (
MultiSigAgent,
ContractAgency
)
from nucypher.blockchain.eth.constants import DISPATCHER_CONTRACT_NAME, STAKING_INTERFACE_ROUTER_CONTRACT_NAME
from nucypher.blockchain.eth.constants import DISPATCHER_CONTRACT_NAME
from nucypher.blockchain.eth.decorators import validate_secret, validate_checksum_address
from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.interfaces import (
BlockchainDeployerInterface,
BlockchainInterfaceFactory,
VersionedContract
)
from nucypher.blockchain.eth.registry import AllocationRegistry
@ -59,6 +66,8 @@ class BaseContractDeployer:
_ownable = NotImplemented
_proxy_deployer = NotImplemented
can_be_idle = False
class ContractDeploymentError(Exception):
pass
@ -493,7 +502,11 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
agency = StakingEscrowAgent
contract_name = agency.registry_contract_name
deployment_steps = ('contract_deployment', 'dispatcher_deployment', 'approve_reward_transfer', 'initialize')
can_be_idle = True
preparation_steps = ('contract_deployment', 'dispatcher_deployment')
activation_steps = ('approve_reward_transfer', 'initialize')
deployment_steps = preparation_steps + activation_steps
_proxy_deployer = DispatcherDeployer
def __init__(self, test_mode: bool = False, *args, **kwargs):
@ -535,7 +548,7 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
return the_escrow_contract, deploy_receipt
def deploy(self,
initial_deployment: bool = True,
deployment_mode=FULL,
secret_hash: bytes = None,
gas_limit: int = None,
progress=None,
@ -557,7 +570,10 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
Returns transaction receipts in a dict.
"""
if initial_deployment and not secret_hash:
if deployment_mode not in (BARE, IDLE, FULL):
raise ValueError(f"Invalid deployment mode ({deployment_mode})")
if deployment_mode is not BARE and not secret_hash:
raise ValueError(f"An upgrade secret hash is required to perform an initial"
f" deployment series for {self.contract_name}.")
@ -576,10 +592,10 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
**overrides)
# This is the end of bare deployment.
if not initial_deployment:
if deployment_mode is BARE:
self._contract = the_escrow_contract
return self._finish_bare_deployment(deployment_receipt=deploy_receipt,
progress=progress)
receipts = self._finish_bare_deployment(deployment_receipt=deploy_receipt, progress=progress)
return receipts
if progress:
progress.update(1)
@ -603,10 +619,27 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
target_contract=the_escrow_contract)
# Switch the contract for the wrapped one
the_escrow_contract = wrapped_escrow_contract
self._contract = wrapped_escrow_contract
# 3 - Approve transfer the reward supply tokens to StakingEscrow #
approve_reward_function = self.token_contract.functions.approve(the_escrow_contract.address,
preparation_receipts = dict(zip(self.preparation_steps, (deploy_receipt, dispatcher_deploy_receipt)))
self.deployment_receipts = preparation_receipts
if deployment_mode is IDLE:
# This is the end of deployment without activation: the contract is now idle, waiting for activation
return preparation_receipts
else: # deployment_mode is FULL
activation_receipts = self.activate(gas_limit=gas_limit, progress=progress)
self.deployment_receipts.update(activation_receipts)
return self.deployment_receipts
def activate(self, gas_limit: int = None, progress=None):
origin_args = {}
if gas_limit:
origin_args.update({'gas': gas_limit}) # TODO: #842 - Gas Management
# 3 - Approve transferring the reward supply tokens to StakingEscrow #
approve_reward_function = self.token_contract.functions.approve(self._contract.address,
self.economics.erc20_reward_supply)
# TODO: Confirmations / Successful Transaction Indicator / Events ?? - #1193, #1194
@ -617,22 +650,15 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
progress.update(1)
# 4 - Initialize the StakingEscrow contract
init_function = the_escrow_contract.functions.initialize(self.economics.erc20_reward_supply)
init_function = self._contract.functions.initialize(self.economics.erc20_reward_supply)
init_receipt = self.blockchain.send_transaction(contract_function=init_function,
sender_address=self.deployer_address,
payload=origin_args)
if progress:
progress.update(1)
# Gather the transaction receipts
ordered_receipts = (deploy_receipt, dispatcher_deploy_receipt, approve_reward_receipt, init_receipt)
deployment_receipts = dict(zip(self.deployment_steps, ordered_receipts))
# Set the contract and transaction receipts #
self._contract = the_escrow_contract
self.deployment_receipts = deployment_receipts
return deployment_receipts
activation_receipts = dict(zip(self.activation_steps, (approve_reward_receipt, init_receipt)))
return activation_receipts
class PolicyManagerDeployer(BaseContractDeployer, UpgradeableContractMixin, OwnableContractMixin):

View File

@ -19,6 +19,12 @@ import json
import os
import click
from constant_sorrow import constants
from constant_sorrow.constants import (
BARE,
IDLE,
FULL
)
from nucypher.blockchain.eth.actors import ContractAdministrator, Trustee
from nucypher.blockchain.eth.agents import NucypherTokenAgent, ContractAgency, MultiSigAgent
@ -359,13 +365,19 @@ def rollback(general_config, actor_options):
@deploy.command()
@group_general_config
@group_actor_options
@click.option('--bare', help="Deploy a contract *only* without any additional operations.", is_flag=True)
@click.option('--mode',
help="Deploy a contract following all steps ('full'), up to idle status ('idle'), "
"or just the bare contract ('bare'). Defaults to 'full'",
type=click.Choice(['full', 'idle', 'bare']),
#case_sensitive
default='full'
)
@option_gas
@option_ignore_deployed
@click.option('--confirmations', help="Number of required block confirmations", type=click.IntRange(min=0))
@click.option('--parameters', help="Filepath to a JSON file containing additional deployment parameters",
type=EXISTING_READABLE_FILE)
def contracts(general_config, actor_options, bare, gas, ignore_deployed, confirmations, parameters):
def contracts(general_config, actor_options, mode, gas, ignore_deployed, confirmations, parameters):
"""
Compile and deploy contracts.
"""
@ -383,6 +395,7 @@ def contracts(general_config, actor_options, bare, gas, ignore_deployed, confirm
# Deploy Single Contract (Amend Registry)
#
contract_name = actor_options.contract_name
deployment_mode = constants.__getattr__(mode.upper()) # TODO: constant sorrow
if contract_name:
try:
contract_deployer = ADMINISTRATOR.deployers[contract_name]
@ -393,24 +406,24 @@ def contracts(general_config, actor_options, bare, gas, ignore_deployed, confirm
# Deploy
emitter.echo(f"Deploying {contract_name}")
if contract_deployer._upgradeable and not bare:
if contract_deployer._upgradeable and deployment_mode is not BARE:
# NOTE: Bare deployments do not engage the proxy contract
secret = ADMINISTRATOR.collect_deployment_secret(deployer=contract_deployer)
receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name,
plaintext_secret=secret,
gas_limit=gas,
bare=bare,
deployment_mode=deployment_mode,
ignore_deployed=ignore_deployed,
confirmations=confirmations)
confirmations=confirmations,
deployment_parameters=deployment_parameters)
else:
# Non-Upgradeable or Bare
receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name,
gas_limit=gas,
bare=bare,
deployment_mode=deployment_mode,
ignore_deployed=ignore_deployed,
confirmations=confirmations,
deployment_parameters=deployment_parameters
)
deployment_parameters=deployment_parameters)
# Report
paint_contract_deployment(contract_name=contract_name,
@ -424,6 +437,9 @@ def contracts(general_config, actor_options, bare, gas, ignore_deployed, confirm
#
# Deploy Automated Series (Create Registry)
#
if deployment_mode is not FULL:
raise click.BadOptionUsage(option_name='--mode',
message="Only 'full' mode is supported when deploying all network contracts")
# Confirm filesystem registry writes.
if os.path.isfile(local_registry.filepath):

View File

@ -111,7 +111,7 @@ def test_bare_contract_deployment_to_alternate_registry(click_runner, agency_loc
command = ('contracts',
'--contract-name', StakingEscrowDeployer.contract_name,
'--bare',
'--mode', 'bare',
'--provider', TEST_PROVIDER_URI,
'--registry-infile', agency_local_registry.filepath,
'--registry-outfile', ALTERNATE_REGISTRY_FILEPATH,