Implements signer URI for remaining CLI and configuration entrypoints: Alice, Bob, Ursula, Worklock, etc.

pull/1664/head
Kieran Prasch 2020-03-23 13:09:01 -07:00
parent 878a243246
commit fe1c4703aa
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
10 changed files with 82 additions and 42 deletions

View File

@ -72,7 +72,7 @@ from nucypher.blockchain.eth.registry import (
BaseContractRegistry,
IndividualAllocationRegistry
)
from nucypher.blockchain.eth.signers import ClefSigner, Web3Signer
from nucypher.blockchain.eth.signers import ClefSigner, Web3Signer, Signer
from nucypher.blockchain.eth.token import NU, Stake, StakeList, WorkTracker
from nucypher.blockchain.eth.utils import datetime_to_period, calculate_period_duration, datetime_at_period, \
prettify_eth_amount
@ -194,27 +194,30 @@ class ContractAdministrator(NucypherTokenActor):
registry: BaseContractRegistry,
deployer_address: str = None,
client_password: str = None,
signer: Signer = None,
staking_escrow_test_mode: bool = False,
economics: BaseEconomics = None):
"""
Note: super() is not called here to avoid setting the token agent.
TODO: Review this logic ^^ "bare mode". #1510
Note: super() is not called here to avoid setting the token agent. TODO: call super but use "bare mode" without token agent. #1510
"""
self.log = Logger("Deployment-Actor")
self.deployer_address = deployer_address
self.checksum_address = self.deployer_address
self.economics = economics or StandardTokenEconomics()
self.staking_escrow_test_mode = staking_escrow_test_mode
self.registry = registry
self.preallocation_escrow_deployers = dict()
self.deployers = {d.contract_name: d for d in self.all_deployer_classes}
self.deployer_power = TransactingPower(password=client_password,
account=deployer_address, cache=True)
# Powers
self.deployer_power = TransactingPower(signer=signer,
password=client_password,
account=deployer_address,
cache=True)
self.transacting_power = self.deployer_power
self.transacting_power.activate()
self.staking_escrow_test_mode = staking_escrow_test_mode
self.sidekick_power = None
self.sidekick_address = None
@ -1526,7 +1529,9 @@ class StakeHolder(Staker):
try:
transacting_power = self.__transacting_powers[checksum_address]
except KeyError:
transacting_power = TransactingPower(password=password, account=checksum_address)
transacting_power = TransactingPower(signer=self.__signer,
password=password,
account=checksum_address)
self.__transacting_powers[checksum_address] = transacting_power
transacting_power.activate(password=password)
@ -1664,17 +1669,20 @@ class Bidder(NucypherTokenActor):
@validate_checksum_address
def __init__(self,
checksum_address: str,
is_transacting: bool = True,
signer: Signer = None,
client_password: str = None,
*args, **kwargs):
super().__init__(checksum_address=checksum_address, *args, **kwargs)
self.log = Logger(f"WorkLockBidder")
self.worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=self.registry) # type: WorkLockAgent
self.staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=self.registry)
self.economics = EconomicsFactory.get_economics(registry=self.registry)
if is_transacting:
self.transacting_power = TransactingPower(password=client_password, account=checksum_address)
if signer:
self.transacting_power = TransactingPower(signer=signer,
password=client_password,
account=checksum_address)
self.transacting_power.activate()
self._all_bonus_bidders = None

View File

@ -23,6 +23,7 @@ from geth.process import BaseGethProcess
from twisted.logger import Logger
from web3 import Web3
from nucypher.blockchain.eth.signers import ClefSigner
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, DEPLOY_DIR, USER_LOG_DIR
UNKNOWN_DEVELOPMENT_CHAIN_ID.bool_value(True)

View File

@ -7,9 +7,7 @@ from hexbytes import HexBytes
from twisted.logger import Logger
from web3 import Web3, IPCProvider
from nucypher.blockchain.eth.clients import EthereumClient
from nucypher.blockchain.eth.decorators import validate_checksum_address
from nucypher.blockchain.eth.interfaces import BlockchainInterface, BlockchainInterfaceFactory
class Signer(ABC):
@ -57,12 +55,14 @@ class Signer(ABC):
class Web3Signer(Signer):
def __init__(self, client: EthereumClient):
def __init__(self, client):
super().__init__()
self.__client = client
@classmethod
def from_signer_uri(cls, uri: str) -> 'Web3Signer':
from nucypher.blockchain.eth.interfaces import BlockchainInterface, BlockchainInterfaceFactory
try:
blockchain = BlockchainInterfaceFactory.get_or_create_interface(provider_uri=uri)
except BlockchainInterface.UnsupportedProvider:
@ -150,14 +150,14 @@ class ClefSigner(Signer):
return checksum_addresses
@validate_checksum_address
def sign_transaction(self, account: str, transaction_dict: dict) -> HexBytes:
def sign_transaction(self, transaction_dict: dict) -> HexBytes:
formatters = {
'nonce': Web3.toHex,
'gasPrice': Web3.toHex,
'gas': Web3.toHex,
'value': Web3.toHex,
'chainId': Web3.toHex,
'from': to_normalized_address
'from': to_checksum_address
}
transaction_dict = apply_formatters_to_dict(formatters, transaction_dict)
signed = self.w3.manager.request_blocking("account_signTransaction", [transaction_dict])

View File

@ -49,7 +49,7 @@ from nucypher.cli.options import (
option_provider_uri,
option_registry_filepath,
option_teacher_uri,
option_rate)
option_rate, option_signer_uri)
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS
from nucypher.config.characters import AliceConfiguration
from nucypher.config.constants import NUCYPHER_ENVVAR_ALICE_ETH_PASSWORD
@ -72,7 +72,7 @@ class AliceConfigOptions:
__option_name__ = 'config_options'
def __init__(self, dev, network, provider_uri, geth, federated_only, discovery_port,
pay_with, registry_filepath, middleware, gas_strategy):
pay_with, registry_filepath, middleware, gas_strategy, signer_uri):
if federated_only and geth:
raise click.BadOptionUsage(
@ -88,6 +88,7 @@ class AliceConfigOptions:
self.dev = dev
self.domains = {network} if network else None
self.provider_uri = provider_uri
self.signer_uri = signer_uri
self.gas_strategy = gas_strategy
self.geth = geth
self.federated_only = federated_only
@ -114,6 +115,7 @@ class AliceConfigOptions:
domains={TEMPORARY_DOMAIN},
provider_process=self.eth_node,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
federated_only=True)
@ -126,6 +128,7 @@ class AliceConfigOptions:
domains=self.domains,
provider_process=self.eth_node,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
filepath=config_file,
rest_port=self.discovery_port,
@ -143,6 +146,7 @@ group_config_options = group_options(
dev=option_dev,
network=option_network,
provider_uri=option_provider_uri(),
signer_uri=option_signer_uri,
gas_strategy=option_gas_strategy,
geth=option_geth,
federated_only=option_federated_only,
@ -188,6 +192,7 @@ class AliceFullConfigOptions:
domains=opts.domains,
federated_only=opts.federated_only,
provider_uri=opts.provider_uri,
signer_uri=opts.signer_uri,
provider_process=opts.eth_node,
registry_filepath=opts.registry_filepath,
poa=self.poa,
@ -202,6 +207,7 @@ class AliceFullConfigOptions:
domains=opts.domains,
federated_only=opts.federated_only,
provider_uri=opts.provider_uri,
signer_uri=opts.signer_uri,
registry_filepath=opts.registry_filepath,
poa=self.poa,
light=self.light,

View File

@ -23,7 +23,7 @@ from nucypher.cli.options import (
option_provider_uri,
option_registry_filepath,
option_teacher_uri,
)
option_signer_uri)
from nucypher.config.characters import BobConfiguration
from nucypher.crypto.powers import DecryptingPower
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
@ -33,10 +33,11 @@ class BobConfigOptions:
__option_name__ = 'config_options'
def __init__(self, provider_uri, network, registry_filepath,
checksum_address, discovery_port, dev, middleware, federated_only, gas_strategy):
def __init__(self, provider_uri, network, registry_filepath, checksum_address, discovery_port,
dev, middleware, federated_only, gas_strategy, signer_uri):
self.provider_uri = provider_uri
self.signer_uri = signer_uri
self.gas_strategy = gas_strategy,
self.domains = {network} if network else None
self.registry_filepath = registry_filepath
@ -54,6 +55,7 @@ class BobConfigOptions:
domains={TEMPORARY_DOMAIN},
provider_uri=self.provider_uri,
gas_strategy=self.gas_strategy,
signer_uri=self.signer_uri,
federated_only=True,
checksum_address=self.checksum_address,
network_middleware=self.middleware)
@ -66,6 +68,7 @@ class BobConfigOptions:
checksum_address=self.checksum_address,
rest_port=self.discovery_port,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
registry_filepath=self.registry_filepath,
network_middleware=self.middleware)
@ -90,6 +93,7 @@ class BobConfigOptions:
federated_only=self.federated_only,
registry_filepath=self.registry_filepath,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
)
@ -99,6 +103,7 @@ class BobConfigOptions:
federated_only=self.federated_only,
registry_filepath=self.registry_filepath,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy
)
# Depends on defaults being set on Configuration classes, filtrates None values
@ -110,6 +115,7 @@ group_config_options = group_options(
BobConfigOptions,
provider_uri=option_provider_uri(),
gas_strategy=option_gas_strategy,
signer_uri=option_signer_uri,
network=option_network,
registry_filepath=option_registry_filepath,
checksum_address=option_checksum_address,

View File

@ -52,8 +52,8 @@ from nucypher.cli.options import (
option_hw_wallet,
option_poa,
option_provider_uri,
option_contract_name
)
option_contract_name,
option_signer_uri)
from nucypher.cli.painting import (
echo_solidity_version,
paint_staged_deployment,
@ -123,8 +123,9 @@ class ActorOptions:
def __init__(self, provider_uri, deployer_address, contract_name,
registry_infile, registry_outfile, hw_wallet, dev, force, poa, config_root, etherscan,
se_test_mode, ignore_solidity_check, gas_strategy):
se_test_mode, ignore_solidity_check, gas_strategy, signer_uri):
self.provider_uri = provider_uri
self.signer_uri = signer_uri
self.gas_strategy = gas_strategy
self.deployer_address = deployer_address
self.contract_name = contract_name
@ -194,6 +195,7 @@ group_actor_options = group_options(
ActorOptions,
provider_uri=option_provider_uri(),
gas_strategy=option_gas_strategy,
signer_uri=option_signer_uri,
contract_name=option_contract_name,
poa=option_poa,
force=option_force,

View File

@ -49,18 +49,18 @@ from nucypher.cli.options import (
option_provider_uri,
option_registry_filepath,
option_staking_address,
)
option_signer_uri)
from nucypher.cli.painting import paint_receipt_summary
from nucypher.cli.types import (
EIP55_CHECKSUM_ADDRESS,
EXISTING_READABLE_FILE,
WEI)
WEI
)
from nucypher.config.characters import StakeHolderConfiguration
option_value = click.option('--value', help="Token value of stake", type=click.INT)
option_lock_periods = click.option('--lock-periods', help="Duration of stake in periods.", type=click.INT)
option_worker_address = click.option('--worker-address', help="Address to assign as an Ursula-Worker", type=EIP55_CHECKSUM_ADDRESS)
option_signer_uri = click.option('--signer', 'signer_uri', '-S', default=None, type=str)
def _setup_emitter(general_config):
@ -175,7 +175,7 @@ group_staker_options = group_options(
StakerOptions,
config_options=group_config_options,
staking_address=option_staking_address,
)
)
class TransactingStakerOptions:

View File

@ -51,7 +51,7 @@ from nucypher.cli.options import (
option_provider_uri,
option_registry_filepath,
option_teacher_uri,
)
option_signer_uri)
from nucypher.cli.processes import UrsulaCommandProtocol
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS, NETWORK_PORT
from nucypher.config.characters import UrsulaConfiguration
@ -65,7 +65,7 @@ class UrsulaConfigOptions:
__option_name__ = 'config_options'
def __init__(self, geth, provider_uri, worker_address, federated_only, rest_host,
rest_port, db_filepath, network, registry_filepath, dev, poa, light, gas_strategy):
rest_port, db_filepath, network, registry_filepath, dev, poa, light, gas_strategy, signer_uri):
if federated_only:
# TODO: consider rephrasing in a more universal voice.
@ -85,6 +85,7 @@ class UrsulaConfigOptions:
self.eth_node = eth_node
self.provider_uri = provider_uri
self.signer_uri = signer_uri
self.worker_address = worker_address
self.federated_only = federated_only
self.rest_host = rest_host
@ -108,6 +109,7 @@ class UrsulaConfigOptions:
registry_filepath=self.registry_filepath,
provider_process=self.eth_node,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
checksum_address=self.worker_address,
federated_only=self.federated_only,
@ -123,6 +125,7 @@ class UrsulaConfigOptions:
registry_filepath=self.registry_filepath,
provider_process=self.eth_node,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
rest_host=self.rest_host,
rest_port=self.rest_port,
@ -170,6 +173,7 @@ class UrsulaConfigOptions:
registry_filepath=self.registry_filepath,
provider_process=self.eth_node,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
poa=self.poa,
light=self.light)
@ -183,6 +187,7 @@ class UrsulaConfigOptions:
checksum_address=self.worker_address,
registry_filepath=self.registry_filepath,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
gas_strategy=self.gas_strategy,
poa=self.poa,
light=self.light)
@ -195,6 +200,7 @@ group_config_options = group_options(
UrsulaConfigOptions,
geth=option_geth,
provider_uri=option_provider_uri(),
signer_uri=option_signer_uri,
gas_strategy=option_gas_strategy,
worker_address=click.option('--worker-address', help="Run the worker-ursula with a specified address", type=EIP55_CHECKSUM_ADDRESS),
federated_only=option_federated_only,
@ -205,7 +211,8 @@ group_config_options = group_options(
registry_filepath=option_registry_filepath,
poa=option_poa,
light=option_light,
dev=option_dev)
dev=option_dev
)
class UrsulaCharacterOptions:

View File

@ -15,27 +15,30 @@ You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
from decimal import Decimal
from typing import Optional
import click
import maya
import tabulate
from decimal import Decimal
from web3 import Web3
from nucypher.blockchain.eth.actors import Bidder
from nucypher.blockchain.eth.agents import WorkLockAgent, ContractAgency
from nucypher.blockchain.eth.agents import ContractAgency, WorkLockAgent
from nucypher.blockchain.eth.signers import Signer
from nucypher.blockchain.eth.token import NU
from nucypher.blockchain.eth.utils import prettify_eth_amount
from nucypher.characters.banners import WORKLOCK_BANNER
from nucypher.cli.actions import get_client_password
from nucypher.cli.actions import select_client_account
from nucypher.cli.commands.status import group_registry_options
from nucypher.cli.config import group_general_config
from nucypher.cli.options import (
option_force,
group_options,
option_hw_wallet
option_hw_wallet,
option_signer_uri
)
from nucypher.cli.actions import get_client_password
from nucypher.cli.painting import (
paint_receipt_summary,
paint_worklock_status,
@ -60,29 +63,35 @@ class WorkLockOptions:
__option_name__ = 'worklock_options'
def __init__(self, bidder_address: str):
def __init__(self, bidder_address: str, signer_uri):
self.bidder_address = bidder_address
self.signer_uri = signer_uri
def __create_bidder(self, registry, transacting: bool = False, hw_wallet: bool = False):
def __create_bidder(self, registry, signer: Optional[Signer] = None, hw_wallet: bool = False):
client_password = None
if transacting and not hw_wallet:
client_password = get_client_password(checksum_address=self.bidder_address)
if signer:
# and not hw_wallet: # TODO: ...mabye?
client_password = None
if signer.is_device(self.bidder_address):
client_password = get_client_password(checksum_address=self.bidder_address)
bidder = Bidder(checksum_address=self.bidder_address,
registry=registry,
client_password=client_password,
is_transacting=transacting)
signer=signer)
return bidder
def create_bidder(self, registry, hw_wallet: bool = False):
return self.__create_bidder(registry, transacting=True, hw_wallet=hw_wallet)
signer = Signer.from_signer_uri(self.signer_uri) if self.signer_uri else None
return self.__create_bidder(registry=registry, signer=signer, hw_wallet=hw_wallet)
def create_transactionless_bidder(self, registry):
return self.__create_bidder(registry, transacting=False)
return self.__create_bidder(registry)
group_worklock_options = group_options(
WorkLockOptions,
bidder_address=option_bidder_address
bidder_address=option_bidder_address,
signer_uri=option_signer_uri
)

View File

@ -190,3 +190,4 @@ option_middleware = wrap_option(
process_middleware,
mock_networking=click.option('-Z', '--mock-networking', help="Use in-memory transport instead of networking", count=True),
)
option_signer_uri = click.option('--signer', 'signer_uri', '-S', default=None, type=str)