Пример #1
0
    def _connect_libraries(self):
        zk_print_banner(f'Deploying Libraries')

        sender = self.w3.eth.accounts[0]
        # Since eth-tester is not persistent -> always automatically deploy libraries
        with cfg.library_compilation_environment():
            with tempfile.TemporaryDirectory() as tmpdir:
                with log_context('transaction', 'deploy_pki'):
                    pki_sol = save_to_file(
                        tmpdir, f'{cfg.pki_contract_name}.sol',
                        library_contracts.get_pki_contract())
                    self._pki_contract = self._deploy_contract(
                        sender,
                        self.compile_contract(pki_sol, cfg.pki_contract_name))
                    zk_print(
                        f'Deployed pki contract at address "{self.pki_contract.address}"'
                    )

                with log_context('transaction', 'deploy_verify_libs'):
                    verify_sol = save_to_file(
                        tmpdir, 'verify_libs.sol',
                        library_contracts.get_verify_libs_code())
                    self._lib_addresses = {}
                    for lib in cfg.external_crypto_lib_names:
                        out = self._deploy_contract(
                            sender, self.compile_contract(verify_sol, lib))
                        self._lib_addresses[lib] = out.address
                        zk_print(
                            f'Deployed crypto lib {lib} at address "{out.address}"'
                        )
Пример #2
0
    def _deploy(self, project_dir: str, sender: Union[bytes, str], contract: str, *actual_args, wei_amount: Optional[int] = None) -> Any:
        with open(os.path.join(project_dir, 'contract.zkay')) as f:
            verifier_names = get_verification_contract_names(f.read())

        # Deploy verification contracts if not already done
        external_contract_addresses =  self._deploy_dependencies(sender, project_dir, verifier_names)
        with self.__hardcoded_external_contracts_ctx(project_dir, external_contract_addresses) as filename:
            cout = self.compile_contract(filename, contract, cwd=project_dir)
        with log_context('constructor'):
            with log_context(f'{contract}'):
                handle = self._deploy_contract(sender, cout, *actual_args, wei_amount=wei_amount)
        zk_print(f'Deployed contract "{contract}" at address "{handle.address}"')
        return handle
Пример #3
0
 def _deploy_dependencies(self, sender: Union[bytes, str], project_dir: str, verifier_names: List[str]) -> Dict[str, AddressValue]:
     # Deploy verification contracts if not already done
     vf = {}
     for verifier_name in verifier_names:
         with log_context('constructor'):
             with log_context(f'{verifier_name}'):
                 filename = os.path.join(project_dir, f'{verifier_name}.sol')
                 cout = self.compile_contract(filename, verifier_name, self.lib_addresses)
                 with time_measure("transaction_full"):
                     vf[verifier_name] = AddressValue(self._deploy_contract(sender, cout).address)
     for crypto_params in cfg.all_crypto_params():
         pki_contract_name = cfg.get_pki_contract_name(crypto_params)
         pki_contract_address = self.pki_contract(crypto_params.crypto_name).address
         vf[pki_contract_name] = AddressValue(pki_contract_address)
     return vf
Пример #4
0
    def _function_ctx(self,
                      trans_sec_size=-1,
                      *,
                      wei_amount: int = 0,
                      name: str = '?'):
        with self.api.api_function_ctx(trans_sec_size,
                                       wei_amount) as is_external:
            if is_external:
                zk_print_banner(f'Calling {name}')
                assert self.locals is None
                self.state.clear()
                t_idx = self.tidx.get(name, 0)
                self.tidx[name] = t_idx + 1

            with nullcontext() if not is_external else log_context(
                    'transaction', f'{name}_{t_idx}'):
                prev_locals = self.locals
                self.locals = LocalsDict()

                try:
                    yield is_external
                except (ValueError, BlockChainError, RequireException) as e:
                    if is_external and not cfg.is_unit_test:
                        # uncomment to raise errors instead of just printing message (for debugging)
                        # raise e
                        with fail_print():
                            print(f'ERROR: {e}')
                    else:
                        raise e
                finally:
                    self.locals = prev_locals
                    if is_external:
                        self.state.clear()
Пример #5
0
 def _deploy_dependencies(
         self, sender: Union[bytes, str], project_dir: str,
         verifier_names: List[str]) -> Dict[str, AddressValue]:
     # Deploy verification contracts if not already done
     vf = {}
     for verifier_name in verifier_names:
         with log_context('transaction', f'deploy_{verifier_name}'):
             filename = os.path.join(project_dir, f'{verifier_name}.sol')
             cout = self.compile_contract(filename, verifier_name,
                                          self.lib_addresses)
             vf[verifier_name] = AddressValue(
                 self._deploy_contract(sender, cout).address)
     vf[cfg.pki_contract_name] = AddressValue(self.pki_contract.address)
     return vf
Пример #6
0
 def _announce_public_key(self, address: Union[bytes, str],
                          pk: Tuple[int, ...]) -> Any:
     with log_context('transaction', f'announcePk'):
         return self._transact(self.pki_contract, address, 'announcePk', pk)
Пример #7
0
def main():
    # parse arguments
    a = parse_arguments()

    from zkay.config_version import Versions

    if a.cmd == 'version':
        print(Versions.ZKAY_VERSION)
        return

    if a.cmd == 'update-solc':
        try:
            import solcx
            solcx.install_solc_pragma(
                Versions.ZKAY_SOLC_VERSION_COMPATIBILITY.expression)
        except Exception as e:
            print(f'ERROR: Error while updating solc\n{e}')
        return

    from pathlib import Path

    import zkay.zkay_frontend as frontend
    from zkay import my_logging
    from zkay.config import cfg
    from zkay.utils.helpers import read_file, save_to_file
    from zkay.errors.exceptions import ZkayCompilerError
    from zkay.my_logging.log_context import log_context
    from zkay.utils.progress_printer import fail_print, success_print
    from zkay.zkay_ast.process_ast import get_processed_ast, get_parsed_ast_and_fake_code

    # Load configuration files
    try:
        cfg.load_configuration_from_disk(a.config_file)
    except Exception as e:
        with fail_print():
            print(f"ERROR: Failed to load configuration files\n{e}")
            exit(42)

    # Support for overriding any user config setting via command line
    # The evaluation order for configuration loading is:
    # Default values in config.py -> Site config.json -> user config.json -> local config.json -> cmdline arguments
    # Settings defined at a later stage override setting values defined at an earlier stage
    override_dict = {}
    for name in vars(UserConfig):
        if name[0] != '_' and hasattr(a, name):
            val = getattr(a, name)
            if val is not None:
                override_dict[name] = val
    cfg.override_defaults(override_dict)

    if a.cmd in ['deploy-pki', 'deploy-crypto-libs']:
        import tempfile
        from zkay.compiler.privacy import library_contracts
        from zkay.transaction.runtime import Runtime
        with tempfile.TemporaryDirectory() as tmpdir:
            try:
                with cfg.library_compilation_environment():
                    if a.cmd == 'deploy-pki':
                        file = save_to_file(
                            tmpdir, f'{cfg.pki_contract_name}.sol',
                            library_contracts.get_pki_contract())
                        addr = Runtime.blockchain().deploy_solidity_contract(
                            file, cfg.pki_contract_name, a.account)
                        print(f'Deployed pki contract at: {addr}')
                    else:
                        if not cfg.external_crypto_lib_names:
                            print(
                                'Current proving scheme does not require library deployment'
                            )
                        else:
                            file = save_to_file(
                                tmpdir, 'verify_libs.sol',
                                library_contracts.get_verify_libs_code())
                            for lib in cfg.external_crypto_lib_names:
                                addr = Runtime.blockchain(
                                ).deploy_solidity_contract(
                                    file, lib, a.account)
                                print(
                                    f'Deployed crypto library {lib} at: {addr}'
                                )
            except Exception as e:
                with fail_print():
                    print(f"ERROR: Deployment failed\n{e}")
    else:
        # Solc version override
        if hasattr(a, 'solc_version') and a.solc_version is not None:
            try:
                cfg.override_solc(a.solc_version)
            except ValueError as e:
                with fail_print():
                    print(f'Error: {e}')
                exit(10)
        print(f'Using solc version {Versions.SOLC_VERSION}')

        input_path = Path(a.input)
        if not input_path.exists():
            with fail_print():
                print(f'Error: input file \'{input_path}\' does not exist')
            exit(1)

        if a.cmd == 'check':
            # only type-check
            print(f'Type checking file {input_path.name}:')

            code = read_file(str(input_path))
            try:
                get_processed_ast(code)
            except ZkayCompilerError as e:
                with fail_print():
                    print(f'{e}')
                exit(3)
        elif a.cmd == 'solify':
            was_unit_test = cfg.is_unit_test
            cfg._is_unit_test = True  # Suppress other output
            try:
                _, fake_code = get_parsed_ast_and_fake_code(
                    read_file(str(input_path)))
                print(fake_code)
            except ZkayCompilerError as e:
                with fail_print():
                    print(f'{e}')
                exit(3)
            finally:
                cfg._is_unit_test = was_unit_test
            exit(0)
        elif a.cmd == 'compile':
            # create output directory
            output_dir = Path(a.output).absolute()
            if not output_dir.exists():
                os.makedirs(output_dir)
            elif not output_dir.is_dir():
                with fail_print():
                    print(f'Error: \'{output_dir}\' is not a directory')
                exit(2)

            # Enable logging
            if a.log:
                log_file = my_logging.get_log_file(filename='compile',
                                                   include_timestamp=False,
                                                   label=None)
                my_logging.prepare_logger(log_file)

            # only type-check
            print(f'Compiling file {input_path.name}:')

            # compile
            with log_context('inputfile', os.path.basename(a.input)):
                try:
                    frontend.compile_zkay_file(str(input_path),
                                               str(output_dir))
                except ZkayCompilerError as e:
                    with fail_print():
                        print(f'{e}')
                    exit(3)
        elif a.cmd == 'import':
            # create output directory
            output_dir = Path(a.output).absolute()
            if output_dir.exists():
                with fail_print():
                    print(f'Error: \'{output_dir}\' already exists')
                exit(2)

            try:
                frontend.extract_zkay_package(str(input_path), str(output_dir))
            except ZkayCompilerError as e:
                with fail_print():
                    print(
                        f"ERROR while compiling unpacked zkay contract.\n{e}")
                exit(3)
            except Exception as e:
                with fail_print():
                    print(f"ERROR while unpacking zkay contract\n{e}")
                exit(5)
        elif a.cmd == 'export':
            output_filename = Path(a.output).absolute()
            os.makedirs(output_filename.parent, exist_ok=True)
            try:
                frontend.package_zkay_contract(str(input_path),
                                               str(output_filename))
            except Exception as e:
                with fail_print():
                    print(f"ERROR while exporting zkay contract\n{e}")
                exit(4)
        elif a.cmd in ['run', 'deploy', 'connect']:
            from enum import IntEnum
            from zkay.transaction.offchain import ContractSimulator

            def echo_only_simple_expressions(e):
                if isinstance(e, (bool, int, str, list, tuple, IntEnum)):
                    print(e)

            # Enable logging
            if a.log:
                log_file = my_logging.get_log_file(
                    filename=f'transactions_{input_path.name}',
                    include_timestamp=True,
                    label=None)
                my_logging.prepare_logger(log_file)

            contract_dir = str(input_path.absolute())
            frontend.use_configuration_from_manifest(contract_dir)
            if a.account is not None:
                me = a.account
            else:
                me = ContractSimulator.default_address()
                if me is not None:
                    me = me.val

            import code
            import sys
            if a.cmd == 'run':
                # Dynamically load module and replace globals with module globals
                contract_mod = frontend.load_transaction_interface_from_directory(
                    contract_dir)
                contract_mod.me = me
                sys.displayhook = echo_only_simple_expressions
                code.interact(local=contract_mod.__dict__)
            else:
                cmod = frontend.load_transaction_interface_from_directory(
                    contract_dir)
                c = frontend.load_contract_transaction_interface_from_module(
                    cmod)
                if a.cmd == 'deploy':
                    from ast import literal_eval
                    cargs = a.constructor_args
                    args = []
                    for arg in cargs:
                        try:
                            val = literal_eval(arg)
                        except Exception:
                            val = arg
                        args.append(val)
                    try:
                        c.deploy(*args, user=me, project_dir=contract_dir)
                    except (ValueError, TypeError) as e:
                        with fail_print():
                            print(
                                f'ERROR invalid arguments.\n{e}\n\nExpected contructor signature: ',
                                end='')
                            if hasattr(c, 'constructor'):
                                from inspect import signature
                                sig = str(signature(c.constructor))
                                sig = sig[5:] if not sig[5:].startswith(
                                    ",") else sig[7:]  # without self
                                print(f'({sig}')
                            else:
                                print('()')
                            exit(11)
                    except Exception as e:
                        with fail_print():
                            print(f'ERROR: failed to deploy contract\n{e}')
                            exit(12)
                elif a.cmd == 'connect':
                    try:
                        c_inst = c.connect(address=a.address,
                                           user=me,
                                           project_dir=contract_dir)
                    except Exception as e:
                        with fail_print():
                            print(f'ERROR: failed to connect to contract\n{e}')
                            exit(13)

                    # Open interactive shell in context of contract object
                    import inspect
                    contract_scope = {name: getattr(c_inst, name) for name in dir(c_inst)
                                      if inspect.isclass(getattr(c_inst, name)) \
                                         or (name != 'constructor' and hasattr(getattr(c_inst, name), '_can_be_external')
                                             and getattr(c_inst, name)._can_be_external)
                                         or name in ['state', 'api']}
                    contract_scope['me'] = me
                    contract_scope['help'] = lambda o=None: help(
                        o
                    ) if o is not None else ContractSimulator.reduced_help(c)
                    sys.displayhook = echo_only_simple_expressions
                    code.interact(local=contract_scope)
                else:
                    raise ValueError(f'unexpected command {a.cmd}')
            exit(0)
        else:
            raise NotImplementedError(a.cmd)

        with success_print():
            print("Finished successfully")
Пример #8
0
 def _announce_public_key(self, address: Union[bytes, str], pk: Tuple[int, ...], crypto_params: CryptoParams) -> Any:
     with log_context(f'announcePk'):
         return self._transact(self.pki_contract(crypto_params.crypto_name), address, 'announcePk', pk)