Пример #1
0
    def test_tzt(self) -> None:
        parser = MichelsonParser()
        for filename in listdir(self.path):
            if filename in self.exclude:
                continue
            with self.subTest(filename):
                filename = join(self.path, filename)
                with open(filename) as file:
                    script = michelson_to_micheline(
                        file.read(),
                        parser=parser,
                    )

                    Interpreter.run_tzt(script=script)
Пример #2
0
    def callback_view(self):
        """Get return value of an on-chain callback method.

        :returns: Decoded parameters of a callback
        """
        if self.address:
            initial_storage = self.shell.blocks[
                self.context.block_id].context.contracts[
                    self.address].storage()
        else:
            storage_ty = StorageSection.match(self.context.storage_expr)
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)

        operations, _, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            context=self.context,
        )
        if not len(operations) == 1:
            raise Exception(
                'Multiple internal operations, not sure which one to pick')
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        return operations[0]
Пример #3
0
    def interpret(
        self,
        storage=None,
        source=None,
        sender=None,
        amount=None,
        balance=None,
        chain_id=None,
        level=None,
        now=None,
        self_address=None,
    ) -> ContractCallResult:
        """Run code in the builtin REPL (WARNING! Not recommended for critical tasks).

        :param storage: initial storage as Python object, leave None if you want to generate a dummy one
        :param source: patch SOURCE
        :param sender: patch SENDER
        :param amount: patch AMOUNT
        :param balance: patch BALANCE
        :param chain_id: patch CHAIN_ID
        :param level: patch LEVEL
        :param now: patch NOW
        :param self_address: patch SELF/SELF_ADDRESS
        :rtype: pytezos.contract.result.ContractCallResult
        """
        storage_ty = StorageSection.match(self.context.storage_expr)
        if storage is None:
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)
        else:
            initial_storage = storage_ty.from_python_object(
                storage).to_micheline_value(lazy_diff=True)
        assert self.context.script
        operations, storage, lazy_diff, stdout, error = Interpreter.run_code(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            script=self.context.script['code'],
            source=source,
            sender=sender or source,
            amount=amount or self.amount,
            balance=balance,
            chain_id=chain_id,
            level=level,
            now=now,
            address=self_address,
        )
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        res = {
            'operations': operations,
            'storage': storage,
            'lazy_diff': lazy_diff,
        }
        return ContractCallResult.from_run_code(
            res,
            parameters=self.parameters,
            context=self.context,
        )
Пример #4
0
    def test_failed_macros(self, filename, storage, parameter):
        with open(join(dirname(__file__), 'macros', filename)) as f:
            script = f.read()

        _, _, _, _, error = Interpreter.run_code(
            parameter=michelson_to_micheline(parameter),
            storage=michelson_to_micheline(storage),
            script=michelson_to_micheline(script))
        self.assertIsNotNone(error)
Пример #5
0
    def test_execute(self) -> None:
        # Arrange
        interpreter = Interpreter()
        code = "PUSH int 1; PUSH int 2; PAIR"

        # Act
        result = interpreter.execute(code)

        # Assert
        self.assertEqual(None, result.error)
        self.assertEqual(
            [
                "PUSH / _ => 1",
                "PUSH / _ => 2",
                "PAIR / 2 : 1 => (2 * 1)",
            ],
            result.stdout,
        )
        self.assertEqual([PairType((IntType(2), IntType(1)))], interpreter.stack.items)
Пример #6
0
    def test_execution(self, filename, parameter, storage, result):
        with open(join(dirname(__file__), 'execution', filename)) as f:
            script = f.read()

        _, storage, lazy_diff, stdout, error = Interpreter.run_code(
            parameter=michelson_to_micheline(parameter),
            storage=michelson_to_micheline(storage),
            script=michelson_to_micheline(script),
        )
        self.assertIsNone(error)
        self.assertEqual(storage, result)
Пример #7
0
    def test_macros(self, filename, storage, parameter, result):
        with open(join(dirname(__file__), 'macros', filename)) as f:
            script = f.read()

        _, storage, _, stdout, error = Interpreter.run_code(
            parameter=michelson_to_micheline(parameter),
            storage=michelson_to_micheline(storage),
            script=michelson_to_micheline(script))
        if error:
            print('\n'.join(stdout))
            raise error
        self.assertEqual(michelson_to_micheline(result), storage)
Пример #8
0
    def test_execute_rollback(self) -> None:
        # Arrange
        interpreter = Interpreter()
        code = "PUSH int 1; PUSH int 2; PAIR"
        bad_code = "PUSH int 1; PAIR; PAIR;"

        # Act
        interpreter.execute(code)
        result = interpreter.execute(bad_code)

        # Assert
        self.assertIsInstance(result.error, MichelsonRuntimeError)
        self.assertEqual(
            [
                "PUSH / _ => 1",
                "PAIR / 1 : (2 * 1) => (1 * (2 * 1))",
                "PAIR: got 1 items on the stack, want to pop 2",
            ],
            result.stdout,
        )
        self.assertEqual([PairType((IntType(2), IntType(1)))], interpreter.stack.items)
Пример #9
0
    def test_execute_contract(self) -> None:
        # Arrange
        interpreter = Interpreter()
        code = """
            storage unit ;
            parameter unit ;
            BEGIN Unit Unit ;
            DROP ;
            PUSH unit Unit ;
            NIL operation ;
            PAIR ;
            COMMIT ;
        """

        # Act
        result = interpreter.execute(code)

        # Assert
        self.assertEqual(None, result.error)
        self.assertEqual(
            [
                "storage: updated",
                "parameter: updated",
                "BEGIN %default / _ => (Unit * Unit)",
                "DROP / (Unit * Unit) => _",
                "PUSH / _ => Unit",
                "NIL / _ => []",
                "PAIR / [] : Unit => ([] * Unit)",
                "END %default / ([] * Unit) => _",
            ],
            result.stdout,
        )
        self.assertEqual(
            [],
            interpreter.stack.items,
        )
Пример #10
0
    def storage_view(self):
        """Get return value of an off-chain storage view.

        :returns: Decoded parameters of a callback
        """
        _, storage, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage={'prim': 'None'},
            context=self.context,
        )
        if error:
            logger.debug('\n'.join(stdout))
            raise error
        return storage  # type: ignore
Пример #11
0
    def test_big_map_opcodes(self, filename, storage, parameter, result,
                             big_map_log):
        with open(join(dirname(__file__), 'opcodes', filename)) as f:
            script = f.read()

        _, storage, lazy_diff, stdout, error = Interpreter.run_code(
            parameter=michelson_to_micheline(parameter),
            storage=michelson_to_micheline(storage),
            script=michelson_to_micheline(script),
            output_mode='optimized')
        if error:
            print('\n'.join(stdout))
            raise error
        self.assertEqual(michelson_to_micheline(result), storage)
        log = list(iter_lazy_diff(lazy_diff))
        self.assertEqual(sorted(big_map_log), sorted(log))
Пример #12
0
    def view(self):
        """ Get return value of a view method.

        :returns: Decoded parameters of a callback
        """
        if self.address:
            initial_storage = self.shell.blocks[
                self.context.block_id].context.contracts[
                    self.address].storage()
        else:
            storage_ty = StorageSection.match(self.context.storage_expr)
            initial_storage = storage_ty.dummy(
                self.context).to_micheline_value(lazy_diff=True)

        res, stdout, error = Interpreter.run_view(
            parameter=self.parameters['value'],
            entrypoint=self.parameters['entrypoint'],
            storage=initial_storage,
            context=self.context)
        if error:
            print('\n'.join(stdout))
            raise error
        return res
Пример #13
0
    def test_execute_contract_big_map(self) -> None:
        # Arrange
        interpreter = Interpreter()
        code = """
            storage (big_map string nat) ;
            parameter unit ;
            BEGIN Unit {};
                DROP ;
                EMPTY_BIG_MAP string nat ;
                PUSH nat 15 ;
                SOME ;
                PUSH string "cherry" ;
                UPDATE ;
                PUSH nat 22 ;
                SOME ;
                PUSH string "banana" ;
                UPDATE ;
                DUP ;
                PUSH string "cherry" ;
                DUP ;
                SWAP ;
                DIP { SWAP } ;
                MEM ;
                IF
                    { 
                        DIP { DUP } ;
                        DUP ;
                        DIP { SWAP } ;
                        GET ;
                        IF_SOME
                            { PUSH nat 5 ; ADD ; SOME ; SWAP ; UPDATE }
                            { DROP }
                    }
                    { DROP } ;
                NIL operation ;
                PAIR ;
            COMMIT ;
        """

        # Act
        result = interpreter.execute(code)

        # Assert
        self.assertEqual(None, result.error)
        self.assertEqual(
            [
                "storage: updated",
                "parameter: updated",
                "BEGIN %default / _ => (Unit * <-1>)",
                "DROP / (Unit * <-1>) => _",
                "EMPTY_BIG_MAP / _ => <-2>",
                "PUSH / _ => 15",
                "SOME / 15 => 15?",
                "PUSH / _ => 'cherry'",
                "UPDATE / 'cherry' : 15? : <-2> => <-2>",
                "PUSH / _ => 22",
                "SOME / 22 => 22?",
                "PUSH / _ => 'banana'",
                "UPDATE / 'banana' : 22? : <-2> => <-2>",
                "DUP / <-2> => <-2> : <-2>",
                "PUSH / _ => 'cherry'",
                "DUP / 'cherry' => 'cherry' : 'cherry'",
                "SWAP / 'cherry' : 'cherry' => 'cherry' : 'cherry'",
                "DIP / * => _",
                "SWAP / 'cherry' : <-2> => <-2> : 'cherry'",
                "DIP 1 / _ => *",
                "MEM / 'cherry' : <-2> => True",
                "IF / True => _",
                "DIP / * => _",
                "DUP / <-2> => <-2> : <-2>",
                "DIP 1 / _ => *",
                "DUP / 'cherry' => 'cherry' : 'cherry'",
                "DIP / * => _",
                "SWAP / 'cherry' : <-2> => <-2> : 'cherry'",
                "DIP 1 / _ => *",
                "GET / 'cherry' : <-2> => 15?",
                "IF_NONE / 15? => 15",
                "PUSH / _ => 5",
                "ADD / 5 : 15 => 20",
                "SOME / 20 => 20?",
                "SWAP / 20? : 'cherry' => 'cherry' : 20?",
                "UPDATE / 'cherry' : 20? : <-2> => <-2>",
                "NIL / _ => []",
                "PAIR / [] : <-2> => ([] * <-2>)",
                "END %default / ([] * <-2>) => _",
            ],
            result.stdout,
        )
        self.assertEqual(
            [],
            interpreter.stack.items,
        )
        self.assertEqual({}, interpreter.context.big_maps)
        commit_instruction = next((i for i in result.instructions.items[::-1]
                                   if isinstance(i, CommitInstruction)))
        self.assertEqual(
            [{
                "diff": {
                    "action":
                    "alloc",
                    "key_type": {
                        "prim": "string"
                    },
                    "updates": [
                        {
                            "key": {
                                "string": "banana"
                            },
                            "key_hash":
                            "expruyWGhjeJ3v2cWgMkRyYuvbdZKjjARtHvhVeJDCyHgLebMmhBEo",
                            "value": {
                                "int": "22"
                            },
                        },
                        {
                            "key": {
                                "string": "cherry"
                            },
                            "key_hash":
                            "expruVgSSodFW5ZDLidXaTVVczu6ddLVebXjMZBG33Z2oyQDUugvdE",
                            "value": {
                                "int": "20"
                            },
                        },
                    ],
                    "value_type": {
                        "prim": "nat"
                    },
                },
                "id": "0",
                "kind": "big_map",
            }],
            commit_instruction.lazy_diff,
        )
Пример #14
0
    def test_execute_contract_operations(self) -> None:
        # Arrange
        interpreter = Interpreter()
        code = """
            PATCH SENDER "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" ;
            PATCH BALANCE 200 ;
            
            parameter mutez ;
            storage unit ;
            
            BEGIN 100 Unit ;
            
                CAR ;
                DUP ;
                BALANCE ;
                IFCMPLT
                    { FAIL }
                    {
                        SENDER ;
                        CONTRACT unit ;
                        IF_NONE
                            { FAIL }
                            {
                                SWAP ;
                                UNIT ;
                                TRANSFER_TOKENS ;
                                NIL operation ;
                                SWAP ;
                                CONS ;
                                UNIT ;
                                SWAP ;
                                PAIR
                            } ;
                    };
            COMMIT
        """

        # Act
        result = interpreter.execute(code)

        # Assert
        self.assertEqual(None, result.error)
        self.assertEqual(
            [
                "parameter: updated",
                "storage: updated",
                "BEGIN %default / _ => (0.0001 * Unit)",
                "CAR / (0.0001 * Unit) => 0.0001",
                "DUP / 0.0001 => 0.0001 : 0.0001",
                "BALANCE / _ => 0.0002",
                "COMPARE / 0.0002 : 0.0001 => 1",
                "LT / 1 => False",
                "IF / False => _",
                "SENDER / _ => tz1VSU…cjb",
                "CONTRACT: skip type checking for tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb",
                "CONTRACT / tz1VSU…cjb => tz1VSU…cjb%default?",
                "IF_NONE / tz1VSU…cjb%default? => tz1VSU…cjb%default",
                "SWAP / tz1VSU…cjb%default : 0.0001 => 0.0001 : tz1VSU…cjb%default",
                "UNIT / _ => Unit",
                "TRANSFER_TOKENS / Unit : 0.0001 : tz1VSU…cjb%default => transaction",
                "NIL / _ => []",
                "SWAP / [] : transaction => transaction : []",
                "CONS / transaction : [] => [transaction]",
                "UNIT / _ => Unit",
                "SWAP / Unit : [transaction] => [transaction] : Unit",
                "PAIR / [transaction] : Unit => ([transaction] * Unit)",
                "END %default / ([transaction] * Unit) => _",
            ],
            result.stdout,
        )
        commit_instruction = next((i for i in result.instructions.items[::-1]
                                   if isinstance(i, CommitInstruction)))
        self.assertEqual(
            PairType((
                ListType([
                    OperationType({
                        "kind": "transaction",
                        "source": "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi",
                        "destination": "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb",
                        "amount": "100",
                        "parameters": {
                            "entrypoint": "default",
                            "value": {
                                "prim": "Unit"
                            },
                        },
                    })
                ]),
                UnitType(),
            )),
            commit_instruction.result,
        )
Пример #15
0
 def __init__(self, **kwargs):
     super(MichelsonKernel, self).__init__(**kwargs)
     self.interpreter = Interpreter()
Пример #16
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self.interpreter = Interpreter()
Пример #17
0
class MichelsonKernel(Kernel):
    implementation = 'IMichelson'
    implementation_version = __version__
    language_info = {
        'name': 'Michelson',
        'mimetype': 'text/x-michelson',
        'file_extension': '.tz',
        'codemirror_mode': 'michelson',
    }
    banner = 'Michelson (Tezos VM language)'
    help_links = [
        'https://michelson.nomadic-labs.com/',
        'https://tezos.gitlab.io/whitedoc/michelson.html',
    ]

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.interpreter = Interpreter()

    def _stdout(self, text: str) -> None:
        self.send_response(
            self.iopub_socket,
            'stream',
            {
                'name': 'stdout',
                'text': text,
            },
        )

    def _find_stack_items(self, instructions: MichelineSequence, stack: MichelsonStack) -> Optional[List[MichelsonInstruction]]:
        for operation in instructions.items[::-1]:
            items = getattr(operation, 'items', None)
            if isinstance(items, list):
                stack_items = self._find_stack_items(MichelineSequence(items), stack)
                if stack_items:
                    return stack_items
            if not isinstance(operation, MichelsonInstruction):
                continue
            if operation.stack_items_added:
                return cast(List[MichelsonInstruction], stack.items[-operation.stack_items_added :])
        return None

    def _find_lazy_diff(self, instructions: MichelineSequence) -> Optional[List[Dict[str, str]]]:
        for instruction in instructions.items[::-1]:
            if isinstance(instruction, CommitInstruction) and instruction.lazy_diff:
                return instruction.lazy_diff
            if isinstance(instruction, BigMapDiffInstruction) and instruction.lazy_diff:
                return instruction.lazy_diff
        return None

    def _find_contract_result(self, instructions: MichelineSequence) -> Optional[PairType]:
        for instruction in instructions.items[::-1]:
            if isinstance(instruction, MichelineSequence):
                return self._find_contract_result(instruction)
            if isinstance(
                instruction,
                (
                    CommitInstruction,
                    RunInstruction,
                ),
            ):
                return instruction.result
        return None

    def _send_success_response(self, instructions: MichelineSequence, stack: MichelsonStack) -> Dict[str, Any]:
        plain, html = '', ''

        contract_result = self._find_contract_result(instructions)
        if contract_result:
            header = 'Operations'
            table = preformat_operations_table(cast(List[OperationType], contract_result.items[0]))
            plain += plain_table(table, header)
            html += html_table(table, header)

            header = 'Storage'
            table = preformat_storage_table(contract_result.items[1])
            plain += plain_table(table, header)
            html += html_table(table, header)

        modified_items = self._find_stack_items(instructions, stack)
        if modified_items is not None and not contract_result:
            header = 'Stack updates'
            table = preformat_stack_table(modified_items)
            plain += plain_table(table, header)
            html += html_table(table, header)

        lazy_diff = self._find_lazy_diff(instructions)
        if lazy_diff:
            header = 'BigMap diff'
            lazy_diff_table = preformat_lazy_diff_table(lazy_diff)
            plain += plain_table(lazy_diff_table, header)
            html += html_table(lazy_diff_table, header)

        result = {
            'data': {
                'text/plain': plain,
                'text/html': html,
            },
            'metadata': {},
            'execution_count': self.execution_count,
        }

        self.send_response(
            self.iopub_socket,
            'execute_result',
            result,
        )
        return result

    def _send_fail_response(self, error: Exception) -> Dict[str, Any]:
        if isinstance(error, (MichelsonParserError, MichelsonRuntimeError)):
            traceback = [error.format_stdout()]
        else:
            traceback = format_exception(error.__class__, error, None)
        result = {
            'status': 'error',
            'ename': error.__class__.__name__,
            'evalue': str(error),
            'traceback': traceback,
        }
        self.send_response(
            self.iopub_socket,
            'stream',
            {
                'name': 'stderr',
                'text': '\n'.join(traceback),
            },
        )
        return result

    def do_execute(self, code, silent, store_history=True, user_expressions=None, allow_stdin=False):

        interpreter_result = self.interpreter.execute(code)

        if not silent and interpreter_result.stdout:
            self._stdout('\n'.join(interpreter_result.stdout))

        if not interpreter_result.error:
            if not silent:
                return self._send_success_response(interpreter_result.instructions, interpreter_result.stack)
        else:
            return self._send_fail_response(interpreter_result.error)
        return {}

    def do_complete(self, code, cursor_pos):
        token, begin_pos, end_pos = parse_token(code, cursor_pos)

        suggests = []
        for word_set in [prim_tags, static_macros]:
            for word in word_set:
                if word.startswith(token):
                    suggests.append(word)

        if suggests:
            res = {
                'matches': suggests,
                'cursor_start': begin_pos,
                'cursor_end': end_pos,
            }
        else:
            res = {
                'matches': [],
                'cursor_start': cursor_pos,
                'cursor_end': cursor_pos,
            }

        res['status'] = 'ok'
        return res

    def do_inspect(self, code, cursor_pos, detail_level=0):
        token, _, _ = parse_token(code, cursor_pos)
        docstring = docs.get(token)
        if docstring:
            res = {'found': True, 'data': {'text/plain': docstring}}
        else:
            res = {'found': False}

        res['status'] = 'ok'
        return res