예제 #1
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.Integer import Integer

        number_zero_to_bytes = b'\x00'
        jmp_place_holder = (Opcode.JMP, b'\x01')

        verify_number_is_zero = [
            (Opcode.DUP, b''),
            (Opcode.NZ, b''),
            jmp_place_holder
        ]

        number_is_not_zero = super().opcode.copy()
        number_is_not_zero.append(jmp_place_holder)

        number_is_zero = [
            (Opcode.DROP, b''),
            (Opcode.PUSHDATA1, Integer(len(number_zero_to_bytes)).to_byte_array() + number_zero_to_bytes),
        ]

        number_is_not_zero[-1] = Opcode.get_jump_and_data(Opcode.JMP, get_bytes_count(number_is_zero))

        verify_number_is_zero[-1] = Opcode.get_jump_and_data(Opcode.JMPIFNOT, get_bytes_count(number_is_not_zero))

        return (
            verify_number_is_zero +
            number_is_not_zero +
            number_is_zero + [(Opcode.NOP, b'')]    # TODO: change this when refactoring calling methods with methods as args
        )
예제 #2
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.neo.vm.type.Integer import Integer
        from boa3.neo.vm.type.StackItem import StackItemType

        ECPOINT_SIZE = 33

        throw_if_invalid = [
            (Opcode.THROW, b''),
        ]
        check_bytestr_size = [
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.PUSHINT8,
             Integer(ECPOINT_SIZE).to_byte_array(signed=True)),
            Opcode.get_jump_and_data(Opcode.JMPEQ,
                                     get_bytes_count(throw_if_invalid),
                                     jump_through=True),
        ]

        return [
            (Opcode.CONVERT, StackItemType.ByteString),  # convert to ECPoint
            (Opcode.DUP, b''),
            (Opcode.ISNULL, b''),
            Opcode.get_jump_and_data(Opcode.JMPIF,
                                     get_bytes_count(check_bytestr_size),
                                     jump_through=True),
        ] + check_bytestr_size + throw_if_invalid
예제 #3
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count

        jmp_place_holder = (Opcode.JMP, b'\x01')

        create_auxiliary_vars = [       # initializes auxiliary variables
            (Opcode.NEWMAP, b''),       # dict_copy = {}
            (Opcode.OVER, b''),
            (Opcode.KEYS, b''),         # list_keys = list(dict_target)
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),          # index = len(list_keys) - 1
        ]

        verify_while_condition = [      # if index < 0: go clean stack
            (Opcode.DUP, b''),
            (Opcode.PUSH0, b''),
            jmp_place_holder            # jump to clean_stack
        ]

        while_loop = [                  # while index >= 0: add key value pair into new dict
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PICKITEM, b''),     # key = list_keys[index]
            (Opcode.PUSH5, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),     # value = dict_target[key]
            (Opcode.SETITEM, b''),      # dict_copy[key] = value
            (Opcode.DEC, b''),          # index--
            # jump back to verify_while_condition
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(Opcode.JMP, -get_bytes_count(while_loop + verify_while_condition))
        while_loop.append(jmp_back_to_verify)

        jmp_while_loop = Opcode.get_jump_and_data(Opcode.JMPLT, get_bytes_count(while_loop))
        verify_while_condition[-1] = jmp_while_loop

        clean_stack = [                 # remove all values from stack except the dict_copy
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.NIP, b'')
        ]

        return (
            create_auxiliary_vars +
            verify_while_condition +
            while_loop +
            clean_stack
        )
예제 #4
0
    def is_instance_opcodes(self) -> List[Tuple[Opcode, bytes]]:
        is_type_opcodes = [
            (Opcode.DUP, b''),  # if is the same internal type
            (Opcode.ISTYPE, self.stack_item)
        ]

        return_false = [
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # return False
        ]
        return_false_bytes_size = get_bytes_count(return_false)

        final_instructions = []
        final_jmp = [(Opcode.JMP, Integer(2 + return_false_bytes_size).to_byte_array(min_length=1))]
        validate_type = self._is_instance_inner_opcodes(get_bytes_count(final_jmp))
        if len(validate_type) > 0:
            final_instructions += (validate_type + final_jmp)

            bytes_size = get_bytes_count(final_instructions)
            jmp_opcode, jmp_arg = Opcode.get_jump_and_data(Opcode.JMPIFNOT, bytes_size + 1)

            final_instructions = (is_type_opcodes +
                                  [(jmp_opcode, jmp_arg)] +
                                  final_instructions +
                                  return_false)
        else:
            is_type_opcodes.remove((Opcode.DUP, b''))
            final_instructions = is_type_opcodes

        return final_instructions
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.neo3.contracts.namedcurve import NamedCurve
        curve = NamedCurve.SECP256K1

        return ([(Opcode.DUP, b''),
                 Opcode.get_push_and_data(curve),
                 (Opcode.APPEND, b'')] + super().opcode)
예제 #6
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.Integer import Integer
        from boa3.neo.vm.type.String import String

        message = String("decimals cannot be negative").to_bytes()

        if_negative_decimal = [
            (Opcode.PUSHDATA1, Integer(len(message)).to_byte_array(signed=True, min_length=1) + message),
            (Opcode.THROW, b''),
        ]

        decimals_unit = [
            (Opcode.OVER, b''),
            (Opcode.PUSH0, b''),
            Opcode.get_jump_and_data(Opcode.JMPGE, get_bytes_count(if_negative_decimal), True),
        ] + if_negative_decimal + [
            (Opcode.DUP, b''),
            (Opcode.REVERSE3, b''),
            Opcode.get_push_and_data(10),
            (Opcode.SWAP, b''),
            (Opcode.POW, b''),
            (Opcode.SWAP, b''),
            (Opcode.OVER, b''),
            (Opcode.MOD, b'')
        ]

        if_negative_mod = [
            (Opcode.ADD, b''),
            (Opcode.JMP, b'')
        ]
        else_negative_mod = [
            (Opcode.NIP, b'')
        ]
        num_jmp_code = get_bytes_count(else_negative_mod)
        if_negative_mod[-1] = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code, True)

        num_jmp_code = get_bytes_count(if_negative_mod)
        floor_computation = [
            (Opcode.DUP, b''),
            (Opcode.PUSH0, b''),
            Opcode.get_jump_and_data(Opcode.JMPGE, num_jmp_code, True),
        ] + if_negative_mod + else_negative_mod + [
            (Opcode.SUB, b'')
        ]

        return decimals_unit + floor_computation
예제 #7
0
    def _is_instance_inner_opcodes(self, jmp_to_if_false: int = 0) -> List[Tuple[Opcode, bytes]]:
        if self.stack_item not in (StackItemType.Array, StackItemType.Struct, StackItemType.Map):
            return []

        variables_count_is_equal = [
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            Opcode.get_push_and_data(len(self._all_variables)),
            (Opcode.NUMEQUAL, b''),
        ]

        total_size = jmp_to_if_false
        variables_type_validations = []

        for var_index, (var_id, var) in reversed(list(enumerate(self._all_variables.items()))):

            if var.type.stack_item != StackItemType.Any:

                # validate primitive types only to avoid recursive code
                if self.stack_item == StackItemType.Map:
                    get = Opcode.get_pushdata_and_data(var_id)
                else:
                    get = Opcode.get_push_and_data(var_index)

                new_opcodes = [
                    (Opcode.DUP, b''),
                    get,
                    (Opcode.PICKITEM, b''),
                    (Opcode.ISTYPE, var.type.stack_item)
                ]
                if len(variables_type_validations) == 0:
                    new_opcodes.append((Opcode.NIP, b''))
                elif total_size > 0:
                    new_opcodes.append((Opcode.get_jump_and_data(Opcode.JMPIFNOT, total_size + 1)))

                variables_type_validations = new_opcodes + variables_type_validations
                total_size += get_bytes_count(new_opcodes)

        if total_size > 0:
            if len(variables_type_validations) > 0:
                final_opcode = (Opcode.get_jump_and_data(Opcode.JMPIFNOT, total_size + 1))
            else:
                final_opcode = (Opcode.NIP, b'')
            variables_count_is_equal.append(final_opcode)

        return variables_count_is_equal + variables_type_validations
예제 #8
0
 def opcode(self) -> List[Tuple[Opcode, bytes]]:
     return [
         Opcode.get_pushdata_and_data(bytes(33)),  # vote_to
         (Opcode.PUSH0, b''),  # height
         (Opcode.PUSH0, b''),  # balance
         (Opcode.PUSH3, b''),
         (Opcode.PACK, b'')
     ]
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3 import constants
        from boa3.model.builtin.interop.crypto.checksigmethod import CheckSigMethod
        from boa3.model.builtin.interop.crypto.sha256method import Sha256Method
        from boa3.model.builtin.interop.crypto.ripemd160method import Ripemd160Method
        from boa3.model.type.type import Type

        # build CheckSig script
        pushdata, pushbytes = Opcode.get_pushdata_and_data_from_size(
            constants.SIZE_OF_ECPOINT)
        opcodes = [
            Opcode.get_pushdata_and_data(pushdata + pushbytes),
            (Opcode.SWAP, b''),
            Opcode.get_pushdata_and_data(CheckSigMethod.get_raw_bytes()),
            (Opcode.CAT, b''),
            (Opcode.CAT, b''),
        ]

        opcodes.extend([
            Opcode.get_push_and_data(1),  # pack argument to call syscall
            (Opcode.PACK, b'')
        ] + Sha256Method().opcode)
        opcodes.extend([
            Opcode.get_push_and_data(1),  # pack argument to call syscall
            (Opcode.PACK, b'')
        ] + Ripemd160Method().opcode)

        opcodes.extend([
            # limit result to UInt160 length
            Opcode.get_push_and_data(0),
            Opcode.get_push_and_data(constants.SIZE_OF_INT160),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, Type.bytes.stack_item)
        ])
        return opcodes
예제 #10
0
    def _is_instance_inner_opcodes(self, jmp_to_if_false: int = 0) -> List[Tuple[Opcode, bytes]]:
        from boa3 import constants
        push_int_opcode, size_data = Opcode.get_push_and_data(constants.SIZE_OF_ECPOINT)

        return [
            (Opcode.SIZE, b''),  # return len(value) == 33
            (push_int_opcode, size_data),
            (Opcode.NUMEQUAL, b'')
        ]
예제 #11
0
    def _is_instance_inner_opcodes(self,
                                   jmp_to_if_false: int = 0
                                   ) -> List[Tuple[Opcode, bytes]]:
        push_int_opcode, size_data = Opcode.get_push_and_data(32)

        return [
            (Opcode.SIZE, b''),  # return len(value) == 32
            (push_int_opcode, size_data),
            (Opcode.NUMEQUAL, b'')
        ]
예제 #12
0
 def swap_reverse_stack_items(self, no_items: int = 0):
     # n = 0 -> value varies in runtime
     if 0 <= no_items != 1:
         opcode: Opcode = Opcode.get_reverse(no_items)
         if opcode is Opcode.REVERSEN and no_items > 0:
             self.convert_literal(no_items)
         op_info = OpcodeInfo.get_info(opcode)
         self.__insert1(op_info)
         if no_items > 0:
             reverse = list(reversed(self._stack[-no_items:]))
             self._stack = self._stack[:-no_items]
             self._stack.extend(reverse)
예제 #13
0
    def convert_integer_literal(self, value: int):
        """
        Converts an integer literal value

        :param value: the value to be converted
        """
        opcode = Opcode.get_literal_push(value)
        if opcode is not None:
            op_info: OpcodeInformation = OpcodeInfo.get_info(opcode)
            self.__insert1(op_info)
            self._stack.append(Type.int)
        else:
            opcode = Opcode.get_literal_push(-value)
            if opcode is not None:
                op_info: OpcodeInformation = OpcodeInfo.get_info(opcode)
                self.__insert1(op_info)
                self._stack.append(Type.int)
                self.convert_operation(UnaryOp.Negative)
            else:
                array = Integer(value).to_byte_array(signed=True)
                self.insert_push_data(array)
                # cast the value to integer
                self.convert_cast(Type.int)
예제 #14
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        jmp_place_holder = (Opcode.JMP, b'')

        mod = [
            (
                Opcode.SWAP, b''
            ),  # neo's mod has a different result from python's mod in some cases
            (Opcode.OVER, b''),
            (Opcode.MOD, b''),
            (Opcode.DUP, b''),
            (Opcode.SIGN, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIGN, b''),
            (
                Opcode.OVER, b''
            ),  # if the result is not zero and the sign is different than the second operator
            (Opcode.NUMEQUAL, b''),  # the result is different
            (Opcode.SWAP, b''),
            (Opcode.PUSH0, b''),
            (Opcode.NUMEQUAL, b''),  # the result is different
            (Opcode.BOOLOR, b''),
            jmp_place_holder,
        ]

        from boa3.compiler.codegenerator import get_bytes_count
        if_negative = [(Opcode.ADD, b''), jmp_place_holder]
        num_jmp_code = get_bytes_count(if_negative)
        mod[-1] = Opcode.get_jump_and_data(Opcode.JMPIF, num_jmp_code, True)

        else_negative = [(Opcode.NIP, b'')]
        num_jmp_code = get_bytes_count(else_negative)
        if_negative[-1] = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code,
                                                   True)

        return mod + if_negative + else_negative
예제 #15
0
    def duplicate_stack_item(self, pos: int = 0):
        """
        Duplicates the item n back in the stack

        :param pos: index of the variable
        """
        # n = 1 -> duplicates stack top item
        # n = 0 -> value varies in runtime
        if pos >= 0:
            opcode: Opcode = Opcode.get_dup(pos)
            if opcode is Opcode.PICK and pos > 0:
                self.convert_literal(pos - 1)
                self._stack.pop()
            op_info = OpcodeInfo.get_info(opcode)
            self.__insert1(op_info)
            self._stack.append(self._stack[-pos])
예제 #16
0
    def remove_stack_item(self, pos: int = 0):
        """
        Removes the item n from the stack

        :param pos: index of the variable
        """
        # n = 1 -> removes stack top item
        if pos > 0:
            opcode: Opcode = Opcode.get_drop(pos)
            if opcode is Opcode.XDROP:
                self.convert_literal(pos - 1)
                self._stack.pop()
            op_info = OpcodeInfo.get_info(opcode)
            self.__insert1(op_info)
            if pos > 0:
                self._stack.pop(-pos)
예제 #17
0
    def is_instance_opcodes(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.neo.vm.type.Integer import Integer
        push_int_opcode, size_data = Opcode.get_push_and_data(20)

        return [
            (Opcode.DUP, b''),  # if isinstance(value, bytes):
            (Opcode.ISTYPE, self.stack_item),
            (Opcode.JMPIFNOT,
             Integer(7 + len(size_data)).to_byte_array(min_length=1)),
            (Opcode.SIZE, b''),  # return len(value) == 20
            (push_int_opcode, size_data),
            (Opcode.NUMEQUAL, b''),
            (Opcode.JMP, Integer(4).to_byte_array(min_length=1)),
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # return False
        ]
예제 #18
0
    def convert_store_variable(self, var_id: str):
        """
        Converts the assignment of a variable

        :param var_id: the value to be converted
        """
        index, local, is_arg = self._get_variable_info(var_id)
        if index >= 0:
            opcode = Opcode.get_store(index, local, is_arg)
            if opcode is not None:
                op_info = OpcodeInfo.get_info(opcode)

                if op_info.data_len > 0:
                    self.__insert1(op_info, Integer(index).to_byte_array())
                else:
                    self.__insert1(op_info)
                self._stack.pop()
예제 #19
0
    def convert_builtin_method_call(self,
                                    function: IBuiltinMethod,
                                    args_address: List[int] = None):
        """
        Converts a builtin method function call

        :param function: the function to be converted
        :param args_address: a list with each function arguments' first addresses
        """
        if args_address is None:
            args_address = []
        store_opcode: OpcodeInformation = None
        store_data: bytes = b''

        if function.stores_on_slot and 0 < len(
                function.args) <= len(args_address):
            address = args_address[-len(function.args)]
            load_instr = VMCodeMapping.instance().code_map[address]
            if load_instr.opcode.is_load_slot:
                store: Opcode = Opcode.get_store_from_load(load_instr.opcode)
                store_opcode = OpcodeInfo.get_info(store)
                store_data = load_instr.data

        for opcode, data in function.opcode:
            op_info = OpcodeInfo.get_info(opcode)
            self.__insert1(op_info, data)

        if store_opcode is not None:
            self._insert_jump(OpcodeInfo.JMP)
            jump = self.last_code_start_address
            self.__insert1(store_opcode, store_data)
            self._update_jump(jump, VMCodeMapping.instance().bytecode_size)

        for _ in range(function.args_on_stack):
            self._stack.pop()
        if function.return_type not in (None, Type.none):
            self._stack.append(function.return_type)
예제 #20
0
    def convert_load_variable(self, var_id: str, var: Variable):
        """
        Converts the assignment of a variable

        :param var_id: the value to be converted
        :param var: the actual variable to be loaded
        """
        index, local, is_arg = self._get_variable_info(var_id)
        if index >= 0:
            opcode = Opcode.get_load(index, local, is_arg)
            op_info = OpcodeInfo.get_info(opcode)

            if op_info.data_len > 0:
                self.__insert1(op_info, Integer(index).to_byte_array())
            else:
                self.__insert1(op_info)
            self._stack.append(var.type)

        elif hasattr(var.type, 'get_value'):
            # the variable is a type constant
            # TODO: change this when implement class conversion
            value = var.type.get_value(var_id.split('.')[-1])
            if value is not None:
                self.convert_literal(value)
예제 #21
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.model.type.type import Type

        jmp_place_holder = (Opcode.JMP, b'\x01')

        # region verify end

        verify_end_null = [  # verifies if end is null
            (Opcode.REVERSE4, b''), (Opcode.DUP, b''), (Opcode.ISNULL, b''),
            jmp_place_holder
        ]

        end_null = [  # if end is null, end = len(self)
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # skip the other end verifications
        ]

        num_jmp_code = get_bytes_count(end_null)
        jmp_str_end_null_statement = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, num_jmp_code, True)
        verify_end_null[-1] = jmp_str_end_null_statement

        verify_end_neg = [  # verifies if end is < 0
            (Opcode.DUP, b''), (Opcode.PUSH0, b''), jmp_place_holder
        ]

        end_neg = [  # if end is < 0, then get the positive equivalent number
            (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIZE, b''),
            (Opcode.ADD, b''), (Opcode.DUP, b''), (Opcode.PUSH0, b''),
            jmp_place_holder
        ]

        end_still_neg = [  # if end is still < 0 after adding it to len(self), end = 0
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),
        ]

        num_jmp_code = get_bytes_count(end_still_neg)
        jmp_end_still_neg_statement = Opcode.get_jump_and_data(
            Opcode.JMPGE, num_jmp_code, True)
        end_neg[-1] = jmp_end_still_neg_statement

        skip_end_gt_size = [
            jmp_place_holder  # skip the other end verification
        ]

        num_jmp_code = get_bytes_count(end_still_neg + end_neg +
                                       skip_end_gt_size)
        jmp_end_neg_statement = Opcode.get_jump_and_data(
            Opcode.JMPGE, num_jmp_code, True)
        verify_end_neg[-1] = jmp_end_neg_statement

        verify_end_gt_size = [  # verifies if end >= len(self)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder,
        ]

        end_gt_size = [  # if end >= len(self), end = len(self)
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
        ]

        num_jmp_code = get_bytes_count(end_gt_size)
        jmp_end_gt_size_statement = Opcode.get_jump_and_data(
            Opcode.JMPLE, num_jmp_code, True)
        verify_end_gt_size[-1] = jmp_end_gt_size_statement

        num_jmp_code = get_bytes_count(end_gt_size + verify_end_gt_size)
        jmp_whole_end_gt_size_statement = Opcode.get_jump_and_data(
            Opcode.JMP, num_jmp_code, True)
        skip_end_gt_size[-1] = jmp_whole_end_gt_size_statement

        num_jmp_code = get_bytes_count(end_gt_size + verify_end_gt_size +
                                       skip_end_gt_size + end_still_neg +
                                       end_neg + verify_end_neg)
        jmp_whole_end_gt_size_statement = Opcode.get_jump_and_data(
            Opcode.JMP, num_jmp_code, True)
        end_null[-1] = jmp_whole_end_gt_size_statement

        verify_end = (verify_end_null + end_null + verify_end_neg + end_neg +
                      end_still_neg + skip_end_gt_size + verify_end_gt_size +
                      end_gt_size)

        # endregion

        # region verify start

        verify_start_neg = [  # verifies if start is < 0
            (Opcode.OVER, b''), (Opcode.PUSH0, b''), jmp_place_holder
        ]

        start_neg = [  # if start is < 0, then get the positive equivalent index
            (Opcode.SWAP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''),
            (Opcode.SIZE, b''), (Opcode.ADD, b''), (Opcode.DUP, b''),
            (Opcode.PUSH0, b''), jmp_place_holder
        ]

        start_still_neg = [  # if start is still < 0 after adding it to len(self), start = 0
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),
        ]

        num_jmp_code = get_bytes_count(start_still_neg)
        jmp_str_start_still_neg_statement = Opcode.get_jump_and_data(
            Opcode.JMPGE, num_jmp_code, True)
        start_neg[-1] = jmp_str_start_still_neg_statement

        correct_start_position = [  # put start on the correct position
            (Opcode.SWAP, b'')
        ]

        num_jmp_code = get_bytes_count(correct_start_position +
                                       start_still_neg + start_neg)
        jmp_str_start_neg_statement = Opcode.get_jump_and_data(
            Opcode.JMPGE, num_jmp_code, True)
        verify_start_neg[-1] = jmp_str_start_neg_statement

        verify_start = (verify_start_neg + start_neg + start_still_neg +
                        correct_start_position)

        # endregion

        # region Count logic

        initialize = [  # initialize variables
            (Opcode.PUSH0, b''),  # count = 0
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # substr_size = len(substr)
            (Opcode.SWAP, b''),
        ]

        verify_while = [  # verifies if substr_size + index >= end
            (Opcode.OVER, b''), (Opcode.PUSH4, b''), (Opcode.PICK, b''),
            (Opcode.ADD, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''),
            jmp_place_holder
        ]

        count_substring = [  # verifies if self[index: index+substr_size] == substr
            (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.PUSH4, b''),
            (Opcode.PICK, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''),
            (Opcode.SUBSTR, b''), (Opcode.CONVERT, Type.str.stack_item),
            (Opcode.PUSH5, b''), (Opcode.PICK, b''), (Opcode.NUMEQUAL, b''),
            jmp_place_holder
        ]

        count_plusplus = [  # if self[index: index+substr_size] == substr
            (Opcode.INC, b''),  # count++
        ]

        num_jmp_code = get_bytes_count(count_plusplus)
        jmp_count_plusplus_statement = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, num_jmp_code, True)
        count_substring[-1] = jmp_count_plusplus_statement

        go_back_to_while = [  # go back to while verification
            (Opcode.REVERSE4, b''),
            (Opcode.INC, b''),  # index ++
            (Opcode.REVERSE4, b''),
            # jump back to while
        ]

        num_jmp_code = -get_bytes_count(go_back_to_while + count_plusplus +
                                        count_substring + verify_while)
        jmp_back_to_while_statement = Opcode.get_jump_and_data(
            Opcode.JMP, num_jmp_code)
        go_back_to_while.append(jmp_back_to_while_statement)

        num_jmp_code = get_bytes_count(go_back_to_while + count_plusplus +
                                       count_substring)
        jmp_to_clean_stack_statement = Opcode.get_jump_and_data(
            Opcode.JMPGT, num_jmp_code, True)
        verify_while[-1] = jmp_to_clean_stack_statement

        clean_stack = [  # remove auxiliary values
            (Opcode.REVERSE4, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        count_logic = (initialize + verify_while + count_substring +
                       count_plusplus + go_back_to_while + clean_stack)

        # endregion

        # count string logic is verify_end + verify_start  + count_logic
        return (verify_end + verify_start + count_logic)
예제 #22
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.StackItem import StackItemType
        jmp_place_holder = (Opcode.JMP, b'\x01')
        a_lower = ord('a')
        a_upper = ord('A')
        zero = ord('0')

        # region verify_base

        verify_base_ge37 = [  # verifies if base >= 37, base greater than 36 shouldn't be accepted
            (Opcode.OVER, b''),
            Opcode.get_push_and_data(37),
            jmp_place_holder,  # jumps to an assertion error
        ]

        verify_base_equal1 = [  # verifies if base == 1, base equals 1 shouldn't be accepted
            (Opcode.OVER, b''),
            (Opcode.PUSH1, b''),
            jmp_place_holder  # jumps to an assertion error
        ]

        verify_base_le_minus1 = [  # verifies if base <= -1, base less than 0 shouldn't be accepted
            (Opcode.OVER, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder,  # jumps to an assertion error
        ]

        verify_base_jump_error = [  # jumps the next set of instructions
            jmp_place_holder
        ]

        verify_base_error = [  # an invalid base was used
            (Opcode.PUSH0, b''),
            (Opcode.ASSERT, b''),
        ]

        # region verify_base jump logic

        jump_instructions = verify_base_error
        verify_base_jump_error[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = verify_base_jump_error
        verify_base_le_minus1[-1] = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(jump_instructions), True)

        jump_instructions = verify_base_jump_error + verify_base_le_minus1
        verify_base_equal1[-1] = Opcode.get_jump_and_data(
            Opcode.JMPEQ, get_bytes_count(jump_instructions), True)

        jump_instructions = verify_base_jump_error + verify_base_le_minus1 + verify_base_equal1
        verify_base_ge37[-1] = Opcode.get_jump_and_data(
            Opcode.JMPGE, get_bytes_count(jump_instructions), True)

        # endregion

        verify_base = (verify_base_ge37 + verify_base_equal1 +
                       verify_base_le_minus1 + verify_base_jump_error +
                       verify_base_error)

        # endregion

        # region verify_code_literal

        verify_code_literal_first_char_is_0 = [  # verifies if the first char in the value is '0'
            (Opcode.DUP, b''),
            (Opcode.PUSH0, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            Opcode.get_pushdata_and_data('0'),
            jmp_place_holder,  # if first char is not 0, skip all verify_code_literal methods
        ]

        verify_code_literal_remove_first_char = [  # the first char is 0, so it will be removed from the value
            (Opcode.PUSH1, b''),
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
        ]

        verify_code_literal_get_base_char = [  # puts the char that could refer to a base in the top of the stack
            (Opcode.DUP, b''),
            (Opcode.PUSH0, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
        ]

        verify_code_literal_initialize_verification = [  # puts a False in the top of the stack to assist the
            (Opcode.PUSH0, b'')  # verifications above
        ]

        verify_code_literal_base_verification = (  # verifies if the original value starts with 0b, 0B, 0o, 0O
            self._verify_is_specific_base(
                'b', 2) +  # 0x, or 0X, and changes the base if necessary
            self._verify_is_specific_base('B', 2) +
            self._verify_is_specific_base('o', 8) +
            self._verify_is_specific_base('O', 8) +
            self._verify_is_specific_base('x', 16) +
            self._verify_is_specific_base('X', 16))

        verify_code_literal_drop_aux = [  # drops auxiliary values from the stack and just keeps the
            (Opcode.DROP, b''),  # base and value on it
            (Opcode.DROP, b''),
        ]

        # region verify_code_literal jump logic

        jump_instructions = (verify_code_literal_remove_first_char +
                             verify_code_literal_get_base_char +
                             verify_code_literal_initialize_verification +
                             verify_code_literal_base_verification +
                             verify_code_literal_drop_aux)

        verify_code_literal_first_char_is_0[-1] = Opcode.get_jump_and_data(
            Opcode.JMPNE_L, get_bytes_count(jump_instructions), True)

        # endregion

        verify_code_literal = (verify_code_literal_first_char_is_0 +
                               verify_code_literal_remove_first_char +
                               verify_code_literal_get_base_char +
                               verify_code_literal_initialize_verification +
                               verify_code_literal_base_verification +
                               verify_code_literal_drop_aux)

        # endregion

        # region ascii to int

        ascii_to_int_initialize = [  # initialize auxiliary variables on the stack
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),  # index = len(value) - 1
            (Opcode.DUP, b''),
            (Opcode.PUSH0, b''),
            (Opcode.GE, b''),
            (Opcode.ASSERT, b''),  # verifies if value was empty
            (Opcode.PUSH0, b''),  # sum = 0
            (Opcode.PUSH1, b''),  # mult = 1
        ]

        ascii_to_int_while = [  # loops from left to right of the value to calculate the equivalent sum in base 10
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),  # char = value[index]
            (Opcode.CONVERT, StackItemType.Integer),
        ]

        ascii_to_int_verify_az_lower_lt = [  # verifies ord(char) is less than ord('a')
            (Opcode.DUP,
             b''),  # if ord(char) is indeed less, go to verify with ord('A')
            Opcode.get_push_and_data(a_lower),
            jmp_place_holder  # jump to ascii_to_int_verify_az_upper_lt
        ]

        ascii_to_int_verify_az_lower_gt = [  # verifies ord(char) is greater than base + 86
            (
                Opcode.DUP, b''
            ),  # the minimum base that accepts letters is base 11, that's why it's
            (Opcode.PUSH6, b''),  # adding 86
            (Opcode.PICK, b''
             ),  # if ord(char) is greater than base + 86, the char is invalid
            Opcode.get_push_and_data(86),
            (Opcode.ADD, b''),
            (Opcode.LE, b''),
            (Opcode.ASSERT,
             b''),  # if assert is False, then the char was indeed invalid
        ]

        ascii_to_int_verify_az_lower = [  # the char was in between 'a' and 'z',
            Opcode.get_push_and_data(
                87
            ),  # so it will be converted to the respective base 10 number
            (Opcode.SUB, b''),
            (Opcode.OVER, b''),
            (Opcode.MUL, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.ADD, b''),  # sum = sum + (ord(char) - 55)) * mult
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            jmp_place_holder  # jumps to ascii_to_int_verify_while
        ]

        ascii_to_int_verify_az_upper_lt = [  # verifies ord(char) is less than ord('A')
            (Opcode.DUP,
             b''),  # if ord(char) is indeed less, go to verify with ord('0')
            Opcode.get_push_and_data(a_upper),
            jmp_place_holder  # jump to ascii_to_int_verify_09_lt
        ]

        ascii_to_int_verify_az_upper_gt = [  # verifies ord(char) is greater than base + 54
            (
                Opcode.DUP, b''
            ),  # the minimum base that accepts letters is base 11, that's why it's
            (Opcode.PUSH6, b''),  # adding 54
            (Opcode.PICK, b''
             ),  # if ord(char) is greater than base + 54, the char is invalid
            Opcode.get_push_and_data(54),
            (Opcode.ADD, b''),
            (Opcode.LE, b''),
            (Opcode.ASSERT,
             b''),  # if assert is False, then the char was indeed invalid
        ]

        ascii_to_int_verify_az_upper = [  # the char was in between 'A' and 'Z',
            Opcode.get_push_and_data(
                55
            ),  # so it will be converted to the respective base 10 number
            (Opcode.SUB, b''),
            (Opcode.OVER, b''),
            (Opcode.MUL, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.ADD, b''),  # sum = sum + (ord(char) - 55)) * mult
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            jmp_place_holder  # jumps to ascii_to_int_verify_while
        ]

        ascii_to_int_verify_09_lt = [  # verifies ord(char) is less than ord('0')
            (Opcode.DUP,
             b''),  # if ord(char) is indeed less, the char is invalid
            Opcode.get_push_and_data(zero),
            (Opcode.GE, b''),
            (Opcode.ASSERT,
             b''),  # if assert is False, then the char was indeed invalid
        ]

        ascii_to_int_verify_09_gt = [  # verifies ord(char) is greater than base + ord('0')
            (
                Opcode.DUP, b''
            ),  # if ord(char) is greater than base + ord('0'), the char is invalid
            (Opcode.PUSH6, b''),
            (Opcode.PICK, b''),
            Opcode.get_push_and_data(zero),
            (Opcode.ADD, b''),
            (Opcode.LE, b''),
            (Opcode.ASSERT,
             b''),  # if assert is False, then the char was indeed invalid
        ]

        ascii_to_int_verify_09 = [  # the char was in between '0' and '9',
            Opcode.get_push_and_data(
                zero
            ),  # so it will be converted to the respective base 10 number
            (Opcode.SUB, b''),
            (Opcode.OVER, b''),
            (Opcode.MUL, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.ADD, b''),  # sum = sum + (ord(char) - ord('0')) * mult
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
        ]

        ascii_to_int_verify_while = [  # verifies if the loop already went through all the chars in value
            (Opcode.REVERSE3, b''),
            (Opcode.DEC, b''),  # index--
            (Opcode.REVERSE3, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.MUL, b''),  # mult = mult * base
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH0, b''),
            # jmp back to ascii_to_int_while if index >= 0
        ]

        # region ascii to int jump logic

        jump_instructions = (ascii_to_int_verify_09_lt +
                             ascii_to_int_verify_09_gt +
                             ascii_to_int_verify_09)

        ascii_to_int_verify_az_upper[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = (ascii_to_int_verify_az_upper_gt +
                             ascii_to_int_verify_az_upper)

        ascii_to_int_verify_az_upper_lt[-1] = Opcode.get_jump_and_data(
            Opcode.JMPLT, get_bytes_count(jump_instructions), True)

        jump_instructions = (ascii_to_int_verify_az_upper_lt +
                             ascii_to_int_verify_az_upper_gt +
                             ascii_to_int_verify_az_upper +
                             ascii_to_int_verify_09_lt +
                             ascii_to_int_verify_09_gt +
                             ascii_to_int_verify_09)

        ascii_to_int_verify_az_lower[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = (ascii_to_int_verify_az_lower_gt +
                             ascii_to_int_verify_az_lower)

        ascii_to_int_verify_az_lower_lt[-1] = Opcode.get_jump_and_data(
            Opcode.JMPLT, get_bytes_count(jump_instructions), True)

        jump_instructions = (
            ascii_to_int_while + ascii_to_int_verify_az_lower_lt +
            ascii_to_int_verify_az_lower_gt + ascii_to_int_verify_az_lower +
            ascii_to_int_verify_az_upper_lt + ascii_to_int_verify_az_upper_gt +
            ascii_to_int_verify_az_upper + ascii_to_int_verify_09_gt +
            ascii_to_int_verify_09_lt + ascii_to_int_verify_09 +
            ascii_to_int_verify_while)

        ascii_to_int_verify_while.append(
            Opcode.get_jump_and_data(Opcode.JMPGE,
                                     -get_bytes_count(jump_instructions),
                                     True))

        # endregion

        ascii_to_int = (ascii_to_int_initialize + ascii_to_int_while +
                        ascii_to_int_verify_az_lower_lt +
                        ascii_to_int_verify_az_lower_gt +
                        ascii_to_int_verify_az_lower +
                        ascii_to_int_verify_az_upper_lt +
                        ascii_to_int_verify_az_upper_gt +
                        ascii_to_int_verify_az_upper +
                        ascii_to_int_verify_09_lt + ascii_to_int_verify_09_gt +
                        ascii_to_int_verify_09 + ascii_to_int_verify_while)

        # endregion

        # region clean stack

        clean_stack = [  # clean everything but the number in base 10
            (Opcode.DROP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
        ]

        # endregion

        return (verify_base + verify_code_literal + ascii_to_int + clean_stack)
예제 #23
0
    def _verify_is_specific_base(self, char: str,
                                 base: int) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.StackItem import StackItemType
        jmp_place_holder = (Opcode.JMP, b'\x01')

        verify_top_stack = [  # verify if True is in the top of the stack
            jmp_place_holder
        ]

        top_stack_is_true = [  # if True is indeed at the top, ignore the rest of this method
            (Opcode.PUSH1, b''),
            jmp_place_holder  # jumps everything below
        ]

        compare_char = [  # compares the char with b, B, o, O, x, or X
            (Opcode.DUP, b''),
            Opcode.get_pushdata_and_data(char), jmp_place_holder
        ]

        char_not_equal = [  # if char at the top of the stack is not b, B, o, O, x, or X,
            (Opcode.PUSH0, b''),  # put False at the top of the stack
            jmp_place_holder  # jumps everything below
        ]

        verify_base_is_the_same = [  # verify if the equivalent base is the same as current base
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            Opcode.get_push_and_data(base),
            jmp_place_holder  # jump to remove_base_char if equivalent base is the same as current base
        ]

        verify_base_is_0 = [  # verify if the current base is 0
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH0, b''),
            jmp_place_holder  # if base is not 0, jump to put_true_in_stack
        ]

        change_base = [  # if base was 0, then change it to the equivalent base
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            Opcode.get_push_and_data(base),
            (Opcode.REVERSE3, b''),
        ]

        remove_base_char = [  # if base was 0 or 16, remove the char in value
            (Opcode.SWAP, b''),
            (Opcode.PUSH1, b''),
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.SWAP, b''),
        ]

        put_true_in_stack = [  # puts True in the top of the stack to skip the next verifications
            (Opcode.PUSH1, b'')
        ]

        # region jmp logic

        jump_instructions = change_base + remove_base_char
        verify_base_is_0[-1] = Opcode.get_jump_and_data(
            Opcode.JMPNE, get_bytes_count(jump_instructions), True)

        jump_instructions = change_base + verify_base_is_0
        verify_base_is_the_same[-1] = Opcode.get_jump_and_data(
            Opcode.JMPEQ, get_bytes_count(jump_instructions), True)

        jump_instructions = change_base + remove_base_char + put_true_in_stack + verify_base_is_0 + verify_base_is_the_same
        char_not_equal[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = char_not_equal
        compare_char[-1] = Opcode.get_jump_and_data(
            Opcode.JMPEQ, get_bytes_count(jump_instructions), True)

        jump_instructions = (compare_char + char_not_equal + change_base +
                             put_true_in_stack + verify_base_is_the_same +
                             verify_base_is_0 + remove_base_char)
        top_stack_is_true[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = top_stack_is_true
        verify_top_stack[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, get_bytes_count(jump_instructions), True)

        # endregion

        return (verify_top_stack + top_stack_is_true + compare_char +
                char_not_equal + verify_base_is_the_same + verify_base_is_0 +
                change_base + remove_base_char + put_true_in_stack)
예제 #24
0
 def opcode(self) -> List[Tuple[Opcode, bytes]]:
     value = NEO_SCRIPT
     return [Opcode.get_pushdata_and_data(value)]
예제 #25
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.Integer import Integer
        from boa3.neo.vm.type.StackItem import StackItemType

        number0 = Integer(ord('0')).to_byte_array()
        number9 = Integer(ord('9')).to_byte_array()
        jmp_place_holder = (Opcode.JMP, b'\x01')

        initializing = [  # initialize auxiliary values
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),  # index = len(string) - 1
            (Opcode.PUSH1, b''),  # isdigit = True
        ]

        verify_empty_string = [  # verifies if string is empty
            (Opcode.OVER, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder,  # jump to change_to_false if index == -1
        ]

        skip_first_verify_while = [  # skips the first while verification, since string is not empty
            jmp_place_holder
        ]

        verify_while = [  # verifies if while is over
            (Opcode.OVER, b''),
            (Opcode.PUSH0, b''),
            jmp_place_holder,  # jump to return_bool if index >= len(string)
        ]

        jmp_verify_while = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(verify_while), True)
        skip_first_verify_while[-1] = jmp_verify_while

        while_verify_lt_0 = [  # verifies if ord(string[index]) is < ord('0')
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.DUP, b''),
            (Opcode.PUSHDATA1,
             Integer(len(number0)).to_byte_array() + number0),
            jmp_place_holder,  # if ord(string[index]) < ord('0'), return False
        ]

        while_verify_gt_9 = [  # verifies if ord(string[index]) is > ord('9')
            (Opcode.PUSHDATA1,
             Integer(len(number9)).to_byte_array() + number9),
            jmp_place_holder,  # if ord(string[index]) > ord('9'), return False
        ]

        while_go_to_verify = [  # decreases index and goes back to verify if there all characters were visited already
            (Opcode.SWAP, b''),
            (Opcode.DEC, b''),  # index--
            (Opcode.SWAP, b''),
            # jump back to verify_while
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_while + while_verify_lt_0 +
                             while_verify_gt_9 + while_go_to_verify))
        while_go_to_verify.append(jmp_back_to_verify)

        jmp_out_of_while = Opcode.get_jump_and_data(
            Opcode.JMPLT,
            get_bytes_count(while_verify_gt_9 + while_go_to_verify), True)
        while_verify_lt_0[-1] = jmp_out_of_while

        drop_char = [  # remove extra char from stack
            (Opcode.DROP, b'')
        ]

        jmp_to_change_to_false = Opcode.get_jump_and_data(
            Opcode.JMPGT, get_bytes_count(while_go_to_verify + drop_char),
            True)
        while_verify_gt_9[-1] = jmp_to_change_to_false

        change_to_false = [  # remove True on top of stack and put False
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),
        ]

        jmp_to_return = Opcode.get_jump_and_data(
            Opcode.JMPEQ,
            get_bytes_count(skip_first_verify_while + verify_while +
                            while_verify_lt_0 + while_verify_gt_9 +
                            while_go_to_verify + drop_char), True)
        verify_empty_string[-1] = jmp_to_return

        jmp_to_return = Opcode.get_jump_and_data(
            Opcode.JMPLT,
            get_bytes_count(while_verify_lt_0 + while_verify_gt_9 +
                            while_go_to_verify + drop_char + change_to_false),
            True)
        verify_while[-1] = jmp_to_return

        clean_and_return_bool = [  # remove extra values from stack
            (Opcode.NIP, b''), (Opcode.NIP, b'')
        ]

        return (initializing + verify_empty_string + skip_first_verify_while +
                verify_while + while_verify_lt_0 + while_verify_gt_9 +
                while_go_to_verify + drop_char + change_to_false +
                clean_and_return_bool)
예제 #26
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.neo.vm.type.StackItem import StackItemType
        from boa3.compiler.codegenerator import get_bytes_count
        jmp_place_holder = (Opcode.JMP, b'\x01')

        verify_is_none = [  # verify if value is None
            (Opcode.DUP, b''), (Opcode.ISNULL, b''), jmp_place_holder
        ]

        value_is_none = [  # if value is None, then return False
            (Opcode.DROP, b''), (Opcode.PUSH0, b''), jmp_place_holder
        ]

        verify_is_array = [  # if value is an array, check the length of it
            (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Array),
            jmp_place_holder
        ]

        verify_is_map = [  # if value is a map, check the length of it
            (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Map),
            jmp_place_holder
        ]

        verify_is_int = [  # if value is an int, check if it is non zero
            (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.Integer),
            jmp_place_holder
        ]

        verify_is_bytestring = [  # if value is a bytestring, check if it is non zero
            (Opcode.DUP, b''), (Opcode.ISTYPE, StackItemType.ByteString),
            jmp_place_holder
        ]

        put_true = [  # if value it's not a type from above, return True
            (Opcode.DROP, b''), (Opcode.PUSH1, b''), jmp_place_holder
        ]

        collection_non_zero = [  # get length of collection
            (Opcode.SIZE, b''),
        ]

        non_zero = [  # verify if it's non zero
            (Opcode.NZ, b''),
        ]

        # region jump logic

        jump_instructions = collection_non_zero + non_zero
        put_true[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = collection_non_zero + put_true
        verify_is_bytestring[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(jump_instructions), True)

        jump_instructions = collection_non_zero + put_true + verify_is_bytestring
        verify_is_int[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(jump_instructions), True)

        jump_instructions = put_true + verify_is_int + verify_is_bytestring
        verify_is_map[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(jump_instructions), True)

        jump_instructions = verify_is_map + verify_is_int + verify_is_bytestring + put_true
        verify_is_array[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(jump_instructions), True)

        jump_instructions = (verify_is_array + verify_is_map + verify_is_int +
                             verify_is_bytestring + put_true +
                             collection_non_zero + non_zero)
        value_is_none[-1] = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(jump_instructions), True)

        jump_instructions = value_is_none
        verify_is_none[-1] = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, get_bytes_count(jump_instructions), True)

        # endregion

        bool_method = (verify_is_none + value_is_none + verify_is_array +
                       verify_is_map + verify_is_int + verify_is_bytestring +
                       put_true + collection_non_zero + non_zero)

        return bool_method
예제 #27
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.StackItem import StackItemType

        jmp_place_holder = (Opcode.JMP, b'\x01')
        message = String("substring not found").to_bytes()

        # receives: end, start, substr, str
        verify_negative_index = [  # verifies if index in a negative value
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if index >= 0, jump to verify_big_end or verify_big_start
        ]

        fix_negative_end = [  # gets the correspondent positive value of end
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            (Opcode.ADD, b''),
            (Opcode.INC, b''),  # end = end + len(str) + 1
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if end is not negative anymore, start verifying start
        ]

        fix_still_negative_index = [  # if index is still negative, consider it 0 then
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # end = 0
        ]

        jmp_fix_negative_index = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_negative_end + fix_still_negative_index), True)
        verify_negative_index[-1] = jmp_fix_negative_index

        verify_big_end = [  # verify if end is bigger then len(str)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if end <= len(str), start verifying start
        ]

        fix_big_end = [  # consider end as len(str)
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # end = len(str)
        ]

        jmp_other_verifies = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_still_negative_index + verify_big_end +
                            fix_big_end), True)
        fix_negative_end[-1] = jmp_other_verifies

        jmp_fix_big_index = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(fix_big_end), True)
        verify_big_end[-1] = jmp_fix_big_index

        verify_and_fix_end = [  # collection of Opcodes regarding verifying and fixing end index
            (Opcode.REVERSE4, b''),
        ]
        verify_and_fix_end.extend(verify_negative_index)
        verify_and_fix_end.extend(fix_negative_end)
        verify_and_fix_end.extend(fix_still_negative_index)
        verify_and_fix_end.extend(verify_big_end)
        verify_and_fix_end.extend(fix_big_end)

        verify_and_fix_start = [  # collection of Opcodes regarding verifying and fixing start index
            (Opcode.SWAP, b'')
        ]
        verify_and_fix_start.extend(verify_negative_index)
        verify_and_fix_start.extend(fix_negative_end)
        verify_and_fix_start.extend(fix_still_negative_index)
        verify_and_fix_start.extend(verify_big_end)
        verify_and_fix_start.extend(fix_big_end)

        change_stack_order = [  # change order of items on the stack
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # size = len(substr)
            (Opcode.ROT, b''),
            (Opcode.ROT, b''),
        ]

        verify_while = [  # verify already compared all that was need
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            (Opcode.SUB, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            jmp_place_holder  # if end - index >= size, jump to not_inside_sequence
        ]

        compare_item = [  # compare str[index:index+size] with substr
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.NUMEQUAL, b''),
            jmp_place_holder  # if str[index:index+size] == substr, return index
        ]

        not_found = [  # increments index and goes back to verify again
            (Opcode.INC, b''),  # index++
            # jump to verify_while
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_while + compare_item + not_found), True)
        not_found.append(jmp_back_to_verify)

        jmp_to_error = Opcode.get_jump_and_data(
            Opcode.JMPLT, get_bytes_count(compare_item + not_found), True)
        verify_while[-1] = jmp_to_error

        not_inside_sequence = [  # send error message saying that substring not found
            (Opcode.PUSHDATA1,
             Integer(len(message)).to_byte_array(signed=True, min_length=1) +
             message),
            (Opcode.THROW, b''),
        ]

        jmp_to_return_index = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(not_found + not_inside_sequence),
            True)
        compare_item[-1] = jmp_to_return_index

        return_index = [  # removes all values in the stack but the index
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
        ]

        return (verify_and_fix_end + verify_and_fix_start +
                change_stack_order + verify_while + compare_item + not_found +
                not_inside_sequence + return_index)
예제 #28
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count

        jmp_place_holder = (Opcode.JMP, b'\x01')
        message = String("x not in sequence").to_bytes()

        # receives: end, start, x, sequence
        verify_negative_index = [  # verifies if index in a negative value
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if index >= 0, jump to verify_big_end or verify_big_start
        ]

        fix_negative_end = [  # gets the correspondent positive value of end
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            (Opcode.ADD, b''),
            (Opcode.INC, b''),  # end = end + len(sequence) + 1
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if end is not negative anymore, start verifying start
        ]

        fix_still_negative_index = [  # if index is still negative, consider it 0 then
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # end = 0
        ]

        jmp_fix_negative_index = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_negative_end + fix_still_negative_index), True)
        verify_negative_index[-1] = jmp_fix_negative_index

        verify_big_end = [  # verify if end is bigger then len(sequence)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if end <= len(sequence), start verifying start
        ]

        fix_big_end = [  # consider end as len(sequence)
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # end = len(sequence)
        ]

        jmp_other_verifies = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_still_negative_index + verify_big_end +
                            fix_big_end), True)
        fix_negative_end[-1] = jmp_other_verifies

        jmp_fix_big_index = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(fix_big_end), True)
        verify_big_end[-1] = jmp_fix_big_index

        verify_and_fix_end = [  # collection of Opcodes regarding verifying and fixing end index
            (Opcode.REVERSE4, b''),
        ]
        verify_and_fix_end.extend(verify_negative_index)
        verify_and_fix_end.extend(fix_negative_end)
        verify_and_fix_end.extend(fix_still_negative_index)
        verify_and_fix_end.extend(verify_big_end)
        verify_and_fix_end.extend(fix_big_end)

        verify_and_fix_start = [  # collection of Opcodes regarding verifying and fixing start index
            (Opcode.SWAP, b'')
        ]
        verify_and_fix_start.extend(verify_negative_index)
        verify_and_fix_start.extend(fix_negative_end)
        verify_and_fix_start.extend(fix_still_negative_index)
        verify_and_fix_start.extend(verify_big_end)
        verify_and_fix_start.extend(fix_big_end)

        verify_while = [  # verify if already went through all items on the sequence[start:end]
            (Opcode.OVER, b''),  # index = start
            (Opcode.OVER, b''),
            jmp_place_holder  # if index <= start, jump to not_inside_sequence
        ]

        compare_item = [  # verifies if x is in sequence
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.NUMEQUAL, b''),  # found_x = sequence[index] == x
            jmp_place_holder  # if found_x, jump to return_index
        ]

        not_found = [  # increments index and goes back to verify again
            (Opcode.INC, b''),  # index++
            # jump to verify_while
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_while + compare_item + not_found), True)
        not_found.append(jmp_back_to_verify)

        jmp_to_error = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(compare_item + not_found), True)
        verify_while[-1] = jmp_to_error

        not_inside_sequence = [  # send error message saying that x is not in sequence
            (Opcode.PUSHDATA1,
             Integer(len(message)).to_byte_array(signed=True, min_length=1) +
             message),
            (Opcode.THROW, b''),
        ]

        jmp_to_return_index = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(not_found + not_inside_sequence),
            True)
        compare_item[-1] = jmp_to_return_index

        return_index = [  # removes all values in the stack but the index
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
        ]

        return (verify_and_fix_end + verify_and_fix_start + verify_while +
                compare_item + not_found + not_inside_sequence + return_index)
예제 #29
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.StackItem import StackItemType
        from boa3.neo.vm.type.Integer import Integer

        upper_a = Integer(ord('A')).to_byte_array()
        upper_z = Integer(ord('Z')).to_byte_array()
        jmp_place_holder = (Opcode.JMP, b'\x01')

        initializing = [  # initialize auxiliary values
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.PUSH0, b''),  # index = 0
        ]

        verify_while = [  # verifies if while is over
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            jmp_place_holder,  # jump to last statement to clean the stack if index >= len(string)
        ]

        get_substring_left = [  # gets the substring to the left of the index
            (Opcode.REVERSE3, b''),
            (Opcode.DUP, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            (Opcode.LEFT, b''),  # substr_left = string[:index]
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.ROT, b''),
            (Opcode.ROT, b''),
        ]

        get_substring_middle = [  # gets the substring on the index
            (
                Opcode.OVER, b''
            ),  # TODO: verify if string[index] < c0 when other values are implemented
            (Opcode.OVER, b''),
            (
                Opcode.PUSH1, b''
            ),  # modifier = 1, since using upper is only supported with ASCII for now
            (Opcode.SUBSTR,
             b''),  # substr_middle = string[index:index+modifier]
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.DUP, b''),
            (Opcode.PUSHDATA1,
             Integer(len(upper_a)).to_byte_array() + upper_a),
            jmp_place_holder,  # jump to get the substring to the right if substr_middle value is lower than 'A'
        ]

        verify_greater_than_z = [  # verifies if substr_middle is between 'A' and 'Z'
            (Opcode.DUP, b''),
            (Opcode.PUSHDATA1,
             Integer(len(upper_z)).to_byte_array() + upper_z),
            jmp_place_holder,  # jump to get the substring to the right if substr_middle value is greater than 'Z'
        ]

        swap_upper_to_lower_case = [  # change middle_substr to lowercase equivalent
            (Opcode.PUSHINT8, Integer(32).to_byte_array(signed=True)),
            (Opcode.ADD, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
        ]

        jmp_to_join_substring = Opcode.get_jump_and_data(
            Opcode.JMPLT,
            get_bytes_count(verify_greater_than_z + swap_upper_to_lower_case),
            True)
        get_substring_middle[-1] = jmp_to_join_substring

        jmp_to_join_substring = Opcode.get_jump_and_data(
            Opcode.JMPGT, get_bytes_count(swap_upper_to_lower_case), True)
        verify_greater_than_z[-1] = jmp_to_join_substring

        get_substring_middle.extend(verify_greater_than_z)
        get_substring_middle.extend(swap_upper_to_lower_case)

        get_substring_right = [  # gets the substring to the right of the index
            (Opcode.ROT, b''),
            (Opcode.ROT, b''),
            (Opcode.INC, b''),
            (Opcode.NEGATE, b''),
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.ADD, b''),
            (Opcode.RIGHT, b''),  # substr_right = string[index+modifier:]
        ]

        join_substrings = [  # concatenate substr_left, substr_middle, substr_right
            (Opcode.CAT, b''),
            (Opcode.CAT, b''),  # substr_left + substr_middle + substr_right
            (Opcode.NIP, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.REVERSE3, b''),
            (Opcode.INC, b''),  # index ++
            # jump back to verify,
        ]

        jmp_to_verify_while = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_while + get_substring_left +
                             get_substring_middle + get_substring_right +
                             join_substrings))
        join_substrings.append(jmp_to_verify_while)

        clean_stack = [  # removes all auxiliary values
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        while_body = (get_substring_left + get_substring_middle +
                      get_substring_right + join_substrings)

        jmp_to_clean_stack = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(while_body), True)
        verify_while[-1] = jmp_to_clean_stack

        return (initializing + verify_while + while_body + clean_stack)
예제 #30
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.StackItem import StackItemType

        jmp_place_holder = (Opcode.JMP, b'\x01')
        # string, end, start, substring

        verify_negative_index = [  # verify if index is negative value
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if not index < 0, jump to verify_big_end
        ]

        fix_negative_end = [  # fix negative value to a positive equivalent
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            (Opcode.ADD, b''),
            (Opcode.INC, b''),  # end = end + len(string) + 1
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if not end < 0, jump to verify_and_fix_start
        ]

        fix_still_negative_index = [  # if end still is less than 0, then it should be 0
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # end = 0
        ]

        jmp_fix_negative_index = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_negative_end + fix_still_negative_index), True)
        verify_negative_index[-1] = jmp_fix_negative_index

        verify_big_end = [  # verify if end is greater or equals to len(string)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if not end >= len(string), jump to verify_and_fix_start
        ]

        fix_big_end = [  # fix end value to a positive equivalent
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # end = len(string)
        ]

        jmp_other_verifies = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_still_negative_index + verify_big_end +
                            fix_big_end), True)
        fix_negative_end[-1] = jmp_other_verifies

        jmp_fix_big_index = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(fix_big_end), True)
        verify_big_end[-1] = jmp_fix_big_index

        verify_and_fix_end = [  # verify and fix end index
            (Opcode.REVERSE3, b''),  # change positions on stack
        ]
        verify_and_fix_end.extend(verify_negative_index)
        verify_and_fix_end.extend(fix_negative_end)
        verify_and_fix_end.extend(fix_still_negative_index)
        verify_and_fix_end.extend(verify_big_end)
        verify_and_fix_end.extend(fix_big_end)

        verify_and_fix_start = [  # verify and fix end index
            (Opcode.SWAP, b''),  # change positions on stack
        ]

        # fix_negative_start is the same as fix_negative_end, but jump is different
        fix_negative_start = fix_negative_end.copy()
        verify_big_start = [  # verify if start is greater or equals to len(string)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if start >= len(string), return False
        ]

        jmp_other_verifies = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_still_negative_index + verify_big_start), True)
        fix_negative_end[-1] = jmp_other_verifies

        verify_size = [  # verify if len(string[start:end]) > len(substring)
            (Opcode.REVERSE3, b''),
            (Opcode.REVERSE4, b''),
            (Opcode.REVERSE3, b''),
            (Opcode.OVER, b''),
            (Opcode.SUB, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.PUSH0, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            (Opcode.DUP, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if len(string[start:end]) > len(substring), return False
        ]

        compare_starts = [  # string.startswith(substring)
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.NUMEQUAL,
             b''),  # return string[start:end][0:len(substring)] == substring
            jmp_place_holder  # jumps other opcodes
        ]

        jmp_compare_starts = Opcode.get_jump_and_data(
            Opcode.JMPGT, get_bytes_count(compare_starts), True)
        verify_size[-1] = jmp_compare_starts

        jmp_to_false = Opcode.get_jump_and_data(
            Opcode.JMPGE, get_bytes_count(verify_size + compare_starts), True)
        verify_big_start[-1] = jmp_to_false

        verify_and_fix_start.extend(verify_negative_index)
        verify_and_fix_start.extend(fix_negative_start)
        verify_and_fix_start.extend(fix_still_negative_index)
        verify_and_fix_start.extend(verify_big_start)

        return_false = [  # remove all values from stack and put False
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # return False
        ]

        jmp_bigger_substr = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(return_false), True)
        compare_starts[-1] = jmp_bigger_substr

        return (verify_and_fix_end + verify_and_fix_start + verify_size +
                compare_starts + return_false)