Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy new registries and release packages #49

Merged
merged 6 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions ethpm_cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ def get_authorized_private_key(password: str) -> str:
Returns the private key associated with stored keyfile. Password required.
"""
keyfile_path = get_keyfile_path()
private_key = eth_keyfile.extract_key_from_keyfile(
str(keyfile_path), to_bytes(text=password)
)
try:
private_key = eth_keyfile.extract_key_from_keyfile(
str(keyfile_path), to_bytes(text=password)
)
except ValueError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nice upstream change would be for the library to raise something less generic than a ValueError on authentication failure.

raise AuthorizationError(
f"Provided keyfile password: {password} is not a valid "
f"password for encrypted keyfile at {keyfile_path}."
)
return private_key
37 changes: 31 additions & 6 deletions ethpm_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
from pathlib import Path
from typing import Any, Dict

from eth_account import Account
from eth_utils import to_checksum_address
from ethpm.constants import SUPPORTED_CHAIN_IDS
from web3 import Web3
from web3.auto.infura.endpoints import build_http_headers, build_infura_url
from web3.middleware import construct_sign_and_send_raw_middleware
from web3.providers.auto import load_provider_from_uri

from ethpm_cli._utils.filesystem import atomic_replace
from ethpm_cli._utils.ipfs import get_ipfs_backend
from ethpm_cli._utils.logger import cli_logger
from ethpm_cli._utils.xdg import get_xdg_ethpmcli_root
from ethpm_cli.auth import get_authorized_private_key, import_keyfile
from ethpm_cli.constants import (
ETHPM_DIR_ENV_VAR,
ETHPM_PACKAGES_DIR,
Expand All @@ -32,6 +37,8 @@ class Config:
- Projects dir
"""

private_key = None

def __init__(self, args: Namespace) -> None:
# Setup IPFS backend
if "local_ipfs" in args and args.local_ipfs:
Expand All @@ -52,13 +59,20 @@ def __init__(self, args: Namespace) -> None:

# Setup w3
if "chain_id" in args and args.chain_id:
self.w3 = get_w3(args.chain_id)
chain_id = args.chain_id
else:
self.w3 = get_w3(1)
chain_id = 1

if "keyfile_path" in args and args.keyfile_path:
import_keyfile(args.keyfile_path)

if "keyfile_password" in args and args.keyfile_password:
self.private_key = get_authorized_private_key(args.keyfile_password)
self.w3 = setup_w3(chain_id, self.private_key)

# Setup xdg ethpm dir
xdg_ethpmcli_root = get_xdg_ethpmcli_root()
setup_xdg_ethpm_dir(xdg_ethpmcli_root, self.w3)
self.xdg_ethpmcli_root = get_xdg_ethpmcli_root()
setup_xdg_ethpm_dir(self.xdg_ethpmcli_root, self.w3)

# Setup projects dir
if "project_dir" in args and args.project_dir:
Expand All @@ -68,7 +82,7 @@ def __init__(self, args: Namespace) -> None:
self.project_dir = None


def get_w3(chain_id: int) -> Web3:
def setup_w3(chain_id: int, private_key: str = None) -> Web3:
if chain_id not in SUPPORTED_CHAIN_IDS.keys():
raise ValidationError(
f"Chain ID: {chain_id} is invalid. Currently supported chain ids "
Expand All @@ -77,7 +91,18 @@ def get_w3(chain_id: int) -> Web3:
infura_url = f"{SUPPORTED_CHAIN_IDS[chain_id]}.infura.io"
headers = build_http_headers()
infura_url = build_infura_url(infura_url)
return Web3(load_provider_from_uri(infura_url, headers))
w3 = Web3(load_provider_from_uri(infura_url, headers))

if private_key is not None:
owner_address = Account.from_key(private_key).address
signing_middleware = construct_sign_and_send_raw_middleware(private_key)
w3.middleware_onion.add(signing_middleware)
w3.eth.defaultAccount = to_checksum_address(owner_address)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a good place to issue a DEBUG level logging statement indicating that in-flight signing has been enabled for whatever account address.

cli_logger.debug(
"In-flight tx signing has been enabled for address: {owner_address}."
)
w3.enable_unstable_package_management_api()
return w3


def setup_xdg_ethpm_dir(xdg_ethpmcli_root: Path, w3: Web3) -> None:
Expand Down
4 changes: 2 additions & 2 deletions ethpm_cli/etherscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import requests

from ethpm_cli._utils.etherscan import get_etherscan_network, is_etherscan_uri
from ethpm_cli.config import get_ipfs_backend, get_w3
from ethpm_cli.config import get_ipfs_backend, setup_w3
from ethpm_cli.constants import ETHERSCAN_KEY_ENV_VAR
from ethpm_cli.exceptions import ContractNotVerified
from ethpm_cli.validation import validate_etherscan_key_available
Expand Down Expand Up @@ -43,7 +43,7 @@ def build_etherscan_manifest(
network = get_etherscan_network(chain_id)
body = make_etherscan_request(address, network)
contract_type = body["ContractName"]
w3 = get_w3(to_int(text=chain_id))
w3 = setup_w3(to_int(text=chain_id))
block_uri = create_latest_block_uri(w3)
runtime_bytecode = to_hex(w3.eth.getCode(address))

Expand Down
4 changes: 2 additions & 2 deletions ethpm_cli/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
create_basic_manifest_from_solc_output,
get_contract_types,
)
from ethpm_cli.config import get_w3
from ethpm_cli.config import setup_w3
from ethpm_cli.constants import SOLC_OUTPUT
from ethpm_cli.validation import validate_solc_output

Expand Down Expand Up @@ -144,7 +144,7 @@ def gen_all_deployments(solc_output: Dict[str, Any]) -> Iterable[Dict[str, Any]]

def gen_single_deployment(solc_output: Dict[str, Any]) -> Dict[str, Any]:
chain_id = get_chain_id()
w3 = get_w3(chain_id)
w3 = setup_w3(chain_id)
block_uri = create_latest_block_uri(w3)
address = get_deployment_address()
contract_type = get_deployment_contract_type(solc_output)
Expand Down
140 changes: 114 additions & 26 deletions ethpm_cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ethpm_cli._utils.logger import cli_logger
from ethpm_cli._utils.solc import generate_solc_input
from ethpm_cli._utils.xdg import get_xdg_ethpmcli_root
from ethpm_cli.auth import get_authorized_address, import_keyfile
from ethpm_cli.auth import get_authorized_address
from ethpm_cli.config import Config, validate_config_has_project_dir_attr
from ethpm_cli.constants import IPFS_CHAIN_DATA
from ethpm_cli.exceptions import AuthorizationError, ValidationError
Expand All @@ -17,7 +17,13 @@
)
from ethpm_cli.manifest import generate_basic_manifest, generate_custom_manifest
from ethpm_cli.package import Package
from ethpm_cli.registry import activate_registry, add_registry, list_registries
from ethpm_cli.registry import (
activate_registry,
add_registry,
deploy_registry,
list_registries,
)
from ethpm_cli.release import release_package
from ethpm_cli.scraper import scrape
from ethpm_cli.validation import (
validate_chain_data_store,
Expand All @@ -26,8 +32,9 @@
validate_uninstall_cli_args,
)

parser = argparse.ArgumentParser(description="ethpm-cli")
ethpm_parser = parser.add_subparsers(help="commands", dest="command")
#
# Shared args
#


def add_chain_id_arg_to_parser(parser: argparse.ArgumentParser) -> None:
Expand Down Expand Up @@ -80,15 +87,89 @@ def add_package_version_arg_to_parser(parser: argparse.ArgumentParser) -> None:
)


def add_keyfile_password_arg_to_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--keyfile-password",
dest="keyfile_password",
action="store",
type=str,
help="Password to local encrypted keyfile.",
)


def add_keyfile_path_arg_to_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--keyfile-path",
dest="keyfile_path",
action="store",
type=Path,
help="Path to your keyfile.",
)


def add_alias_arg_to_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--alias",
dest="alias",
action="store",
type=str,
help="Alias to use in reference to this target registry / package.",
)


parser = argparse.ArgumentParser(description="ethpm-cli")
ethpm_parser = parser.add_subparsers(help="commands", dest="command")


#
# ethpm release
#


# todo: extend to pin & release a local manifest
def release_cmd(args: argparse.Namespace) -> None:
config = Config(args)
release_package(args.package_name, args.version, args.manifest_uri, config)
cli_logger.info(
f"{args.package_name} @ {args.version} @ {args.manifest_uri} "
"released to registry @ ..."
)


release_parser = ethpm_parser.add_parser("release")
release_parser.add_argument(
"--package-name",
dest="package_name",
action="store",
type=str,
help="Package name of package you want to release. Must match `package_name` in manifest.",
)
release_parser.add_argument(
"--version",
action="store",
type=str,
help="Version of package you want to release. Must match the `version` field in manifest.",
)
release_parser.add_argument(
"--manifest-uri",
dest="manifest_uri",
action="store",
type=str,
help="Content addressed URI at which the manifest for released package is located.",
)
add_ethpm_dir_arg_to_parser(release_parser)
add_keyfile_password_arg_to_parser(release_parser)
add_keyfile_path_arg_to_parser(release_parser)
release_parser.set_defaults(func=release_cmd)


#
# ethpm auth
#


def auth_action(args: argparse.Namespace) -> None:
Config(args)
if args.keyfile_path:
import_keyfile(args.keyfile_path)
try:
authorized_address = get_authorized_address()
cli_logger.info(f"Keyfile stored for address: 0x{authorized_address}.")
Expand All @@ -100,13 +181,7 @@ def auth_action(args: argparse.Namespace) -> None:


auth_parser = ethpm_parser.add_parser("auth", help="auth")
auth_parser.add_argument(
"--keyfile-path",
dest="keyfile_path",
action="store",
type=Path,
help="Path to your keyfile.",
)
add_keyfile_path_arg_to_parser(auth_parser)
auth_parser.set_defaults(func=auth_action)


Expand Down Expand Up @@ -138,35 +213,50 @@ def registry_activate_cmd(args: argparse.Namespace) -> None:
cli_logger.info(f"Registry @ {args.uri_or_alias} activated.")


def registry_deploy_cmd(args: argparse.Namespace) -> None:
config = Config(args)
registry_address = deploy_registry(config, args.alias)
explorer_uri = (
f"http://explorer.ethpm.com/browse/{config.w3.eth.chainId}/{registry_address}"
)
cli_logger.info(
f"Congrats on your new ethPM registry! Check it out @ {explorer_uri}."
)
cli_logger.info(
"You can now release a package on your registrywith `ethpm release`."
)


registry_parser = ethpm_parser.add_parser("registry")
registry_subparsers = registry_parser.add_subparsers(help="registry", dest="registry")

# ethpm registry deploy
registry_deploy_parser = registry_subparsers.add_parser("deploy", help="deploy")
add_alias_arg_to_parser(registry_deploy_parser)
add_chain_id_arg_to_parser(registry_deploy_parser)
add_keyfile_password_arg_to_parser(registry_deploy_parser)
registry_deploy_parser.set_defaults(func=registry_deploy_cmd)

# ethpm registry list
registry_list_parser = registry_subparsers.add_parser("list", help="list")
add_ethpm_dir_arg_to_parser(registry_list_parser)
registry_list_parser.set_defaults(func=registry_list_cmd)

# ethpm registry add
registry_add_parser = registry_subparsers.add_parser("add", help="add")
registry_add_parser.add_argument(
"uri", action="store", type=str, help="Registry URI for target registry."
)
registry_add_parser.add_argument(
"--alias",
dest="alias",
action="store",
type=str,
help="Alias with which to reference this registry.",
)
add_ethpm_dir_arg_to_parser(registry_add_parser)
add_alias_arg_to_parser(registry_add_parser)
registry_add_parser.set_defaults(func=registry_add_cmd)

# ethpm registry activate
registry_activate_parser = registry_subparsers.add_parser("activate", help="activate")
registry_activate_parser.add_argument(
"uri_or_alias",
action="store",
type=str,
help="Registry URI or alias for target registry.",
)
add_ethpm_dir_arg_to_parser(registry_activate_parser)
registry_activate_parser.set_defaults(func=registry_activate_cmd)


Expand Down Expand Up @@ -317,15 +407,13 @@ def install_action(args: argparse.Namespace) -> None:
)
add_package_name_arg_to_parser(install_parser)
add_package_version_arg_to_parser(install_parser)
install_parser.add_argument(
"--alias", action="store", type=str, help="Alias to install target package under."
)
install_parser.add_argument(
"--local-ipfs",
dest="local_ipfs",
action="store_true",
help="Flag to use locally running IPFS node.",
)
add_alias_arg_to_parser(install_parser)
add_ethpm_dir_arg_to_parser(install_parser)
install_parser.set_defaults(func=install_action)

Expand Down
Loading