def compile_zkay_file(input_file_path: str, output_dir: str, import_keys: bool = False, **kwargs): """ Parse, type-check and compile the given zkay contract file. :param input_file_path: path to the zkay contract file :param output_dir: path to a directory where the compilation output should be generated :param import_keys: | if false, zk-snark of all modified circuits will be generated during compilation | if true, zk-snark keys for all circuits are expected to be already present in the output directory, and the compilation will use the provided keys to generate the verification contracts | This option is mostly used internally when connecting to a zkay contract provided by a 3rd-party :raise ZkayCompilerError: if any compilation stage fails :raise RuntimeError: if import_keys is True and zkay file, manifest file or any of the key files is missing """ code = read_file(input_file_path) # log specific features of compiled program my_logging.data('originalLoc', lines_of_code(code)) m = re.search(r'\/\/ Description: (.*)', code) if m: my_logging.data('description', m.group(1)) m = re.search(r'\/\/ Domain: (.*)', code) if m: my_logging.data('domain', m.group(1)) _, filename = os.path.split(input_file_path) # compile with time_measure('compileFull'): cg, _ = compile_zkay(code, output_dir, import_keys, **kwargs)
def test_timer_decorator(self): log_file = base_log_file + '_decorator' my_logging.prepare_logger(log_file) sleep(0.5) my_logging.shutdown() content = read_file(log_file + '_data.log') d = json.loads(content) self.assertAlmostEqual(0.5, d['value'], 1)
def test_timer_context_manager(self): log_file = base_log_file + '_context_manager' my_logging.prepare_logger(log_file) my_logging.shutdown() with time_measure('mykey2'): time.sleep(0.5) content = read_file(log_file + '_data.log') d = json.loads(content) self.assertAlmostEqual(0.5, d['value'], 1)
def test_data(self): log_file = default_log_file + '_data_test' my_logging.prepare_logger(log_file) my_logging.data('key', 2) my_logging.info('ABCD') my_logging.shutdown() # check content = read_file(log_file + '_data.log') d = json.loads(content) self.assertEqual(d['key'], 'key') self.assertEqual(d['value'], 2) self.assertTrue('ABCD' not in content)
def test_logger(self): # ignore warnings warnings.simplefilter("ignore") # log something log_file = default_log_file + '_basic_test' my_logging.prepare_logger(log_file) my_logging.info("ABCD") my_logging.shutdown() # check logfile success = 'ABCD' in read_file(log_file + '_info.log') self.assertTrue(success)
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")