def cairo_run(args): trace_file = args.trace_file if trace_file is None and args.tracer: # If --tracer is used, use a temporary file as trace_file. trace_file = tempfile.NamedTemporaryFile(mode='wb') memory_file = args.memory_file if memory_file is None and args.tracer: # If --tracer is used, use a temporary file as memory_file. memory_file = tempfile.NamedTemporaryFile(mode='wb') debug_info_file = args.debug_info_file if debug_info_file is None and args.tracer: # If --tracer is used, use a temporary file as debug_info_file. debug_info_file = tempfile.NamedTemporaryFile(mode='w') ret_code = 0 if args.program is not None: program: ProgramBase = Program.Schema().load(json.load(args.program)) initial_memory = MemoryDict() steps_input = args.steps else: raise NotImplementedError('--run_from_cairo_pie is not supported.') runner = CairoRunner(program=program, layout=args.layout, memory=initial_memory, proof_mode=args.proof_mode) runner.initialize_segments() end = runner.initialize_main_entrypoint() if args.run_from_cairo_pie is not None: # Add extra_segments. for segment_info in cairo_pie_input.metadata.extra_segments: runner.segments.add(size=segment_info.size) program_input = json.load(args.program_input) if args.program_input else {} runner.initialize_vm(hint_locals={'program_input': program_input}) try: if args.no_end: assert args.steps is not None, '--steps must specified when running with --no-end.' else: additional_steps = 1 if args.proof_mode else 0 max_steps = steps_input - additional_steps if steps_input is not None else None runner.run_until_pc(end, max_steps=max_steps) if args.proof_mode: # Run one more step to make sure the last pc that was executed (rather than the pc # after it) is __end__. runner.run_for_steps(1) runner.original_steps = runner.vm.current_step if args.min_steps: runner.run_until_steps(args.min_steps) if steps_input is not None: runner.run_until_steps(steps_input) elif args.proof_mode: runner.run_until_next_power_of_2() while not runner.check_used_cells(): runner.run_for_steps(1) runner.run_until_next_power_of_2() runner.end_run() except (VmException, AssertionError) as exc: if args.debug_error: print(f'Got an error:\n{exc}') ret_code = 1 else: raise exc if not args.no_end: runner.read_return_values() if args.no_end or not args.proof_mode: runner.finalize_segments_by_effective_size() else: # Finalize important segments by correct size. runner.finalize_segments() # Finalize all user segments by effective size. runner.finalize_segments_by_effective_size() if args.secure_run: verify_secure_runner(runner) if args.cairo_pie_output: runner.get_cairo_pie().to_file(args.cairo_pie_output) runner.relocate() if args.print_memory: runner.print_memory(relocated=args.relocate_prints) if args.print_output: runner.print_output() if args.print_info: runner.print_info(relocated=args.relocate_prints) # Skip builtin usage calculation if the execution stopped before reaching the end symbol. # Trying to calculate the builtin usage is likely to raise an exception and prevent the user # from opening the tracer. if args.proof_mode and not args.no_end: runner.print_builtin_usage() if trace_file is not None: field_bytes = math.ceil(program.prime.bit_length() / 8) write_binary_trace(trace_file, runner.relocated_trace) if memory_file is not None: field_bytes = math.ceil(program.prime.bit_length() / 8) write_binary_memory(memory_file, runner.relocated_memory, field_bytes) if args.air_public_input is not None: rc_min, rc_max = runner.get_perm_range_check_limits() write_air_public_input( layout=args.layout, public_input_file=args.air_public_input, memory=runner.relocated_memory, public_memory_addresses=runner.segments. get_public_memory_addresses(runner.segment_offsets), memory_segment_addresses=runner.get_memory_segment_addresses(), trace=runner.relocated_trace, rc_min=rc_min, rc_max=rc_max) if args.air_private_input is not None: assert args.trace_file is not None, \ '--trace_file must be set when --air_private_input is set.' assert args.memory_file is not None, \ '--memory_file must be set when --air_private_input is set.' json.dump( { 'trace_path': f'{os.path.abspath(trace_file.name)}', 'memory_path': f'{os.path.abspath(memory_file.name)}', **runner.get_air_private_input(), }, args.air_private_input, indent=4) print(file=args.air_private_input) args.air_private_input.flush() if debug_info_file is not None: json.dump(DebugInfo.Schema().dump(runner.get_relocated_debug_info()), debug_info_file) debug_info_file.flush() if args.tracer: CAIRO_TRACER = 'starkware.cairo.lang.tracer.tracer' subprocess.call( list( filter(None, [ sys.executable, '-m', CAIRO_TRACER, f'--program={args.program.name}', f'--trace={trace_file.name}', f'--memory={memory_file.name}', f'--air_public_input={args.air_public_input.name}' if args.air_public_input else None, f'--debug_info={debug_info_file.name}', ]))) return ret_code
def cairo_run(args): trace_needed = args.tracer or args.profile_output is not None trace_file = args.trace_file if trace_file is None and trace_needed: # If --tracer or --profile_output is used, use a temporary file as trace_file. trace_file = tempfile.NamedTemporaryFile(mode='wb') memory_file = args.memory_file if memory_file is None and trace_needed: # If --tracer or --profile_output is used, use a temporary file as memory_file. memory_file = tempfile.NamedTemporaryFile(mode='wb') debug_info_file = args.debug_info_file if debug_info_file is None and trace_needed: # If --tracer or --profile_output is used, use a temporary file as debug_info_file. debug_info_file = tempfile.NamedTemporaryFile(mode='w') ret_code = 0 cairo_pie_input = None if args.program is not None: program: ProgramBase = load_program(args.program) initial_memory = MemoryDict() steps_input = args.steps else: assert args.run_from_cairo_pie is not None assert args.steps is None and args.min_steps is None, \ '--steps and --min_steps cannot be specified in --run_from_cairo_pie mode.' cairo_pie_input = CairoPie.from_file(args.run_from_cairo_pie) try: cairo_pie_input.run_validity_checks() except Exception as exc: # Trim error message in case it's too long. msg = str(exc)[:10000] raise CairoRunError( f'Security check for the CairoPIE input failed: {msg}') program = cairo_pie_input.program initial_memory = cairo_pie_input.memory steps_input = cairo_pie_input.execution_resources.n_steps runner = CairoRunner(program=program, layout=args.layout, memory=initial_memory, proof_mode=args.proof_mode) runner.initialize_segments() end = runner.initialize_main_entrypoint() if args.run_from_cairo_pie is not None: # Add extra_segments. for segment_info in cairo_pie_input.metadata.extra_segments: runner.segments.add(size=segment_info.size) # Update the builtin runners' additional_data. for name, builtin_runner in runner.builtin_runners.items(): if name in cairo_pie_input.additional_data: builtin_runner.extend_additional_data( data=cairo_pie_input.additional_data[name], relocate_callback=lambda x: x, data_is_trusted=not args.secure_run) program_input = json.load(args.program_input) if args.program_input else {} runner.initialize_vm(hint_locals={'program_input': program_input}) try: if args.no_end: assert args.steps is not None, '--steps must be specified when running with --no-end.' else: additional_steps = 1 if args.proof_mode else 0 max_steps = steps_input - additional_steps if steps_input is not None else None runner.run_until_pc(end, max_steps=max_steps) if args.proof_mode: # Run one more step to make sure the last pc that was executed (rather than the pc # after it) is __end__. runner.run_for_steps(1) runner.original_steps = runner.vm.current_step if args.min_steps: runner.run_until_steps(args.min_steps) disable_trace_padding = False if steps_input is not None: runner.run_until_steps(steps_input) disable_trace_padding = True runner.end_run(disable_trace_padding=disable_trace_padding) except (VmException, AssertionError) as exc: if args.debug_error: print(f'Got an error:\n{exc}') ret_code = 1 else: raise exc if not args.no_end: runner.read_return_values() if not args.no_end and args.proof_mode: # Finalize important segments by correct size. runner.finalize_segments() if args.secure_run: verify_secure_runner(runner) if args.run_from_cairo_pie is not None: assert cairo_pie_input is not None assert cairo_pie_input == runner.get_cairo_pie(), \ 'The Cairo PIE input is not identical to the resulting Cairo PIE. ' \ 'This may indicate that the Cairo PIE was not generated by cairo_run.' if args.cairo_pie_output: runner.get_cairo_pie().to_file(args.cairo_pie_output) runner.relocate() if args.print_memory: runner.print_memory(relocated=args.relocate_prints) if args.print_output: runner.print_output() if args.print_info: runner.print_info(relocated=args.relocate_prints) # Skip builtin usage calculation if the execution stopped before reaching the end symbol. # Trying to calculate the builtin usage is likely to raise an exception and prevent the user # from opening the tracer. if args.proof_mode and not args.no_end: runner.print_builtin_usage() if trace_file is not None: field_bytes = math.ceil(program.prime.bit_length() / 8) write_binary_trace(trace_file, runner.relocated_trace) if memory_file is not None: field_bytes = math.ceil(program.prime.bit_length() / 8) write_binary_memory(memory_file, runner.relocated_memory, field_bytes) if args.air_public_input is not None: rc_min, rc_max = runner.get_perm_range_check_limits() write_air_public_input( layout=args.layout, public_input_file=args.air_public_input, memory=runner.relocated_memory, public_memory_addresses=runner.segments. get_public_memory_addresses(runner.segment_offsets), memory_segment_addresses=runner.get_memory_segment_addresses(), trace=runner.relocated_trace, rc_min=rc_min, rc_max=rc_max) if args.air_private_input is not None: assert args.trace_file is not None, \ '--trace_file must be set when --air_private_input is set.' assert args.memory_file is not None, \ '--memory_file must be set when --air_private_input is set.' json.dump( { 'trace_path': f'{os.path.abspath(trace_file.name)}', 'memory_path': f'{os.path.abspath(memory_file.name)}', **runner.get_air_private_input(), }, args.air_private_input, indent=4) print(file=args.air_private_input) args.air_private_input.flush() if debug_info_file is not None: json.dump(DebugInfo.Schema().dump(runner.get_relocated_debug_info()), debug_info_file) debug_info_file.flush() if args.tracer: CAIRO_TRACER = 'starkware.cairo.lang.tracer.tracer' subprocess.call( list( filter(None, [ sys.executable, '-m', CAIRO_TRACER, f'--program={args.program.name}', f'--trace={trace_file.name}', f'--memory={memory_file.name}', f'--air_public_input={args.air_public_input.name}' if args.air_public_input else None, f'--debug_info={debug_info_file.name}', ]))) if args.profile_output is not None: CAIRO_PROFILER = 'starkware.cairo.lang.tracer.profiler' subprocess.call( list( filter(None, [ sys.executable, '-m', CAIRO_PROFILER, f'--program={args.program.name}', f'--trace={trace_file.name}', f'--memory={memory_file.name}', f'--air_public_input={args.air_public_input.name}' if args.air_public_input else None, f'--debug_info={debug_info_file.name}', f'--profile_output={args.profile_output}', ]))) return ret_code