Exemple #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
        )
Exemple #2
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
Exemple #3
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.model.builtin.interop.interop import Interop
        from boa3.neo.vm.type.Integer import Integer

        copy_list_and_reverse = [
            (Opcode.UNPACK, b''),  # copy - it must not change the original
            (Opcode.PACK, b''),
            (Opcode.DUP, b''),
            (Opcode.REVERSEITEMS, b'')
        ]
        check_if_arg_is_empty = [
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),
            (Opcode.PUSH0, b''),
        ]

        complete_loop = ([
            (Opcode.DUP, b''),
            (Opcode.POPITEM, b''),
        ] + Interop.Log.opcode + check_if_arg_is_empty)
        complete_loop.append(
            (Opcode.JMPNE,
             Integer(-get_bytes_count(complete_loop)).to_byte_array(
                 signed=True)))

        return (check_if_arg_is_empty + [
            (
                Opcode.JMPEQ,
                Integer(
                    get_bytes_count(copy_list_and_reverse) +
                    1  # the size of the JMPEQ arg
                    + get_bytes_count(complete_loop)).to_byte_array(
                        signed=True)),
        ] + copy_list_and_reverse + complete_loop + [(Opcode.DROP, b'')])
Exemple #4
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
Exemple #5
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
        )
Exemple #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
Exemple #7
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
Exemple #8
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
Exemple #9
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)
Exemple #10
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)
Exemple #11
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')

        # receive: string, chars

        initializing_first_loop = [  # initializes the variables for the first loop
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),  # string_size = len(string)
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.PUSH0, b''),  # index = 0
        ]

        verify_leading_chars = [  # verifies if all leading characters are in chars
            (Opcode.DUP, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            jmp_place_holder,  # if index >= string_size, jump to initialize_second_loop
        ]

        get_leading_char_at_index = [  # gets the character at the current index and create another index variable
            (Opcode.PUSH4, b''),  # to go through the chars
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),  # char = string[index]
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.PUSH0, b''),  # index_chars = 0
        ]

        verify_if_index_gt_len_chars = [  # verify if already compared all chars with char
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            jmp_place_holder,  # if index >= string_size, jump to remove_extras
        ]

        verify_if_char_in_chars = [  # compares char with chars[index_chars]
            (Opcode.PUSH5, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.NUMEQUAL, b''),  # equal = char == chars[index_chars]
            (Opcode.SWAP, b''),
            (Opcode.INC, b''),  # index_chars++
            (Opcode.SWAP, b''),
            # jump back to verify_if_index_gt_len_chars if not equal
        ]

        jmp_back_to_verify_index = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, -get_bytes_count(verify_if_char_in_chars +
                                              verify_if_index_gt_len_chars))
        verify_if_char_in_chars.append(jmp_back_to_verify_index)

        leading_char_found = [  # char is in chars, so go back to verify_leading_chars
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.INC, b''),  # index++
            # jump back to verify_leading_chars
        ]

        jmp_back_to_verify_leading_chars = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_leading_chars + get_leading_char_at_index +
                             verify_if_index_gt_len_chars +
                             verify_if_char_in_chars + leading_char_found))

        leading_char_found.append(jmp_back_to_verify_leading_chars)

        jmp_to_leading_chars = Opcode.get_jump_and_data(
            Opcode.JMPGE,
            get_bytes_count(verify_if_char_in_chars + leading_char_found),
            True)
        verify_if_index_gt_len_chars[-1] = jmp_to_leading_chars

        remove_extras = [  # remove opcodes that won't be used anymore
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        jmp_to_leading_chars = Opcode.get_jump_and_data(
            Opcode.JMPGE,
            get_bytes_count(get_leading_char_at_index +
                            verify_if_index_gt_len_chars +
                            verify_if_char_in_chars + leading_char_found +
                            remove_extras), True)
        verify_leading_chars[-1] = jmp_to_leading_chars

        get_number_of_leading_chars = (initializing_first_loop +
                                       verify_leading_chars +
                                       get_leading_char_at_index +
                                       verify_if_index_gt_len_chars +
                                       verify_if_char_in_chars +
                                       leading_char_found + remove_extras)

        initialize_second_loop = [  # initializes the variables for the second loop
            (Opcode.REVERSE3, b''),  # n_leading = index
            (Opcode.DEC, b''),  # index = string_size - 1
        ]

        verify_trailing_chars = [  # verifies if leading and trailing characters are the same
            (Opcode.DUP, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            jmp_place_holder,  # if index <= n_leading, go strip the string
        ]

        get_trailing_char_at_index = [  # gets the character at the current index and create another index variable
            (Opcode.PUSH4, b''),  # to go through the chars
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),  # char = string[index]
            (Opcode.CONVERT, StackItemType.ByteString),
            (Opcode.PUSH0, b''),  # index_chars = 0
        ]

        get_trailing_char_at_index.extend(verify_if_index_gt_len_chars)
        get_trailing_char_at_index.extend(verify_if_char_in_chars)

        trailing_char_found = [  # char is in chars, so go back to get_trailing_char_at_index
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.DEC, b''),  # index--
            # jump back to get_trailing_char_at_index
        ]

        jmp_back_to_verify_trailing_chars = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(get_trailing_char_at_index + trailing_char_found))

        trailing_char_found.append(jmp_back_to_verify_trailing_chars)

        remove_extras = [  # remove opcodes that won't be used anymore
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        jmp_to_strip_string = Opcode.get_jump_and_data(
            Opcode.JMPLE,
            get_bytes_count(get_trailing_char_at_index + trailing_char_found +
                            remove_extras), True)
        verify_trailing_chars[-1] = jmp_to_strip_string

        get_number_of_trailing_chars = (initialize_second_loop +
                                        verify_trailing_chars +
                                        get_trailing_char_at_index +
                                        trailing_char_found + remove_extras)

        strip_string = [  # strips the string using chars
            (Opcode.NIP, b''),
            (Opcode.OVER, b''),
            (Opcode.SUB, b''),
            (Opcode.INC, b''),
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            (Opcode.SWAP, b''),
            (Opcode.SUBSTR, b''),  # string.strip(chars)
            (Opcode.CONVERT, StackItemType.ByteString),
        ]

        return (get_number_of_leading_chars + get_number_of_trailing_chars +
                strip_string)
Exemple #12
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count

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

        # Receives: string, iterable
        verify_empty_string = [  # verify if string is empty
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),  # iterable_size = len(iterable)
            (Opcode.PUSH0, b''),  # index = 0
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            jmp_place_holder  # if iterable_size is less than or equals to 0, return empty string
        ]

        initialize_string = [  # initializes the return value
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),  # joined = iterable[0]
            (Opcode.SWAP, b''),
            (Opcode.INC, b''),  # index++
            (Opcode.SWAP, b''),
        ]

        from boa3.model.type.type import Type
        if Type.dict.is_type_of(self._arg_iterable.type):
            get_dict_keys = [  # get dictionary keys as an array
                (Opcode.REVERSE3, b''),
                (Opcode.KEYS, b''),
                (Opcode.REVERSE3, b''),
            ]
            initialize_string = get_dict_keys + initialize_string

        verify_index = [  # verify if all items on the iterable were visited
            (Opcode.OVER, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            jmp_place_holder  # jump to remove_extra_values if every item was already visited
        ]

        concat_strings = [  # concatenate the items inside de interable
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.CAT, b''),  # joined = joined + string
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PICKITEM, b''),
            (Opcode.CAT, b''),  # joined = joined + iterable[index]
            (Opcode.SWAP, b''),
            (Opcode.INC, b''),  # index++
            (Opcode.SWAP, b''),
            # jump back to verify_index
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(
            Opcode.JMP, -get_bytes_count(verify_index + concat_strings))
        concat_strings.append(jmp_back_to_verify)

        jmp_concatenation = Opcode.get_jump_and_data(
            Opcode.JMPLE,
            get_bytes_count(initialize_string + verify_index + concat_strings),
            True)
        verify_empty_string[-1] = jmp_concatenation

        add_empty_string = [  # add a empty string at the top of the stack
            (Opcode.PUSHDATA1, b'\x00')
        ]

        jmp_concatenation = Opcode.get_jump_and_data(
            Opcode.JMPGE, get_bytes_count(concat_strings + add_empty_string),
            True)
        verify_index[-1] = jmp_concatenation

        remove_extra_values = [  # remove all values from stack except the joined string
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
        ]

        return (verify_empty_string + initialize_string + verify_index +
                concat_strings + add_empty_string + remove_extra_values)
    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)
Exemple #14
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)
Exemple #15
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.model.type.type import Type
        from boa3.compiler.codegenerator import get_bytes_count

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

        if_statement = [
            (Opcode.DUP, b''),
            (Opcode.ISTYPE, Type.str.stack_item
             ),  # if isinstance(arg1, (str, bytes)) continue
            # if not isinstance(arg1, (str, bytes)) will jump into the else_body
        ]

        if_true_body = [  # if isinstance(arg1, (str, bytes)) body will continue until else_body
            (Opcode.NEWARRAY0, b''),  # list_aux = []
            (Opcode.SWAP, b''),
            (Opcode.DUP, b''),
            (Opcode.SIZE, b''),  # limit = len(arg)
            (Opcode.PUSH0, b''),  # index = 0
        ]

        while_statement = [  # index and limit will be at the top of the stack
            (Opcode.DUP, b''),  # verifies if index < limit
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.LT, b''),
            jmp_place_holder  # if index >= limit, go to break_opcode
        ]

        while_body = [  # will add every byte or character into the array and increase the index
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH1, b''),
            (Opcode.SUBSTR, b''),
            (Opcode.CONVERT, Type.int.stack_item if Type.bytes.is_type_of(
                self.args['sequence'].type) else Type.str.stack_item),
            (Opcode.APPEND, b''),  # list_aux.append(arg[index])
            (Opcode.INC, b''),  # index++
            # returns to beginning of the while to verify if it index < limit
        ]

        jmp_back_to_while_statement = Opcode.get_jump_and_data(
            Opcode.JMP, -get_bytes_count(while_body + while_statement))
        while_body.append(jmp_back_to_while_statement)

        jmp_to_break_body = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, get_bytes_count(while_body), True)
        while_statement[-1] = jmp_to_break_body

        break_opcode = [  # remove auxiliary values from stack after leaving `while`
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            # skips the else_body, because it's a bytestring value and unpacking and packing are expensive
        ]

        else_body = [  # creates a new array from an array, used when the arg is not a str or bytes value
            (Opcode.UNPACK, b''),
            (Opcode.PACK, b''),
        ]

        jmp_else_body = Opcode.get_jump_and_data(Opcode.JMP,
                                                 get_bytes_count(else_body),
                                                 True)
        break_opcode.append(jmp_else_body)

        if_true_body = if_true_body + while_statement + while_body + break_opcode

        jmp_if_true_body = Opcode.get_jump_and_data(
            Opcode.JMPIFNOT, get_bytes_count(if_true_body))
        if_statement.append(jmp_if_true_body)

        reverse_array = [  # reverse the array
            (Opcode.DUP, b''),
            (Opcode.REVERSEITEMS, b''),  # return reversed(arg)
        ]

        return (if_statement + if_true_body + else_body + reverse_array)
Exemple #16
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)
Exemple #17
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
Exemple #18
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)
    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)
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count

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

        # region Sequence logic

        repack_array = [  # recreates an array to not change the original one
            (Opcode.UNPACK, b''),
            (Opcode.PACK, b''),
        ]

        sequence_initialize = [  # initializes variables
            (Opcode.PUSH0, b''),  # count = 0
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),  # index = len(sequence) - -1
        ]

        sequence_verify_while = [  # verifies if all the elements from the sequence were visited
            (Opcode.DUP, b''),  # would be equivalent to: while (index >= 0)
            (Opcode.SIGN, b''),
            (Opcode.PUSH0, b''),  # if index < 0:
            jmp_place_holder,  # jump to clean the stack
        ]

        sequence_get_element = [  # gets a element from the sequence
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b'')  # element = sequence[index]
        ]

        sequence_equals = [  # verifies if the element and the given value are the same
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.EQUAL, b''),  # if element != value:
            jmp_place_holder  # jump to list_tuple_count_index_dec
        ]

        sequence_count_inc = [  # increment count if element == value
            (Opcode.SWAP, b''),
            (Opcode.INC, b''),  # count++
            (Opcode.SWAP, b''),
        ]

        num_jmp_code = get_bytes_count(sequence_count_inc)
        jmp_to_dec_statement = Opcode.get_jump_and_data(Opcode.JMPIFNOT, num_jmp_code, True)
        sequence_equals[-1] = jmp_to_dec_statement

        list_tuple_count_index_dec = [  # decreases the index
            (Opcode.DEC, b''),  # index--
            # return to the while verification
        ]

        num_jmp_code = -get_bytes_count(list_tuple_count_index_dec + sequence_count_inc + sequence_equals +
                                        sequence_get_element + sequence_verify_while)
        jmp_back_to_while_verify_statement = Opcode.get_jump_and_data(Opcode.JMP, num_jmp_code)
        list_tuple_count_index_dec.append(jmp_back_to_while_verify_statement)

        num_jmp_code = get_bytes_count(sequence_get_element + sequence_equals +
                                       sequence_count_inc + list_tuple_count_index_dec)
        jmp_to_clean_statement = Opcode.get_jump_and_data(Opcode.JMPLT, num_jmp_code, True)
        sequence_verify_while[-1] = jmp_to_clean_statement

        sequence_clean_stack = [
            (Opcode.DROP, b''),
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        # endregion

        return (
            repack_array +
            sequence_initialize +
            sequence_verify_while +
            sequence_get_element +
            sequence_equals +
            sequence_count_inc +
            list_tuple_count_index_dec +
            sequence_clean_stack
        )
Exemple #21
0
    def _compare_values(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.neo.vm.type.Integer import Integer

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

        test_if_are_equal = [
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            (Opcode.EQUAL, b''),  # if str1 == str2:
            Opcode.get_jump_and_data(Opcode.JMPIFNOT, 4),
            (Opcode.PUSH1, b''),
            jmp_place_holder,  # go to final test
        ]

        get_limit_index = [
            (Opcode.OVER, b''),  # limit = min((len(str1), len(str2))
            (Opcode.SIZE, b''),
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.MIN, b''),
            (Opcode.PUSH0, b''),  # index = 0
        ]

        while_body_before_compare = [
            (Opcode.PUSH3, b''),  # value1 = str1[index]
            (Opcode.get_dup(3), b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),
            (Opcode.OVER, b''),
            (Opcode.PUSH4, b''),  # value2 = str2[index]
            (Opcode.get_dup(4), b''),
            (Opcode.SWAP, b''),
            (Opcode.PICKITEM, b''),
        ]
        while_body_compare = [
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            (Opcode.JMPEQ, Integer(7).to_byte_array(
                signed=True)),  # if value1 != value2 jmp to end
            (Opcode.GT, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            jmp_place_holder,  # jmp to end
        ]
        while_body_after_compare = [
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.INC, b''),  # index++
        ]

        while_full_body = while_body_before_compare + while_body_compare + while_body_after_compare
        while_bytes_size = get_bytes_count(while_full_body)
        get_limit_index.append(
            Opcode.get_jump_and_data(Opcode.JMP, while_bytes_size, True))

        while_condition = [(Opcode.OVER, b''), (Opcode.OVER, b'')]
        while_condition_bytes_size = get_bytes_count(while_condition)
        while_condition.append(
            Opcode.get_jump_and_data(
                Opcode.JMPGT, -while_bytes_size - while_condition_bytes_size))

        while_else_body = [
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
            (Opcode.OVER, b''),  # if len(str1) > len(str2) jmp to end
            (Opcode.SIZE, b''),
            (Opcode.OVER, b''),
            (Opcode.SIZE, b''),
            (Opcode.GT, b''),
        ]

        everything_after_while_check = while_body_after_compare + while_condition + while_else_body
        jmp_while_check = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(everything_after_while_check), True)
        while_body_compare[-1] = jmp_while_check

        everything_after_equal_check = (get_limit_index +
                                        while_body_before_compare +
                                        while_body_compare +
                                        everything_after_while_check)
        jmp_test_equal = Opcode.get_jump_and_data(
            Opcode.JMP, get_bytes_count(everything_after_equal_check), True)
        test_if_are_equal[-1] = jmp_test_equal

        final_test = [
            (Opcode.JMPIF, Integer(4).to_byte_array(
                signed=True)),  # if condition is not True
            (Opcode.DROP, b''),  # remove str1 <=> return str2
            (Opcode.JMP, Integer(3).to_byte_array(signed=True)),  # else
            (Opcode.NIP, b'')  # remove str2 <=> return str1
        ]

        return (test_if_are_equal + everything_after_equal_check + final_test)
Exemple #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)
Exemple #23
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count
        from boa3.neo.vm.type.Integer import Integer

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

        verify_number_of_parameters = [  # verifies if the stack has 2 or 3 items
            (Opcode.DEPTH, b''),
            (Opcode.PUSH2, b''),
            (Opcode.JMPEQ, b''),
            jmp_place_holder
        ]

        if_n_parameters_gt_2 = [  # if number of items in stack is 3
            (Opcode.REVERSE3, b''),
            (Opcode.UNPACK, b''),
            (Opcode.INC, b''),
            (Opcode.INC, b''),
            jmp_place_holder  # skips the next block of instructions
        ]

        if_n_parameters_eq_2 = [  # if number of items in stack is 2
            (Opcode.PUSH2, b'')
        ]

        jmp_n_parameters_eq_2 = Opcode.get_jump_and_data(Opcode.JMP, get_bytes_count(if_n_parameters_eq_2), True)
        if_n_parameters_gt_2[-1] = jmp_n_parameters_eq_2

        jmp_n_parameters_gt_2 = Opcode.get_jump_and_data(Opcode.JMPEQ, get_bytes_count(if_n_parameters_gt_2))
        verify_number_of_parameters[-1] = jmp_n_parameters_gt_2

        repack_array = [  # pack all the arguments in the array
            (Opcode.PACK, b''),
        ]

        is_int_initialize = [  # puts the last array element as the max value
            (Opcode.DUP, b''),  # index = len(array) - 1
            (Opcode.SIZE, b''),
            (Opcode.DEC, b''),
            (Opcode.OVER, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),     # min = array[index]
        ]

        is_int_while = [    # this will get the next number in the array and compare it with the current min
            (Opcode.SWAP, b''),         # index--
            (Opcode.DEC, b''),
            (Opcode.SWAP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),         # min = min if min < array[index] else array[index]
            (Opcode.PICKITEM, b''),
        ]
        is_int_while.extend(self._compare_values())
        is_int_while.extend([
            (Opcode.OVER, b''),
            (Opcode.SIGN, b'')
            # if index != 0: go back to index--
            # else go to the end
        ])

        jmp_back_to_while_statement = (Opcode.JMPIF, Integer(-get_bytes_count(is_int_while)).to_byte_array(signed=True))
        is_int_while.append(jmp_back_to_while_statement)

        clean_stack = [    # removes everything but min
            (Opcode.REVERSE3, b''),
            (Opcode.DROP, b''),
            (Opcode.DROP, b''),
        ]

        return (
            verify_number_of_parameters +
            if_n_parameters_gt_2 +
            if_n_parameters_eq_2 +
            repack_array +
            is_int_initialize +
            is_int_while +
            clean_stack
        )