mirror of https://github.com/nucypher/nucypher.git
Attaching the integrated provider process to config and blockchain classes
parent
600decc8b4
commit
ad84a526bb
|
@ -89,7 +89,7 @@ class NucypherTokenActor:
|
|||
self.checksum_public_address = checksum_address # type: str
|
||||
|
||||
if blockchain is None:
|
||||
blockchain = Blockchain.connect()
|
||||
blockchain = Blockchain.connect() # Attempt to connect
|
||||
self.blockchain = blockchain
|
||||
|
||||
self.token_agent = NucypherTokenAgent()
|
||||
|
|
|
@ -39,9 +39,12 @@ class Blockchain:
|
|||
class ConnectionNotEstablished(RuntimeError):
|
||||
pass
|
||||
|
||||
def __init__(self, interface: Union[BlockchainInterface, BlockchainDeployerInterface] = None):
|
||||
def __init__(self,
|
||||
provider_process=None,
|
||||
interface: Union[BlockchainInterface, BlockchainDeployerInterface] = None):
|
||||
|
||||
self.log = Logger("blockchain")
|
||||
self.__provider_process = provider_process
|
||||
|
||||
# Default interface
|
||||
if interface is None:
|
||||
|
@ -56,8 +59,8 @@ class Blockchain:
|
|||
|
||||
def __repr__(self):
|
||||
class_name = self.__class__.__name__
|
||||
r = "{}(interface={})"
|
||||
return r.format(class_name, self.__interface)
|
||||
r = "{}(interface={}, process={})"
|
||||
return r.format(class_name, self.__interface, self.__provider_process)
|
||||
|
||||
@property
|
||||
def interface(self) -> Union[BlockchainInterface, BlockchainDeployerInterface]:
|
||||
|
@ -65,6 +68,7 @@ class Blockchain:
|
|||
|
||||
@classmethod
|
||||
def connect(cls,
|
||||
provider_process=None,
|
||||
provider_uri: str = None,
|
||||
registry: EthereumContractRegistry = None,
|
||||
deployer: bool = False,
|
||||
|
@ -74,6 +78,8 @@ class Blockchain:
|
|||
fetch_registry: bool = True
|
||||
) -> 'Blockchain':
|
||||
|
||||
log = Logger('blockchain-init')
|
||||
|
||||
if cls._instance is NO_BLOCKCHAIN_AVAILABLE:
|
||||
if not registry and fetch_registry:
|
||||
from nucypher.config.node import NodeConfiguration
|
||||
|
@ -85,15 +91,23 @@ class Blockchain:
|
|||
else:
|
||||
registry = registry or EthereumContractRegistry()
|
||||
|
||||
# Spawn child process
|
||||
if provider_process:
|
||||
provider_process.start()
|
||||
else:
|
||||
log.info(f"Using external Web3 Provider '{provider_uri}'")
|
||||
|
||||
compiler = SolidityCompiler() if compile is True else None
|
||||
InterfaceClass = BlockchainDeployerInterface if deployer is True else BlockchainInterface
|
||||
interface = InterfaceClass(provider_uri=provider_uri, registry=registry, compiler=compiler)
|
||||
|
||||
if poa is True:
|
||||
log.debug('Injecting POA middleware at layer 0')
|
||||
interface.w3.middleware_onion.inject(geth_poa_middleware, layer=0)
|
||||
|
||||
cls._instance = cls(interface=interface)
|
||||
cls._instance = cls(interface=interface, provider_process=provider_process)
|
||||
else:
|
||||
|
||||
if provider_uri is not None:
|
||||
existing_uri = cls._instance.interface.provider_uri
|
||||
if (existing_uri != provider_uri) and not force:
|
||||
|
@ -107,6 +121,11 @@ class Blockchain:
|
|||
|
||||
return cls._instance
|
||||
|
||||
@classmethod
|
||||
def disconnect(cls):
|
||||
if cls._instance.__provider_process:
|
||||
cls._instance.__provider_process.stop()
|
||||
|
||||
def get_contract(self, name: str) -> Contract:
|
||||
"""
|
||||
Gets an existing contract from the registry, or raises UnknownContract
|
||||
|
|
|
@ -9,6 +9,7 @@ from nucypher.cli.config import nucypher_click_config
|
|||
from nucypher.cli.types import NETWORK_PORT, EXISTING_READABLE_FILE, EIP55_CHECKSUM_ADDRESS
|
||||
from nucypher.config.characters import FelixConfiguration
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION
|
||||
|
||||
|
||||
@click.command()
|
||||
|
@ -54,14 +55,12 @@ def felix(click_config,
|
|||
force):
|
||||
|
||||
click.clear()
|
||||
|
||||
if not click_config.quiet:
|
||||
click.secho(FELIX_BANNER.format(checksum_address or ''))
|
||||
|
||||
ETH_NODE = None # TODO: Make constant
|
||||
ETH_NODE = NO_BLOCKCHAIN_CONNECTION.bool_value(False)
|
||||
if geth:
|
||||
ETH_NODE = NuCypherGethDevnetProcess(config_root=config_root)
|
||||
ETH_NODE.start()
|
||||
provider_uri = ETH_NODE.provider_uri
|
||||
|
||||
if action == "init":
|
||||
|
@ -76,17 +75,26 @@ def felix(click_config,
|
|||
|
||||
# Acquire Keyring Password
|
||||
new_password = click_config.get_password(confirm=True)
|
||||
new_felix_config = FelixConfiguration.generate(password=new_password,
|
||||
config_root=config_root,
|
||||
rest_host=host,
|
||||
rest_port=discovery_port,
|
||||
db_filepath=db_filepath,
|
||||
domains={network} if network else None,
|
||||
checksum_public_address=checksum_address,
|
||||
download_registry=not no_registry,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
poa=poa)
|
||||
|
||||
try:
|
||||
new_felix_config = FelixConfiguration.generate(password=new_password,
|
||||
config_root=config_root,
|
||||
rest_host=host,
|
||||
rest_port=discovery_port,
|
||||
db_filepath=db_filepath,
|
||||
domains={network} if network else None,
|
||||
checksum_public_address=checksum_address,
|
||||
download_registry=not no_registry,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_uri=provider_uri,
|
||||
provider_process=ETH_NODE,
|
||||
poa=poa)
|
||||
except Exception as e:
|
||||
if click_config.debug:
|
||||
raise
|
||||
else:
|
||||
click.secho(str(e), fg='red', bold=True)
|
||||
raise click.Abort
|
||||
|
||||
# Paint Help
|
||||
painting.paint_new_installation_help(new_configuration=new_felix_config,
|
||||
|
@ -103,6 +111,7 @@ def felix(click_config,
|
|||
felix_config = FelixConfiguration.from_configuration_file(filepath=config_file,
|
||||
domains=domains,
|
||||
registry_filepath=registry_filepath,
|
||||
provider_process=ETH_NODE,
|
||||
provider_uri=provider_uri,
|
||||
rest_host=host,
|
||||
rest_port=port,
|
||||
|
@ -165,14 +174,15 @@ ETH ........ {str(eth_balance)}
|
|||
|
||||
elif action == 'run': # Start web services
|
||||
|
||||
FELIX.start(host=host,
|
||||
port=port,
|
||||
web_services=not dry_run,
|
||||
distribution=True,
|
||||
crash_on_error=click_config.debug)
|
||||
try:
|
||||
FELIX.blockchain.connect()
|
||||
FELIX.start(host=host,
|
||||
port=port,
|
||||
web_services=not dry_run,
|
||||
distribution=True,
|
||||
crash_on_error=click_config.debug)
|
||||
finally:
|
||||
FELIX.blockchain.disconnect()
|
||||
|
||||
else:
|
||||
raise click.BadArgumentUsage("No such argument {}".format(action))
|
||||
|
||||
if ETH_NODE:
|
||||
ETH_NODE.stop()
|
||||
|
|
|
@ -148,7 +148,7 @@ class NodeConfiguration(ABC):
|
|||
# Blockchain
|
||||
poa: bool = False,
|
||||
provider_uri: str = None,
|
||||
geth: bool = False,
|
||||
provider_process = None,
|
||||
|
||||
# Registry
|
||||
registry_source: str = None,
|
||||
|
@ -249,7 +249,7 @@ class NodeConfiguration(ABC):
|
|||
#
|
||||
self.poa = poa
|
||||
self.provider_uri = provider_uri or self.DEFAULT_PROVIDER_URI
|
||||
self.geth = geth
|
||||
self.provider_process = provider_process or NO_BLOCKCHAIN_CONNECTION
|
||||
|
||||
self.blockchain = NO_BLOCKCHAIN_CONNECTION
|
||||
self.accounts = NO_BLOCKCHAIN_CONNECTION
|
||||
|
@ -286,8 +286,6 @@ class NodeConfiguration(ABC):
|
|||
return node_config
|
||||
|
||||
def __write(self, password: str):
|
||||
if not self.federated_only:
|
||||
self.connect_to_blockchain() # Needed for access to ethereum node addresses and NC key signing
|
||||
_new_installation_path = self.initialize(password=password, download_registry=self.download_registry)
|
||||
_configuration_filepath = self.to_configuration_file(filepath=self.config_file_location)
|
||||
|
||||
|
@ -315,14 +313,16 @@ class NodeConfiguration(ABC):
|
|||
"""
|
||||
if self.federated_only:
|
||||
raise NodeConfiguration.ConfigurationError("Cannot connect to blockchain in federated mode")
|
||||
|
||||
self.blockchain = Blockchain.connect(provider_uri=self.provider_uri,
|
||||
compile=recompile_contracts,
|
||||
poa=self.poa,
|
||||
fetch_registry=True)
|
||||
fetch_registry=True,
|
||||
provider_process=self.provider_process)
|
||||
|
||||
# Read Ethereum Node Keyring
|
||||
self.accounts = self.blockchain.interface.w3.eth.accounts
|
||||
|
||||
# Add Ethereum Peer
|
||||
if enode:
|
||||
if self.blockchain.interface.client_version == 'geth':
|
||||
self.blockchain.interface.w3.geth.admin.addPeer(enode)
|
||||
|
@ -376,7 +376,11 @@ class NodeConfiguration(ABC):
|
|||
return payload
|
||||
|
||||
@classmethod
|
||||
def from_configuration_file(cls, filepath: str = None, **overrides) -> 'NodeConfiguration':
|
||||
def from_configuration_file(cls,
|
||||
filepath: str = None,
|
||||
provider_process=None,
|
||||
**overrides) -> 'NodeConfiguration':
|
||||
|
||||
"""Initialize a NodeConfiguration from a JSON file."""
|
||||
|
||||
from nucypher.config.storages import NodeStorage
|
||||
|
@ -414,7 +418,9 @@ class NodeConfiguration(ABC):
|
|||
overrides = {k: v for k, v in overrides.items() if v is not None}
|
||||
|
||||
# Instantiate from merged params
|
||||
node_configuration = cls(config_file_location=filepath, **{**payload, **overrides})
|
||||
node_configuration = cls(config_file_location=filepath,
|
||||
provider_process=provider_process,
|
||||
**{**payload, **overrides})
|
||||
|
||||
return node_configuration
|
||||
|
||||
|
@ -569,6 +575,13 @@ class NodeConfiguration(ABC):
|
|||
# Generate Installation Subdirectories
|
||||
self._cache_runtime_filepaths()
|
||||
|
||||
#
|
||||
# Blockchain
|
||||
#
|
||||
if not self.federated_only:
|
||||
if self.provider_process:
|
||||
self.provider_process.initialize_blockchain()
|
||||
|
||||
#
|
||||
# Node Storage
|
||||
#
|
||||
|
@ -621,27 +634,26 @@ class NodeConfiguration(ABC):
|
|||
*args, **kwargs)
|
||||
|
||||
def write_keyring(self, password: str, **generation_kwargs) -> NucypherKeyring:
|
||||
# Get or create wallet address
|
||||
|
||||
# Note: It is assumed the blockchain is not yet available.
|
||||
if not self.federated_only and not self.checksum_public_address:
|
||||
|
||||
# TODO: Bury deeper in keying and powers
|
||||
try:
|
||||
checksum_address = self.blockchain.interface.w3.eth.accounts[0] # etherbase
|
||||
#
|
||||
# Integrated Provider Process
|
||||
#
|
||||
|
||||
except IndexError:
|
||||
if self.provider_process:
|
||||
|
||||
data_dir = os.path.join(self.config_root, '.ethereum', NuCypherGethDevnetProcess._CHAIN_NAME)
|
||||
if not os.path.exists(data_dir):
|
||||
os.mkdir(data_dir)
|
||||
if not os.path.exists(self.provider_process.data_dir):
|
||||
os.mkdir(self.provider_process.data_dir)
|
||||
|
||||
client_version = self.blockchain.interface.w3.clientVersion
|
||||
if 'Geth' in client_version:
|
||||
checksum_address = NuCypherGethDevnetProcess.ensure_account_exists(password=password,
|
||||
data_dir=data_dir)
|
||||
# Get or create wallet address (geth etherbase)
|
||||
checksum_address = self.provider_process.ensure_account_exists(password=password)
|
||||
|
||||
else:
|
||||
raise RuntimeError("THIS IS A TEMPORARY DEBUGGING EXCEPTION") # TODO
|
||||
else:
|
||||
# Manual Web3 Provider, We assume is already running and available
|
||||
self.connect_to_blockchain()
|
||||
# TODO: Create etherbase over RPC instead
|
||||
raise self.ConfigurationError(f'Web3 provider "{self.provider_uri}" does not have any accounts')
|
||||
|
||||
# Addresses read from some node keyrings are *not* returned in checksum format.
|
||||
checksum_address = to_checksum_address(checksum_address)
|
||||
|
|
|
@ -19,7 +19,7 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
import os
|
||||
from typing import List, Tuple, Dict
|
||||
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_AVAILABLE
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_AVAILABLE, TEST_PROVIDER_ON_MAIN_PROCESS
|
||||
from twisted.logger import Logger
|
||||
from web3 import Web3
|
||||
from web3.middleware import geth_poa_middleware
|
||||
|
@ -86,7 +86,7 @@ class TesterBlockchain(Blockchain):
|
|||
if test_accounts is None:
|
||||
test_accounts = self._default_test_accounts
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
super().__init__(provider_process=TEST_PROVIDER_ON_MAIN_PROCESS, *args, **kwargs)
|
||||
self.log = Logger("test-blockchain")
|
||||
self.attach_middleware(w3=self.interface.w3, poa=poa, free_transactions=free_transactions)
|
||||
|
||||
|
|
Loading…
Reference in New Issue