Beispiel #1
0
def run_single(code: str,
               steps: int,
               *,
               pc=RelocatableValue(0, 10),
               ap=100,
               fp=100,
               extra_mem={}):
    program = compile_cairo(code, PRIME, debug_info=True)

    # Set memory[fp - 1] to an arbitrary value, since [fp - 1] is assumed to be set.
    memory: Dict[MaybeRelocatable, MaybeRelocatable] = {
        **{pc + i: v
           for i, v in enumerate(program.data)}, fp - 1: 1234,
        **extra_mem
    }
    context = RunContext(
        pc=pc,
        ap=ap,
        fp=fp,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})
    for _ in range(steps):
        vm.step()
    return vm
Beispiel #2
0
def test_jmp_segment():
    code = """
    jmp abs [ap]; ap++
    """
    program = compile_cairo(code=code, prime=PRIME, debug_info=True)

    program_base_a = RelocatableValue(0, 10)
    program_base_b = RelocatableValue(1, 20)

    memory = {
        **{program_base_a + i: v
           for i, v in enumerate(program.data)},
        **{program_base_b + i: v
           for i, v in enumerate(program.data)}, 99: 0,
        100: program_base_b,
        101: program_base_a
    }
    context = RunContext(
        pc=program_base_a,
        ap=100,
        fp=100,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})
    vm.step()
    assert vm.run_context.pc == program_base_b
    assert vm.get_location(vm.run_context.pc) is None
    vm.step()
    assert vm.run_context.pc == program_base_a
    assert vm.get_location(vm.run_context.pc) is not None
    def initialize_vm(self,
                      hint_locals,
                      static_locals: Optional[Dict[str, Any]] = None,
                      vm_class=VirtualMachine):
        context = RunContext(
            pc=self.initial_pc,
            ap=self.initial_ap,
            fp=self.initial_fp,
            memory=self.memory,
            prime=self.program.prime,
        )

        if static_locals is None:
            static_locals = {}

        self.vm = vm_class(
            self.program,
            context,
            hint_locals=hint_locals,
            static_locals=dict(segments=self.segments, **static_locals),
            builtin_runners=self.builtin_runners,
            program_base=self.program_base,
        )

        for builtin_runner in self.builtin_runners.values():
            builtin_runner.add_validation_rules(self)
            builtin_runner.add_auto_deduction_rules(self)

        self.vm.validate_existing_memory()
Beispiel #4
0
    def __init__(self,
                 program: Program,
                 memory: MemoryDict,
                 trace: List[TraceEntry],
                 air_public_input: Optional[PublicInput] = None,
                 debug_info: Optional[DebugInfo] = None):
        self.program = program
        self.memory = memory
        self.trace = trace
        self.debug_info = debug_info if debug_info is not None else program.debug_info

        # Read AIR public input, if available and extract public memory addresses.
        if air_public_input is not None:
            self.public_memory: List[int] = [
                x.address for x in air_public_input.public_memory
            ]
        else:
            self.public_memory = []

        self.input_files: Dict[str, InputCodeFile] = {}

        if self.debug_info is not None:
            # Process each instruction in the program and surround it by a <span> tag.
            for pc, instruction_location in self.debug_info.instruction_locations.items(
            ):
                loc = instruction_location.inst
                filename = loc.input_file.filename
                # If filename was not loaded yet, create a new InputCodeFile instance.
                if filename not in self.input_files:
                    self.input_files[filename] = InputCodeFile(
                        loc.input_file.get_content())
                input_file = self.input_files[filename]

                # Surround the instruction code with a <span> tag.
                input_file.mark_text(loc.start_line, loc.start_col,
                                     loc.end_line, loc.end_col,
                                     [f'inst{pc}', 'instruction'])

        # Find memory accesses for each step.
        self.memory_accesses = []
        for trace_entry in self.trace:
            run_context = RunContext(pc=trace_entry.pc,
                                     ap=trace_entry.ap,
                                     fp=trace_entry.fp,
                                     memory=self.memory,
                                     prime=self.program.prime)
            instruction_encoding, imm = run_context.get_instruction_encoding()
            instruction = decode_instruction(instruction_encoding, imm)

            dst_addr = run_context.compute_dst_addr(instruction)
            op0_addr = run_context.compute_op0_addr(instruction)
            op1_addr = run_context.compute_op1_addr(instruction,
                                                    self.memory.get(op0_addr))
            self.memory_accesses.append({
                'dst': dst_addr,
                'op0': op0_addr,
                'op1': op1_addr
            })
Beispiel #5
0
def test_hint_exception():
    code = """
# Some comment.

%{ x = 0 %}

%{
def f():
    0 / 0  # Raises exception.
%}
[ap] = 0; ap++

%{ y = 0 %}
%{


f()
%}
[ap] = 1; ap++
"""

    # In this test we actually do write the code to a file, to allow the linecache module to fetch
    # the line raising the exception.
    cairo_file = tempfile.NamedTemporaryFile('w')
    print(code, file=cairo_file)
    cairo_file.flush()
    program = compile_cairo(code=[(code, cairo_file.name)],
                            prime=PRIME,
                            debug_info=True)
    program_base = 10
    memory = {program_base + i: v for i, v in enumerate(program.data)}

    # Set memory[fp - 1] to an arbitrary value, since [fp - 1] is assumed to be set.
    memory[99] = 1234

    context = RunContext(
        pc=program_base,
        ap=200,
        fp=100,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})

    vm.step()
    with pytest.raises(VmException) as excinfo:
        vm.step()
    assert str(excinfo.value) == f"""\
Beispiel #6
0
def test_skip_instruction_execution():
    code = """
%{
    x = 0
    vm.run_context.pc += 2
    vm.skip_instruction_execution = True
%}
[ap] = [ap] + 1; ap++ # This intruction will not be executed.
%{
    x = 1
%}
[ap] = 10; ap++
    """

    program = compile_cairo(code, PRIME, debug_info=True)

    initial_ap = 100
    memory: Dict[MaybeRelocatable, MaybeRelocatable] = {
        **{i: v
           for i, v in enumerate(program.data)},
        initial_ap - 1: 1234,
    }
    context = RunContext(
        pc=0,
        ap=initial_ap,
        fp=initial_ap,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})
    vm.enter_scope({'vm': vm})
    exec_locals = vm.exec_scopes[-1]

    assert 'x' not in exec_locals
    assert vm.run_context.pc == 0
    vm.step()
    assert exec_locals['x'] == 0
    assert vm.run_context.pc == 2
    vm.step()
    assert exec_locals['x'] == 1
    assert vm.run_context.pc == 4
    assert vm.run_context.ap == initial_ap + 1
    assert vm.run_context.memory[vm.run_context.ap - 1] == 10
    vm.exit_scope()
Beispiel #7
0
    def initialize_vm(self, hint_locals, vm_class=VirtualMachine):
        context = RunContext(
            pc=self.initial_pc,
            ap=self.initial_ap,
            fp=self.initial_fp,
            memory=self.memory,
            prime=self.program.prime,
        )

        self.vm = vm_class(
            self.program,
            context,
            hint_locals=hint_locals,
            static_locals=dict(segments=self.segments),
            builtin_runners=self.builtin_runners,
            program_base=self.program_base,
        )

        for builtin_runner in self.builtin_runners.values():
            builtin_runner.add_validation_rules(self)
            builtin_runner.add_auto_deduction_rules(self)
Beispiel #8
0
def test_memory_validation_in_hints():
    code = """
%{ memory[ap] = 0 %}
[ap] = [ap]; ap++
%{ memory[ap] = 0 %}
[ap] = [ap]; ap++
"""

    program = compile_cairo(code=code, prime=PRIME, debug_info=True)
    initial_ap_and_fp = RelocatableValue(segment_index=1, offset=200)
    memory = {i: v for i, v in enumerate(program.data)}
    # Set memory[fp - 1] to an arbitrary value, since [fp - 1] is assumed to be set.
    memory[initial_ap_and_fp - 1] = 1234

    context = RunContext(
        pc=0,
        ap=initial_ap_and_fp,
        fp=initial_ap_and_fp,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})

    vm.add_validation_rule(1, lambda memory, addr: {addr})
    assert vm.validated_memory._ValidatedMemoryDict__validated_addresses == set(
    )
    vm.step()
    assert vm.validated_memory._ValidatedMemoryDict__validated_addresses == {
        initial_ap_and_fp
    }

    def fail_validation(memory, addr):
        raise Exception('Validation failed.')

    vm.add_validation_rule(1, fail_validation)
    with pytest.raises(VmException, match='Exception: Validation failed.'):
        vm.step()
Beispiel #9
0
def test_auto_deduction_rules():
    code = """
[fp + 1] = [fp] + [ap]
"""

    program = compile_cairo(code=code, prime=PRIME, debug_info=True)
    memory = {i: v for i, v in enumerate(program.data)}
    initial_ap = RelocatableValue(segment_index=1, offset=200)
    initial_fp = RelocatableValue(segment_index=2, offset=100)

    context = RunContext(
        pc=0,
        ap=initial_ap,
        fp=initial_fp,
        memory=MemoryDict(memory),
        prime=PRIME,
    )

    vm = VirtualMachine(program, context, {})

    def rule_ap_segment(vm, addr, val):
        return val

    vm.add_auto_deduction_rule(1, rule_ap_segment, 100)
    vm.add_auto_deduction_rule(2, lambda vm, addr: None)
    vm.add_auto_deduction_rule(
        2, lambda vm, addr: 200 if addr == initial_fp else None)
    vm.add_auto_deduction_rule(2, lambda vm, addr: 456)

    vm.step()

    assert vm.run_context.memory[initial_ap] == 100
    assert vm.run_context.memory[initial_fp] == 200
    assert vm.run_context.memory[initial_fp + 1] == 300

    with pytest.raises(InconsistentAutoDeductionError,
                       match='at address 2:100. 200 != 456'):
        vm.verify_auto_deductions()