def test_generate_manifest_file_abi_method_offset(self):
        path = self.get_contract_path('GenerationWithDecorator.py')
        manifest_path = path.replace('.py', '.manifest.json')

        compiler = Compiler()
        compiler.compile_and_save(path, path.replace('.py', '.nef'))
        methods: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Method)
        }
        self.assertGreater(len(methods), 0)

        output, manifest = self.get_output(path)
        self.assertTrue(os.path.exists(manifest_path))
        self.assertIn('abi', manifest)
        abi = manifest['abi']

        self.assertIn('methods', abi)
        abi_methods = abi['methods']
        self.assertGreater(len(abi['methods']), 0)

        for method in abi_methods:
            self.assertIn('name', method)
            self.assertIn('offset', method)
            self.assertIn(method['name'], methods)
            self.assertEqual(method['offset'],
                             methods[method['name']].start_address)
Example #2
0
    def test_declaration_with_type(self):
        path = '%s/boa3_test/test_sc/variable_test/DeclarationWithType.py' % self.dirname

        test_variable_id = 'a'
        test_method_id = 'Main'
        compiler = Compiler()

        expected_compiler_output = (
            Opcode.INITSLOT  # function signature
            + b'\x01' + b'\x00' + Opcode.PUSHNULL + Opcode.RET  # return
        )
        compiler_output = compiler.compile(path)
        self.assertEqual(expected_compiler_output, compiler_output)

        main_symbol_table: Dict[str, ISymbol] = self.get_compiler_analyser(
            compiler).symbol_table
        # the variable is local to a method, so it shouldn't be in the main symbol table
        self.assertFalse(test_variable_id in main_symbol_table)

        self.assertTrue(test_method_id in main_symbol_table)
        self.assertIsInstance(main_symbol_table[test_method_id], Method)
        method: Method = main_symbol_table[test_method_id]

        method_symbol_table: Dict[str, Variable] = method.symbols
        # the variable is local to this method, so it should be in the method symbol table
        self.assertTrue(test_variable_id in method_symbol_table)
Example #3
0
    def test_generate_manifest_file_with_imported_event(self):
        path = self.get_contract_path('GenerationWithImportedEvent.py')
        expected_manifest_output = path.replace('.py', '.manifest.json')
        compiler = Compiler()
        compiler.compile_and_save(path, path.replace('.py', '.nef'))
        events: Dict[str, Event] = {}
        for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items():
            if isinstance(method, Event):
                events[name] = method
                if method.name not in events:
                    events[method.name] = method

        output, manifest = self.get_output(path)
        self.assertTrue(os.path.exists(expected_manifest_output))
        self.assertIn('abi', manifest)
        abi = manifest['abi']

        self.assertIn('events', abi)
        self.assertEqual(1, len(abi['events']))

        for abi_event in abi['events']:
            self.assertIn('name', abi_event)
            self.assertIn(abi_event['name'], events)
            self.assertIn('parameters', abi_event)

            event_args = events[abi_event['name']].args
            for event_param in abi_event['parameters']:
                self.assertIn('name', event_param)
                self.assertIn(event_param['name'], event_args)
                self.assertIn('type', event_param)
                self.assertEqual(event_args[event_param['name']].type.abi_type,
                                 event_param['type'])
    def test_generate_manifest_file_with_nep5_transfer_event(self):
        path = self.get_contract_path('test_sc/event_test',
                                      'EventNep5Transfer.py')
        expected_manifest_output = path.replace('.py', '.manifest.json')
        compiler = Compiler()
        compiler.compile_and_save(path, path.replace('.py', '.nef'))
        events: Dict[str, Event] = {
            event.name: event
            for event in self.get_compiler_analyser(
                compiler).symbol_table.values() if isinstance(event, Event)
        }

        output, manifest = self.get_output(path)
        self.assertTrue(os.path.exists(expected_manifest_output))
        self.assertIn('abi', manifest)
        abi = manifest['abi']

        self.assertIn('methods', abi)
        self.assertEqual(1, len(abi['methods']))

        self.assertIn('events', abi)
        self.assertEqual(1, len(abi['events']))

        for abi_event in abi['events']:
            self.assertIn('name', abi_event)
            self.assertIn(abi_event['name'], events)
            self.assertIn('parameters', abi_event)

            event_args = events[abi_event['name']].args
            for event_param in abi_event['parameters']:
                self.assertIn('name', event_param)
                self.assertIn(event_param['name'], event_args)
                self.assertIn('type', event_param)
                self.assertEqual(event_args[event_param['name']].type.abi_type,
                                 event_param['type'])
Example #5
0
    def test_generate_manifest_file_with_event(self):
        path = '%s/boa3_test/test_sc/event_test/EventWithArgument.py' % self.dirname
        expected_manifest_output = path.replace('.py', '.manifest.json')
        compiler = Compiler()
        compiler.compile_and_save(path, path.replace('.py', '.nef'))
        events: Dict[str, Event] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Event)
        }

        output, manifest = self.get_output(path)
        self.assertTrue(os.path.exists(expected_manifest_output))
        self.assertIn('abi', manifest)
        abi = manifest['abi']

        self.assertIn('methods', abi)
        self.assertEqual(1, len(abi['methods']))

        self.assertIn('events', abi)
        self.assertEqual(1, len(abi['events']))

        for abi_event in abi['events']:
            self.assertIn('name', abi_event)
            self.assertIn(abi_event['name'], events)
            self.assertIn('parameters', abi_event)

            event_args = events[abi_event['name']].args
            for event_param in abi_event['parameters']:
                self.assertIn('name', event_param)
                self.assertIn(event_param['name'], event_args)
                self.assertIn('type', event_param)
                self.assertEqual(event_args[event_param['name']].type.abi_type,
                                 event_param['type'])
Example #6
0
    def test_generate_init_method(self):
        path = self.get_contract_path('test_sc/variable_test',
                                      'GlobalAssignmentWithType.py')

        compiler = Compiler()
        compiler.compile_and_save(path,
                                  path.replace('.py', '.nef'),
                                  debug=True)
        methods: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Method)
        }

        self.assertGreater(len(methods), 0)
        self.assertIn(constants.INITIALIZE_METHOD_ID, methods)
        init_method = methods[constants.INITIALIZE_METHOD_ID]

        output, manifest = self.get_output(path)
        self.assertIn('abi', manifest)
        abi = manifest['abi']

        self.assertIn('methods', abi)
        self.assertGreater(len(abi['methods']), 0)

        abi_init = next(method for method in abi['methods'] if 'name' in method
                        and method['name'] == constants.INITIALIZE_METHOD_ID)
        self.assertIsNotNone(abi_init)
        self.assertIn('offset', abi_init)
        self.assertEqual(init_method.start_address, abi_init['offset'])
        self.assertIn('parameters', abi_init)
        self.assertEqual(0, len(abi_init['parameters']))
        self.assertIn('returntype', abi_init)
        self.assertEqual(AbiType.Void, abi_init['returntype'])

        debug_info = self.get_debug_info(path)
        self.assertIn('methods', debug_info)
        self.assertGreater(len(debug_info['methods']), 0)

        debug_method = next(
            (method for method in debug_info['methods']
             if 'id' in method and method['id'] == str(id(init_method))), None)
        self.assertIsNotNone(debug_method)
        parsed_name = debug_method['name'].split(
            constants.VARIABLE_NAME_SEPARATOR)
        self.assertEqual(2, len(parsed_name))
        self.assertIn(parsed_name[-1], methods)

        # validate parameters
        self.assertIn('params', debug_method)
        self.assertEqual(0, len(debug_method['params']))

        # validate local variables
        self.assertIn('variables', debug_method)
        self.assertEqual(0, len(debug_method['variables']))

        # validate sequence points
        self.assertIn('sequence-points', debug_method)
        self.assertEqual(0, len(debug_method['sequence-points']))
Example #7
0
    def test_generate_nefdbgnfo_file(self):
        from boa3.model.type.itype import IType
        path = self.get_contract_path('GenerationWithDecorator.py')

        expected_nef_output = path.replace('.py', '.nefdbgnfo')
        compiler = Compiler()
        compiler.compile_and_save(path,
                                  path.replace('.py', '.nef'),
                                  debug=True)
        methods: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Method)
        }

        self.assertTrue(os.path.exists(expected_nef_output))
        debug_info = self.get_debug_info(path)
        self.assertNotIn('entrypoint', debug_info)
        self.assertIn('methods', debug_info)
        self.assertGreater(len(debug_info['methods']), 0)

        for debug_method in debug_info['methods']:
            self.assertIn('name', debug_method)
            parsed_name = debug_method['name'].split(
                constants.VARIABLE_NAME_SEPARATOR)
            self.assertEqual(2, len(parsed_name))
            self.assertIn(parsed_name[-1], methods)
            actual_method = methods[parsed_name[-1]]

            # validate id
            self.assertIn('id', debug_method)
            self.assertEqual(str(id(actual_method)), debug_method['id'])

            # validate parameters
            self.assertIn('params', debug_method)
            self.assertEqual(len(actual_method.args),
                             len(debug_method['params']))
            for var in debug_method['params']:
                self.assertEqual(
                    2, len(var.split(constants.VARIABLE_NAME_SEPARATOR)))
                param_id, param_type = var.split(
                    constants.VARIABLE_NAME_SEPARATOR)
                self.assertIn(param_id, actual_method.args)
                self.assertEqual(param_type,
                                 actual_method.args[param_id].type.abi_type)

            # validate local variables
            self.assertIn('variables', debug_method)
            self.assertEqual(len(actual_method.locals),
                             len(debug_method['variables']))
            for var in debug_method['variables']:
                self.assertEqual(
                    2, len(var.split(constants.VARIABLE_NAME_SEPARATOR)))
                var_id, var_type = var.split(constants.VARIABLE_NAME_SEPARATOR)
                self.assertIn(var_id, actual_method.locals)
                local_type = actual_method.locals[var_id].type
                self.assertEqual(
                    local_type.abi_type if isinstance(local_type, IType) else
                    AbiType.Any, var_type)
Example #8
0
    def test_generate_debug_info_with_multiple_flows(self):
        path = self.get_contract_path('GenerationWithMultipleFlows.py')

        compiler = Compiler()
        compiler.compile_and_save(path,
                                  path.replace('.py', '.nef'),
                                  debug=True)
        methods: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Method)
        }
        self.assertGreater(len(methods), 0)

        debug_info = self.get_debug_info(path)
        self.assertIn('methods', debug_info)
        self.assertGreater(len(debug_info['methods']), 0)

        for debug_method in debug_info['methods']:
            self.assertIn('name', debug_method)
            parsed_name = debug_method['name'].split(
                constants.VARIABLE_NAME_SEPARATOR)
            self.assertEqual(2, len(parsed_name))
            self.assertIn(parsed_name[-1], methods)
            actual_method = methods[parsed_name[-1]]

            # validate id
            self.assertIn('id', debug_method)
            self.assertEqual(str(id(actual_method)), debug_method['id'])

            # validate parameters
            self.assertIn('params', debug_method)
            self.assertEqual(len(actual_method.args),
                             len(debug_method['params']))
            for var in debug_method['params']:
                self.assertEqual(
                    2, len(var.split(constants.VARIABLE_NAME_SEPARATOR)))
                param_id, param_type = var.split(
                    constants.VARIABLE_NAME_SEPARATOR)
                self.assertIn(param_id, actual_method.args)
                self.assertEqual(param_type,
                                 actual_method.args[param_id].type.abi_type)

            # validate local variables
            self.assertIn('variables', debug_method)
            self.assertEqual(len(actual_method.locals),
                             len(debug_method['variables']))
            for var in debug_method['variables']:
                self.assertEqual(
                    2, len(var.split(constants.VARIABLE_NAME_SEPARATOR)))
                var_id, var_type = var.split(constants.VARIABLE_NAME_SEPARATOR)
                self.assertIn(var_id, actual_method.locals)
                self.assertEqual(actual_method.locals[var_id].type.abi_type,
                                 var_type)
Example #9
0
    def test_generate_nefdbgnfo_file(self):
        path = '%s/boa3_test/test_sc/generation_test/GenerationWithDecorator.py' % self.dirname

        expected_nef_output = path.replace('.py', '.nefdbgnfo')
        compiler = Compiler()
        compiler.compile_and_save(path, path.replace('.py', '.nef'))
        methods: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Method)
        }

        self.assertTrue(os.path.exists(expected_nef_output))
        debug_info = self.get_debug_info(path)
        self.assertNotIn('entrypoint', debug_info)
        self.assertIn('methods', debug_info)
        self.assertGreater(len(debug_info['methods']), 0)

        for debug_method in debug_info['methods']:
            self.assertIn('name', debug_method)
            parsed_name = debug_method['name'].split(',')
            self.assertEqual(2, len(parsed_name))
            self.assertIn(parsed_name[-1], methods)
            actual_method = methods[parsed_name[-1]]

            # validate id
            self.assertIn('id', debug_method)
            self.assertEqual(str(id(actual_method)), debug_method['id'])

            # validate parameters
            self.assertIn('params', debug_method)
            self.assertEqual(len(actual_method.args),
                             len(debug_method['params']))
            for var in debug_method['params']:
                self.assertEqual(2, len(var.split(',')))
                param_id, param_type = var.split(',')
                self.assertIn(param_id, actual_method.args)
                self.assertEqual(param_type,
                                 actual_method.args[param_id].type.abi_type)

            # validate local variables
            self.assertIn('variables', debug_method)
            self.assertEqual(len(actual_method.locals),
                             len(debug_method['variables']))
            for var in debug_method['variables']:
                self.assertEqual(2, len(var.split(',')))
                var_id, var_type = var.split(',')
                self.assertIn(var_id, actual_method.locals)
                self.assertEqual(actual_method.locals[var_id].type.abi_type,
                                 var_type)
Example #10
0
    def compile_and_save(path: str,
                         output_path: str = None,
                         root_folder: str = None,
                         show_errors: bool = True,
                         debug: bool = False):
        """
        Load a Python file to be compiled and save the result into the files.
        By default, the resultant .nef file is saved in the same folder of the
        source file.

        :param path: the path of the Python file to compile
        :param output_path: Optional path to save the generated files
        :param root_folder: the root path of the project
        :param show_errors: if compiler errors should be logged.
        :param debug: if nefdbgnfo file should be generated.
        """
        if not path.endswith('.py'):
            raise InvalidPathException(path)

        if output_path is None:
            output_path = path.replace('.py', '.nef')
        elif not output_path.endswith('.nef'):
            raise InvalidPathException(path)

        Compiler().compile_and_save(path, output_path, root_folder,
                                    show_errors, debug)
Example #11
0
    def test_generate_nefdbgnfo_file_with_event(self):
        path = self.get_contract_path('test_sc/event_test',
                                      'EventWithArgument.py')

        expected_nef_output = path.replace('.py', '.nefdbgnfo')
        compiler = Compiler()
        compiler.compile_and_save(path,
                                  path.replace('.py', '.nef'),
                                  debug=True)
        events: Dict[str, Event] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Event)
        }

        self.assertTrue(os.path.exists(expected_nef_output))
        debug_info = self.get_debug_info(path)
        self.assertNotIn('entrypoint', debug_info)
        self.assertIn('events', debug_info)
        self.assertGreater(len(debug_info['events']), 0)

        for debug_event in debug_info['events']:
            self.assertIn('name', debug_event)
            parsed_name = debug_event['name'].split(
                constants.VARIABLE_NAME_SEPARATOR)
            self.assertEqual(2, len(parsed_name))
            self.assertIn(parsed_name[-1], events)
            actual_event = events[parsed_name[-1]]

            # validate id
            self.assertIn('id', debug_event)
            self.assertEqual(str(id(actual_event)), debug_event['id'])

            # validate parameters
            self.assertIn('params', debug_event)
            self.assertEqual(len(actual_event.args),
                             len(debug_event['params']))
            for var in debug_event['params']:
                self.assertEqual(
                    2, len(var.split(constants.VARIABLE_NAME_SEPARATOR)))
                param_id, param_type = var.split(
                    constants.VARIABLE_NAME_SEPARATOR)
                self.assertIn(param_id, actual_event.args)
                self.assertEqual(param_type,
                                 actual_event.args[param_id].type.abi_type)
Example #12
0
    def compile(path: str) -> bytes:
        """
        Load a Python file to be compiled but don't write the result into a file

        :param path: the path of the Python file to compile
        :return: the bytecode of the compiled .nef file
        """
        if not path.endswith('.py'):
            raise InvalidPathException(path)

        return Compiler().compile(path)
Example #13
0
    def test_generate_nefdbgnfo_file_with_static_variables(self):
        path = self.get_contract_path('GenerationWithStaticVariables.py')

        expected_nef_output = path.replace('.py', '.nefdbgnfo')
        compiler = Compiler()
        compiler.compile_and_save(path,
                                  path.replace('.py', '.nef'),
                                  debug=True)
        variables: Dict[str, Method] = {
            name: method
            for name, method in self.get_compiler_analyser(
                compiler).symbol_table.items() if isinstance(method, Variable)
        }

        self.assertTrue(os.path.exists(expected_nef_output))
        debug_info = self.get_debug_info(path)

        self.assertNotIn('entrypoint', debug_info)
        self.assertIn('static-variables', debug_info)
        self.assertGreater(len(debug_info['static-variables']), 0)

        for static_variable in debug_info['static-variables']:
            # validate parameters
            self.assertEqual(
                3,
                len(static_variable.split(constants.VARIABLE_NAME_SEPARATOR)))
            var_id, var_type, var_slot = static_variable.split(
                constants.VARIABLE_NAME_SEPARATOR)
            if var_id not in variables:
                self.assertIn(var_id, [
                    var_full_id.split(constants.VARIABLE_NAME_SEPARATOR)[-1]
                    for var_full_id in variables
                ])
                var_inner_id = next((var for var in variables if var.split(
                    constants.VARIABLE_NAME_SEPARATOR)[-1] == var_id), var_id)
            else:
                var_inner_id = var_id

            self.assertIn(var_inner_id, variables)
            self.assertEqual(var_type, variables[var_inner_id].type.abi_type)