Installs new plumbing for --max-gas-price througout CLI and configuration modules.

pull/2445/head
Kieran Prasch 2020-12-23 12:49:16 -08:00 committed by David Núñez
parent 9e1433962e
commit 1cf48ede24
16 changed files with 159 additions and 89 deletions

View File

@ -155,7 +155,7 @@ class BlockchainInterface:
return message return message
def __init__(self, def __init__(self,
emitter = None, # TODO # 1754 emitter=None, # TODO # 1754
poa: bool = None, poa: bool = None,
light: bool = False, light: bool = False,
provider_uri: str = NO_BLOCKCHAIN_CONNECTION, provider_uri: str = NO_BLOCKCHAIN_CONNECTION,
@ -236,7 +236,7 @@ class BlockchainInterface:
self.is_light = light self.is_light = light
# FIXME: Not ready to give users total flexibility. Let's stick for the moment to known values. See #2447 # FIXME: Not ready to give users total flexibility. Let's stick for the moment to known values. See #2447
if gas_strategy not in ('slow', 'medium', 'fast', 'free', None): if gas_strategy not in ('slow', 'medium', 'fast', 'free', None): # FIXME: What is 'None' doing here?
raise ValueError(f"'{gas_strategy}' is an invalid gas strategy") raise ValueError(f"'{gas_strategy}' is an invalid gas strategy")
self.gas_strategy = gas_strategy or self.DEFAULT_GAS_STRATEGY self.gas_strategy = gas_strategy or self.DEFAULT_GAS_STRATEGY
self.max_gas_price = max_gas_price self.max_gas_price = max_gas_price
@ -285,27 +285,33 @@ class BlockchainInterface:
# self.client.add_middleware(middleware.latest_block_based_cache_middleware) # TODO: This line causes failed tests and nonce reuse in tests. See #2348. # self.client.add_middleware(middleware.latest_block_based_cache_middleware) # TODO: This line causes failed tests and nonce reuse in tests. See #2348.
self.client.add_middleware(middleware.simple_cache_middleware) self.client.add_middleware(middleware.simple_cache_middleware)
self.set_gas_strategy() self.configure_gas_strategy()
def configure_gas_strategy(self, gas_strategy: Optional[Callable] = None) -> None:
def set_gas_strategy(self, gas_strategy: Optional[Callable] = None):
if gas_strategy: if gas_strategy:
reported_gas_strategy = f"fixed/{gas_strategy.name}" reported_gas_strategy = f"fixed/{gas_strategy.name}"
elif isinstance(self.client, InfuraClient): elif isinstance(self.client, InfuraClient):
gas_strategy = construct_datafeed_median_strategy(speed=self.gas_strategy) gas_strategy = construct_datafeed_median_strategy(speed=self.gas_strategy)
reported_gas_strategy = f"datafeed/{self.gas_strategy}" reported_gas_strategy = f"datafeed/{self.gas_strategy}"
else: else:
reported_gas_strategy = f"web3/{self.gas_strategy}" reported_gas_strategy = f"web3/{self.gas_strategy}"
gas_strategy = self.get_gas_strategy(self.gas_strategy) gas_strategy = self.get_gas_strategy(self.gas_strategy)
message = f"Using gas strategy '{reported_gas_strategy}'"
configuration_message = f"Using gas strategy '{reported_gas_strategy}'"
if self.max_gas_price: if self.max_gas_price:
gas_strategy = max_price_gas_strategy_wrapper(gas_strategy=gas_strategy, __price = Web3.toWei(self.max_gas_price, 'gwei') # from gwei to wei
max_gas_price_wei=self.max_gas_price) gas_strategy = max_price_gas_strategy_wrapper(gas_strategy=gas_strategy, max_gas_price_wei=__price)
message += ", with a max price of {Web3.fromWei(self.max_gas_price_wei)} gwei" configuration_message += ", with a max price of {Web3.fromWei(self.max_gas_price_wei)} gwei."
self.client.set_gas_strategy(gas_strategy=gas_strategy) self.client.set_gas_strategy(gas_strategy=gas_strategy)
gwei_gas_price = Web3.fromWei(self.client.gas_price_for_transaction(), 'gwei') gwei_gas_price = Web3.fromWei(self.client.gas_price_for_transaction(), 'gwei')
self.log.debug(message + f". Currently, it returns a gas price of {gwei_gas_price} gwei")
self.log.info(configuration_message)
self.log.debug(f"Gas strategy currently reports a gas price of {gwei_gas_price} gwei.")
def connect(self): def connect(self):

View File

@ -59,7 +59,7 @@ from nucypher.cli.options import (
option_registry_filepath, option_registry_filepath,
option_signer_uri, option_signer_uri,
option_teacher_uri, option_teacher_uri,
option_lonely option_lonely, option_max_gas_price
) )
from nucypher.cli.painting.help import paint_new_installation_help from nucypher.cli.painting.help import paint_new_installation_help
from nucypher.cli.painting.help import ( from nucypher.cli.painting.help import (
@ -97,6 +97,7 @@ class AliceConfigOptions:
registry_filepath: str, registry_filepath: str,
middleware: RestMiddleware, middleware: RestMiddleware,
gas_strategy: str, gas_strategy: str,
max_gas_price: int, # gwei
signer_uri: str, signer_uri: str,
lonely: bool, lonely: bool,
): ):
@ -106,6 +107,7 @@ class AliceConfigOptions:
self.provider_uri = provider_uri self.provider_uri = provider_uri
self.signer_uri = signer_uri self.signer_uri = signer_uri
self.gas_strategy = gas_strategy self.gas_strategy = gas_strategy
self.max_gas_price = max_gas_price
self.federated_only = federated_only self.federated_only = federated_only
self.pay_with = pay_with self.pay_with = pay_with
self.discovery_port = discovery_port self.discovery_port = discovery_port
@ -131,6 +133,7 @@ class AliceConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
federated_only=True, federated_only=True,
lonely=self.lonely lonely=self.lonely
) )
@ -145,6 +148,7 @@ class AliceConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
filepath=config_file, filepath=config_file,
rest_port=self.discovery_port, rest_port=self.discovery_port,
checksum_address=self.pay_with, checksum_address=self.pay_with,
@ -165,6 +169,7 @@ group_config_options = group_options(
provider_uri=option_provider_uri(), provider_uri=option_provider_uri(),
signer_uri=option_signer_uri, signer_uri=option_signer_uri,
gas_strategy=option_gas_strategy, gas_strategy=option_gas_strategy,
max_gas_price=option_max_gas_price,
federated_only=option_federated_only, federated_only=option_federated_only,
discovery_port=option_discovery_port(), discovery_port=option_discovery_port(),
pay_with=option_pay_with, pay_with=option_pay_with,

View File

@ -48,7 +48,7 @@ from nucypher.cli.options import (
option_registry_filepath, option_registry_filepath,
option_signer_uri, option_signer_uri,
option_teacher_uri, option_teacher_uri,
option_lonely option_lonely, option_max_gas_price
) )
from nucypher.cli.painting.help import paint_new_installation_help from nucypher.cli.painting.help import paint_new_installation_help
from nucypher.cli.painting.policies import paint_single_card from nucypher.cli.painting.policies import paint_single_card
@ -74,6 +74,7 @@ class BobConfigOptions:
middleware: RestMiddleware, middleware: RestMiddleware,
federated_only: bool, federated_only: bool,
gas_strategy: str, gas_strategy: str,
max_gas_price: int,
signer_uri: str, signer_uri: str,
lonely: bool lonely: bool
): ):
@ -81,6 +82,7 @@ class BobConfigOptions:
self.provider_uri = provider_uri self.provider_uri = provider_uri
self.signer_uri = signer_uri self.signer_uri = signer_uri
self.gas_strategy = gas_strategy self.gas_strategy = gas_strategy
self.max_gas_price = max_gas_price
self.domain = network self.domain = network
self.registry_filepath = registry_filepath self.registry_filepath = registry_filepath
self.checksum_address = checksum_address self.checksum_address = checksum_address
@ -97,7 +99,8 @@ class BobConfigOptions:
dev_mode=True, dev_mode=True,
domain=TEMPORARY_DOMAIN, domain=TEMPORARY_DOMAIN,
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
gas_strategy=self.gas_strategy, # TODO: Fix type hint gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
federated_only=True, federated_only=True,
checksum_address=self.checksum_address, checksum_address=self.checksum_address,
@ -115,6 +118,7 @@ class BobConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
registry_filepath=self.registry_filepath, registry_filepath=self.registry_filepath,
network_middleware=self.middleware, network_middleware=self.middleware,
lonely=self.lonely lonely=self.lonely
@ -141,6 +145,7 @@ class BobConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
lonely=self.lonely lonely=self.lonely
) )
@ -152,6 +157,7 @@ class BobConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
lonely=self.lonely lonely=self.lonely
) )
# Depends on defaults being set on Configuration classes, filtrates None values # Depends on defaults being set on Configuration classes, filtrates None values
@ -163,6 +169,7 @@ group_config_options = group_options(
BobConfigOptions, BobConfigOptions,
provider_uri=option_provider_uri(), provider_uri=option_provider_uri(),
gas_strategy=option_gas_strategy, gas_strategy=option_gas_strategy,
max_gas_price=option_max_gas_price,
signer_uri=option_signer_uri, signer_uri=option_signer_uri,
network=option_network(), network=option_network(),
registry_filepath=option_registry_filepath, registry_filepath=option_registry_filepath,

View File

@ -16,12 +16,16 @@
""" """
import click import click
import json
import os import os
from nucypher.cli.options import option_gas_strategy, option_max_gas_price
try: try:
from nucypher.utilities.clouddeploy import CloudDeployers from nucypher.utilities.clouddeploy import CloudDeployers
except ImportError: except ImportError:
# FIXME: Do something more meaningful and conventional here.
# Locally scope the import instead or raising an
# exception similar to DevelopmentInstallationRequired.
CloudDeployers = None CloudDeployers = None
from nucypher.cli.utils import setup_emitter from nucypher.cli.utils import setup_emitter
from nucypher.config.characters import StakeHolderConfiguration from nucypher.config.characters import StakeHolderConfiguration
@ -45,6 +49,7 @@ def filter_staker_addresses(stakers, stakes):
def cloudworkers(): def cloudworkers():
"""Manage stakes and other staker-related operations.""" """Manage stakes and other staker-related operations."""
@cloudworkers.command('up') @cloudworkers.command('up')
@group_staker_options @group_staker_options
@option_config_file @option_config_file
@ -161,7 +166,7 @@ def add_for_stake(general_config, staker_options, config_file, staker_address, h
emitter = setup_emitter(general_config) emitter = setup_emitter(general_config)
STAKEHOLDER = staker_options.create_character(emitter, config_file) STAKEHOLDER = staker_options.create_character(emitter, config_file) # FIXME: NameErrors for 'staker options' and 'config_file'
stakers = STAKEHOLDER.get_stakers() stakers = STAKEHOLDER.get_stakers()
if not stakers: if not stakers:
@ -188,11 +193,13 @@ def add_for_stake(general_config, staker_options, config_file, staker_address, h
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True) @click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders') @click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet') @click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--gas-strategy', help="Which gas strategy? (glacial, slow, medium, fast)", type=click.STRING) @option_gas_strategy
@option_max_gas_price
@click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING) @click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING)
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[]) @click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@group_general_config @group_general_config
def deploy(general_config, remote_provider, nucypher_image, seed_network, wipe, prometheus, namespace, network, gas_strategy, include_hosts, envvars): def deploy(general_config, remote_provider, nucypher_image, seed_network, sentry_dsn, wipe, prometheus,
namespace, network, gas_strategy, max_gas_price, include_hosts, envvars):
"""Deploys NuCypher on managed hosts.""" """Deploys NuCypher on managed hosts."""
emitter = setup_emitter(general_config) emitter = setup_emitter(general_config)
@ -201,8 +208,19 @@ def deploy(general_config, remote_provider, nucypher_image, seed_network, wipe,
emitter.echo("Ansible is required to use `nucypher cloudworkers *` commands. (Please run 'pip install ansible'.)", color="red") emitter.echo("Ansible is required to use `nucypher cloudworkers *` commands. (Please run 'pip install ansible'.)", color="red")
return return
deployer = CloudDeployers.get_deployer('generic')(emitter, None, None, remote_provider, nucypher_image, seed_network, deployer = CloudDeployers.get_deployer('generic')(emitter,
prometheus=prometheus, namespace=namespace, network=network, gas_strategy=gas_strategy, envvars=envvars) None, # TODO: Why 'None' here? (overtly implicit)
None, # TODO: Convert to kwargs usage for maintainability.
remote_provider,
nucypher_image,
seed_network,
sentry_dsn,
prometheus=prometheus,
namespace=namespace,
network=network,
gas_strategy=gas_strategy,
max_gas_price=max_gas_price,
envvars=envvars)
hostnames = deployer.config['instances'].keys() hostnames = deployer.config['instances'].keys()
if include_hosts: if include_hosts:
@ -220,11 +238,13 @@ def deploy(general_config, remote_provider, nucypher_image, seed_network, wipe,
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True) @click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders') @click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet') @click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--gas-strategy', help="Which gas strategy? (glacial, slow, medium, fast)", type=click.STRING)
@click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING) @click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING)
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[]) @click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@option_gas_strategy
@option_max_gas_price
@group_general_config @group_general_config
def update(general_config, remote_provider, nucypher_image, seed_network, wipe, prometheus, namespace, network, gas_strategy, include_hosts, envvars): def update(general_config, remote_provider, nucypher_image, seed_network, sentry_dsn, wipe, prometheus,
namespace, network, gas_strategy, max_gas_price, include_hosts, envvars):
"""Updates existing installations of Nucypher on existing managed remote hosts.""" """Updates existing installations of Nucypher on existing managed remote hosts."""
emitter = setup_emitter(general_config) emitter = setup_emitter(general_config)
@ -234,9 +254,19 @@ def update(general_config, remote_provider, nucypher_image, seed_network, wipe,
return return
deployer = CloudDeployers.get_deployer('generic')( deployer = CloudDeployers.get_deployer('generic')(
emitter, None, None, remote_provider, nucypher_image, emitter,
None,
None,
remote_provider,
nucypher_image,
seed_network, seed_network,
prometheus=prometheus, namespace=namespace, network=network, gas_strategy=gas_strategy, envvars=envvars sentry_dsn,
prometheus=prometheus,
namespace=namespace,
network=network,
gas_strategy=gas_strategy,
max_gas_price=max_gas_price,
envvars=envvars
) )
emitter.echo(f"updating the following existing hosts:") emitter.echo(f"updating the following existing hosts:")

View File

@ -16,12 +16,12 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
""" """
import json import json
import os
from typing import Tuple
import click import click
import os
from constant_sorrow import constants from constant_sorrow import constants
from constant_sorrow.constants import FULL from constant_sorrow.constants import FULL
from typing import Tuple
from nucypher.blockchain.eth.actors import ContractAdministrator, Trustee from nucypher.blockchain.eth.actors import ContractAdministrator, Trustee
from nucypher.blockchain.eth.agents import ContractAgency, MultiSigAgent from nucypher.blockchain.eth.agents import ContractAgency, MultiSigAgent
@ -86,7 +86,7 @@ from nucypher.cli.options import (
option_poa, option_poa,
option_provider_uri, option_provider_uri,
option_signer_uri, option_signer_uri,
option_parameters) option_parameters, option_gas_strategy, option_max_gas_price)
from nucypher.cli.painting.deployment import ( from nucypher.cli.painting.deployment import (
paint_contract_deployment, paint_contract_deployment,
paint_deployer_contract_inspection, paint_deployer_contract_inspection,
@ -109,7 +109,6 @@ option_registry_infile = click.option('--registry-infile', help="Input path for
option_registry_outfile = click.option('--registry-outfile', help="Output path for contract registry file", type=click.Path(file_okay=True)) option_registry_outfile = click.option('--registry-outfile', help="Output path for contract registry file", type=click.Path(file_okay=True))
option_target_address = click.option('--target-address', help="Address of the target contract", type=EIP55_CHECKSUM_ADDRESS) option_target_address = click.option('--target-address', help="Address of the target contract", type=EIP55_CHECKSUM_ADDRESS)
option_gas = click.option('--gas', help="Operate with a specified gas per-transaction limit", type=click.IntRange(min=1)) option_gas = click.option('--gas', help="Operate with a specified gas per-transaction limit", type=click.IntRange(min=1))
option_gas_strategy = click.option('--gas-strategy', help="Operate with a specified gas price strategy", type=click.STRING) # TODO: GAS_STRATEGY_CHOICES
option_ignore_deployed = click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True) option_ignore_deployed = click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
option_ignore_solidity_version = click.option('--ignore-solidity-check', help="Ignore solidity version compatibility check", is_flag=True) option_ignore_solidity_version = click.option('--ignore-solidity-check', help="Ignore solidity version compatibility check", is_flag=True)
option_confirmations = click.option('--confirmations', help="Number of block confirmations to wait between transactions", type=click.IntRange(min=0), default=3) option_confirmations = click.option('--confirmations', help="Number of block confirmations to wait between transactions", type=click.IntRange(min=0), default=3)
@ -134,6 +133,7 @@ class ActorOptions:
se_test_mode, se_test_mode,
ignore_solidity_check, ignore_solidity_check,
gas_strategy: str, gas_strategy: str,
max_gas_price: int, # gwei
signer_uri: str, signer_uri: str,
network: str network: str
): ):
@ -141,6 +141,7 @@ class ActorOptions:
self.provider_uri = provider_uri self.provider_uri = provider_uri
self.signer_uri = signer_uri self.signer_uri = signer_uri
self.gas_strategy = gas_strategy self.gas_strategy = gas_strategy
self.max_gas_price = max_gas_price
self.deployer_address = deployer_address self.deployer_address = deployer_address
self.contract_name = contract_name self.contract_name = contract_name
self.registry_infile = registry_infile self.registry_infile = registry_infile
@ -165,7 +166,8 @@ class ActorOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
emitter=emitter, emitter=emitter,
ignore_solidity_check=self.ignore_solidity_check, ignore_solidity_check=self.ignore_solidity_check,
gas_strategy=self.gas_strategy) gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price)
# Warnings # Warnings
deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet) deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)
@ -228,6 +230,7 @@ group_actor_options = group_options(
ActorOptions, ActorOptions,
provider_uri=option_provider_uri(), provider_uri=option_provider_uri(),
gas_strategy=option_gas_strategy, gas_strategy=option_gas_strategy,
max_gas_price=option_max_gas_price,
signer_uri=option_signer_uri, signer_uri=option_signer_uri,
contract_name=option_contract_name(required=False), # TODO: Make this required see Issue #2314 contract_name=option_contract_name(required=False), # TODO: Make this required see Issue #2314
poa=option_poa, poa=option_poa,

View File

@ -273,7 +273,7 @@ class TransactingStakerOptions:
blockchain = self.staker_options.get_blockchain() blockchain = self.staker_options.get_blockchain()
if self.gas_price: # TODO: Consider performing this step in the init of EthereumClient if self.gas_price: # TODO: Consider performing this step in the init of EthereumClient
fixed_price_strategy = construct_fixed_price_gas_strategy(gas_price=self.gas_price, denomination="gwei") fixed_price_strategy = construct_fixed_price_gas_strategy(gas_price=self.gas_price, denomination="gwei")
blockchain.set_gas_strategy(fixed_price_strategy) blockchain.configure_gas_strategy(fixed_price_strategy)
return blockchain return blockchain

View File

@ -58,7 +58,7 @@ from nucypher.cli.options import (
option_registry_filepath, option_registry_filepath,
option_signer_uri, option_signer_uri,
option_teacher_uri, option_teacher_uri,
option_lonely option_lonely, option_max_gas_price
) )
from nucypher.cli.painting.help import paint_new_installation_help from nucypher.cli.painting.help import paint_new_installation_help
from nucypher.cli.painting.transactions import paint_receipt_summary from nucypher.cli.painting.transactions import paint_receipt_summary
@ -79,20 +79,21 @@ class UrsulaConfigOptions:
__option_name__ = 'config_options' __option_name__ = 'config_options'
def __init__(self, def __init__(self,
provider_uri, provider_uri: str,
worker_address, worker_address: str,
federated_only, federated_only: bool,
rest_host, rest_host: str,
rest_port, rest_port: int,
db_filepath, db_filepath: str,
network, network: str,
registry_filepath, registry_filepath: str,
dev, dev: bool,
poa, poa: bool,
light, light: bool,
gas_strategy, gas_strategy: str,
signer_uri, max_gas_price: int, # gwei
availability_check, signer_uri: str,
availability_check: bool,
lonely: bool lonely: bool
): ):
@ -114,6 +115,7 @@ class UrsulaConfigOptions:
self.poa = poa self.poa = poa
self.light = light self.light = light
self.gas_strategy = gas_strategy self.gas_strategy = gas_strategy
self.max_gas_price = max_gas_price
self.availability_check = availability_check self.availability_check = availability_check
self.lonely = lonely self.lonely = lonely
@ -129,6 +131,7 @@ class UrsulaConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
checksum_address=self.worker_address, checksum_address=self.worker_address,
federated_only=self.federated_only, federated_only=self.federated_only,
rest_host=self.rest_host, rest_host=self.rest_host,
@ -146,6 +149,7 @@ class UrsulaConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
rest_host=self.rest_host, rest_host=self.rest_host,
rest_port=self.rest_port, rest_port=self.rest_port,
db_filepath=self.db_filepath, db_filepath=self.db_filepath,
@ -195,6 +199,7 @@ class UrsulaConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
poa=self.poa, poa=self.poa,
light=self.light, light=self.light,
availability_check=self.availability_check) availability_check=self.availability_check)
@ -210,6 +215,7 @@ class UrsulaConfigOptions:
provider_uri=self.provider_uri, provider_uri=self.provider_uri,
signer_uri=self.signer_uri, signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price,
poa=self.poa, poa=self.poa,
light=self.light, light=self.light,
availability_check=self.availability_check) availability_check=self.availability_check)
@ -223,6 +229,7 @@ group_config_options = group_options(
provider_uri=option_provider_uri(), provider_uri=option_provider_uri(),
signer_uri=option_signer_uri, signer_uri=option_signer_uri,
gas_strategy=option_gas_strategy, gas_strategy=option_gas_strategy,
max_gas_price=option_max_gas_price,
worker_address=click.option('--worker-address', help="Run the worker-ursula with a specified address", type=EIP55_CHECKSUM_ADDRESS), worker_address=click.option('--worker-address', help="Run the worker-ursula with a specified address", type=EIP55_CHECKSUM_ADDRESS),
federated_only=option_federated_only, federated_only=option_federated_only,
rest_host=click.option('--rest-host', help="The host IP address to run Ursula network services on", type=click.STRING), rest_host=click.option('--rest-host', help="The host IP address to run Ursula network services on", type=click.STRING),

View File

@ -46,7 +46,9 @@ option_etherscan = click.option('--etherscan/--no-etherscan', help="Enable/disab
option_event_name = click.option('--event-name', help="Specify an event by name", type=click.STRING) option_event_name = click.option('--event-name', help="Specify an event by name", type=click.STRING)
option_federated_only = click.option('--federated-only/--decentralized', '-F', help="Connect only to federated nodes", is_flag=True, default=None) option_federated_only = click.option('--federated-only/--decentralized', '-F', help="Connect only to federated nodes", is_flag=True, default=None)
option_force = click.option('--force', help="Don't ask for confirmation", is_flag=True) option_force = click.option('--force', help="Don't ask for confirmation", is_flag=True)
option_gas_price = click.option('--gas-price', help="Use this gas price (in GWEI)", type=GWEI) option_gas_price = click.option('--gas-price', help="Set a static gas price (in GWEI)", type=GWEI)
option_gas_strategy = click.option('--gas-strategy', help="Operate with a specified gas price strategy", type=click.STRING) # TODO: GAS_STRATEGY_CHOICES
option_max_gas_price = click.option('--max-gas-price', help="Maximum acceptable gas price in Gwei", type=GWEI)
option_hw_wallet = click.option('--hw-wallet/--no-hw-wallet') option_hw_wallet = click.option('--hw-wallet/--no-hw-wallet')
option_light = click.option('--light', help="Indicate that node is light", is_flag=True, default=None) option_light = click.option('--light', help="Indicate that node is light", is_flag=True, default=None)
option_lonely = click.option('--lonely', help="Do not connect to seednodes", is_flag=True) option_lonely = click.option('--lonely', help="Do not connect to seednodes", is_flag=True)

View File

@ -176,14 +176,16 @@ def initialize_deployer_interface(emitter: StdoutEmitter,
poa: bool, poa: bool,
provider_uri, provider_uri,
ignore_solidity_check: bool, ignore_solidity_check: bool,
gas_strategy: str = None gas_strategy: str = None,
max_gas_price: int = None
) -> BlockchainDeployerInterface: ) -> BlockchainDeployerInterface:
if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri): if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
deployer_interface = BlockchainDeployerInterface(provider_uri=provider_uri, deployer_interface = BlockchainDeployerInterface(provider_uri=provider_uri,
poa=poa, poa=poa,
ignore_solidity_check=ignore_solidity_check, ignore_solidity_check=ignore_solidity_check,
gas_strategy=gas_strategy) gas_strategy=gas_strategy,
max_gas_price=max_gas_price)
BlockchainInterfaceFactory.register_interface(interface=deployer_interface, emitter=emitter) BlockchainInterfaceFactory.register_interface(interface=deployer_interface, emitter=emitter)
else: else:
deployer_interface = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri) deployer_interface = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)

View File

@ -69,12 +69,15 @@ class CharacterConfiguration(BaseConfiguration):
# Gas # Gas
DEFAULT_GAS_STRATEGY = 'fast' DEFAULT_GAS_STRATEGY = 'fast'
# Fields specified here are *not* passed into the Character's constructor
# and can be understood as configuration fields only.
_CONFIG_FIELDS = ('config_root', _CONFIG_FIELDS = ('config_root',
'poa', 'poa',
'light', 'light',
'provider_uri', 'provider_uri',
'registry_filepath', 'registry_filepath',
'gas_strategy', 'gas_strategy',
'max_gas_price', # gwei
'signer_uri') 'signer_uri')
def __init__(self, def __init__(self,
@ -127,7 +130,8 @@ class CharacterConfiguration(BaseConfiguration):
registry_filepath: str = None, registry_filepath: str = None,
# Deployed Workers # Deployed Workers
worker_data: dict = None): worker_data: dict = None
):
self.log = Logger(self.__class__.__name__) self.log = Logger(self.__class__.__name__)
UNINITIALIZED_CONFIGURATION.bool_value(False) UNINITIALIZED_CONFIGURATION.bool_value(False)
@ -212,14 +216,14 @@ class CharacterConfiguration(BaseConfiguration):
else: else:
self.gas_strategy = gas_strategy self.gas_strategy = gas_strategy
self.max_gas_price = Web3.toWei(max_gas_price, 'gwei') self.max_gas_price = max_gas_price # gwei
is_initialized = BlockchainInterfaceFactory.is_interface_initialized(provider_uri=self.provider_uri) is_initialized = BlockchainInterfaceFactory.is_interface_initialized(provider_uri=self.provider_uri)
if not is_initialized and provider_uri: if not is_initialized and provider_uri:
BlockchainInterfaceFactory.initialize_interface(provider_uri=self.provider_uri, BlockchainInterfaceFactory.initialize_interface(provider_uri=self.provider_uri,
poa=self.poa, poa=self.poa,
light=self.is_light, light=self.is_light,
emitter=emitter, emitter=emitter,
gas_strategy=gas_strategy, gas_strategy=self.gas_strategy,
max_gas_price=self.max_gas_price) max_gas_price=self.max_gas_price)
else: else:
self.log.warn(f"Using existing blockchain interface connection ({self.provider_uri}).") self.log.warn(f"Using existing blockchain interface connection ({self.provider_uri}).")

View File

@ -16,30 +16,28 @@
""" """
import copy import copy
import os
from pathlib import Path
import re
import json import json
import maya
import time
from base64 import b64encode
from mako.template import Template
import requests
from ansible.playbook import Playbook import maya
from ansible.parsing.dataloader import DataLoader import os
from ansible.executor.task_queue_manager import TaskQueueManager import re
import requests
import time
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.inventory.manager import InventoryManager from ansible.inventory.manager import InventoryManager
from ansible.module_utils.common.collections import ImmutableDict
from ansible.parsing.dataloader import DataLoader
from ansible.plugins.callback import CallbackBase from ansible.plugins.callback import CallbackBase
from ansible.vars.manager import VariableManager from ansible.vars.manager import VariableManager
from ansible.playbook.play import Play from base64 import b64encode
from ansible.executor.playbook_executor import PlaybookExecutor from mako.template import Template
from ansible import context as ansible_context from pathlib import Path
from ansible.module_utils.common.collections import ImmutableDict
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, DEPLOY_DIR, NUCYPHER_ENVVAR_KEYRING_PASSWORD, NUCYPHER_ENVVAR_WORKER_ETH_PASSWORD from ansible import context as ansible_context
from nucypher.blockchain.eth.clients import PUBLIC_CHAINS from nucypher.blockchain.eth.clients import PUBLIC_CHAINS
from nucypher.blockchain.eth.networks import NetworksInventory from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, DEPLOY_DIR, NUCYPHER_ENVVAR_KEYRING_PASSWORD, \
NUCYPHER_ENVVAR_WORKER_ETH_PASSWORD
NODE_CONFIG_STORAGE_KEY = 'worker-configs' NODE_CONFIG_STORAGE_KEY = 'worker-configs'
URSULA_PORT = 9151 URSULA_PORT = 9151
@ -167,22 +165,24 @@ class BaseCloudNodeConfigurator:
PROMETHEUS_PORT = PROMETHEUS_PORTS[0] PROMETHEUS_PORT = PROMETHEUS_PORTS[0]
def __init__(self, def __init__(self, # TODO: Add type annotations
emitter, emitter,
stakeholder, stakeholder,
stakeholder_config_path, stakeholder_config_path,
blockchain_provider=None, blockchain_provider=None,
nucypher_image=None, nucypher_image=None,
seed_network=False, seed_network=False,
profile=None, sentry_dsn=None,
prometheus=False, profile=None,
pre_config=False, prometheus=False,
network=None, pre_config=False,
namespace=None, network=None,
gas_strategy=None, namespace=None,
action=None, gas_strategy=None,
envvars=None, max_gas_price=None,
): action=None,
envvars=None
):
self.emitter = emitter self.emitter = emitter
self.stakeholder = stakeholder self.stakeholder = stakeholder
@ -236,11 +236,13 @@ class BaseCloudNodeConfigurator:
'blockchain_provider': blockchain_provider, 'blockchain_provider': blockchain_provider,
'nucypher_image': nucypher_image, 'nucypher_image': nucypher_image,
'gas_strategy': f'--gas-strategy {gas_strategy}' if gas_strategy else '', 'gas_strategy': f'--gas-strategy {gas_strategy}' if gas_strategy else '',
'max_gas_price': f'--max-gas-price {max_gas_price}' if max_gas_price else '',
} }
self.config['blockchain_provider'] = blockchain_provider or self.config.get('blockchain_provider') or f'/root/.local/share/geth/.ethereum/{self.chain_name}/geth.ipc' # the default for nodes that run their own geth container self.config['blockchain_provider'] = blockchain_provider or self.config.get('blockchain_provider') or f'/root/.local/share/geth/.ethereum/{self.chain_name}/geth.ipc' # the default for nodes that run their own geth container
self.config['nucypher_image'] = nucypher_image or self.config.get('nucypher_image') or 'nucypher/nucypher:latest' self.config['nucypher_image'] = nucypher_image or self.config.get('nucypher_image') or 'nucypher/nucypher:latest'
self.config['gas_strategy'] = f'--gas-strategy {gas_strategy}' if gas_strategy else self.config.get('gas-strategy', '') self.config['gas_strategy'] = f'--gas-strategy {gas_strategy}' if gas_strategy else self.config.get('gas-strategy', '')
self.config['max_gas_price'] = f'--max-gas-price {max_gas_price}' if max_gas_price else self.config.get('max-gas-price', '')
self.config['seed_network'] = seed_network if seed_network is not None else self.config.get('seed_network') self.config['seed_network'] = seed_network if seed_network is not None else self.config.get('seed_network')
if not self.config['seed_network']: if not self.config['seed_network']:

View File

@ -44,8 +44,7 @@ def test_deployer_interface_multiversion_contract():
# Prepare chain # Prepare chain
BlockchainInterfaceFactory._interfaces.clear() BlockchainInterfaceFactory._interfaces.clear()
blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm', blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm', gas_strategy='free')
gas_strategy='free')
blockchain_interface.connect() blockchain_interface.connect()
BlockchainInterfaceFactory.register_interface(interface=blockchain_interface) # Lets this test run in isolation BlockchainInterfaceFactory.register_interface(interface=blockchain_interface) # Lets this test run in isolation

View File

@ -107,8 +107,7 @@ def test_multiversion_contract():
BlockchainDeployerInterface.GAS_STRATEGIES = {**BlockchainDeployerInterface.GAS_STRATEGIES, BlockchainDeployerInterface.GAS_STRATEGIES = {**BlockchainDeployerInterface.GAS_STRATEGIES,
'free': free_gas_price_strategy} 'free': free_gas_price_strategy}
blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm/2', blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm/2', gas_strategy='free')
gas_strategy='free')
blockchain_interface.connect(compile_now=False) blockchain_interface.connect(compile_now=False)
blockchain_interface._raw_contract_cache = compiled_contracts blockchain_interface._raw_contract_cache = compiled_contracts

View File

@ -113,8 +113,7 @@ def test_upgradeability(temp_dir_path):
provider_uri = 'tester://pyevm/2' # TODO: Testerchain caching Issues provider_uri = 'tester://pyevm/2' # TODO: Testerchain caching Issues
try: try:
blockchain_interface = BlockchainDeployerInterface(provider_uri=provider_uri, blockchain_interface = BlockchainDeployerInterface(provider_uri=provider_uri, gas_strategy='free')
gas_strategy='free')
blockchain_interface.connect() blockchain_interface.connect()
origin = blockchain_interface.client.accounts[0] origin = blockchain_interface.client.accounts[0]
BlockchainInterfaceFactory.register_interface(interface=blockchain_interface) BlockchainInterfaceFactory.register_interface(interface=blockchain_interface)

View File

@ -82,6 +82,7 @@ DURATION: datetime.timedelta = datetime.timedelta(days=1)
DEFAULT_ITERATIONS = 1 # `None` will run forever DEFAULT_ITERATIONS = 1 # `None` will run forever
SAMPLE_RATE: int = 15 # seconds SAMPLE_RATE: int = 15 # seconds
GAS_STRATEGY: str = 'fast' GAS_STRATEGY: str = 'fast'
MAX_GAS_PRICE: int = 200 # gwei
LABEL_PREFIX = 'random-metrics-label-' LABEL_PREFIX = 'random-metrics-label-'
LABEL_SUFFIXER = lambda: os.urandom(16).hex() LABEL_SUFFIXER = lambda: os.urandom(16).hex()
HANDPICKED_URSULA_URIS: List[str] = [ HANDPICKED_URSULA_URIS: List[str] = [
@ -169,7 +170,8 @@ def make_alice(known_nodes: Optional[Set[Ursula]] = None):
start_learning_now=False, start_learning_now=False,
federated_only=False, federated_only=False,
learn_on_same_thread=True, learn_on_same_thread=True,
gas_strategy=GAS_STRATEGY gas_strategy=GAS_STRATEGY,
max_gas_price=MAX_GAS_PRICE,
) )
alice_config.initialize(password=INSECURE_PASSWORD) alice_config.initialize(password=INSECURE_PASSWORD)

View File

@ -14,6 +14,8 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>. along with nucypher. If not, see <https://www.gnu.org/licenses/>.
""" """
from collections import Callable from collections import Callable
from statistics import median from statistics import median
from unittest.mock import patch from unittest.mock import patch
@ -30,7 +32,8 @@ from nucypher.utilities.datafeeds import (
UpvestGasPriceDatafeed, UpvestGasPriceDatafeed,
ZoltuGasPriceDatafeed ZoltuGasPriceDatafeed
) )
from nucypher.utilities.gas_strategies import construct_datafeed_median_strategy, construct_datafeed_fallback_strategy from nucypher.utilities.gas_strategies import construct_datafeed_median_strategy
etherchain_json = { etherchain_json = {
"safeLow": "99.0", "safeLow": "99.0",