예제 #1
0
    def _search(self, event):
        frame = self.active_frame()
        tree = self.root.main.oplist
        if not frame.tag_ranges("sel"):
            tree.clear_selection()
            return
        start, stop = frame.tag_ranges("sel")
        if self._scope and (frame != self._scope[0] or start < self._scope[1]
                            or stop > self._scope[2]):
            pc = False
        else:
            pc = [
                k for k, v in self.root.pcMap.items()
                if "path" in v and frame._label in v["path"]
                and is_inside_offset((start, stop), v["offset"])
            ]
        if not pc:
            frame.clear_highlight()
            tree.clear_selection()
            return

        def key(k):
            return (start - self.root.pcMap[k]["offset"][0]) + (
                self.root.pcMap[k]["offset"][1] - stop)

        id_ = sorted(pc, key=key)[0]
        tree.selection_set(id_)
예제 #2
0
파일: vyper.py 프로젝트: tomcbean/brownie
def _find_node_by_offset(ast_json: List, offset: Tuple) -> Dict:
    node = next(i for i in ast_json if is_inside_offset(offset, _convert_src(i["src"])))
    if _convert_src(node["src"]) == offset:
        return node
    node_list = [i for i in node.values() if isinstance(i, dict) and "ast_type" in i]
    node_list.extend([x for i in node.values() if isinstance(i, list) for x in i])
    if node_list:
        return _find_node_by_offset(node_list, offset)
    return _find_node_by_offset(ast_json[ast_json.index(node) + 1 :], offset)
예제 #3
0
 def toggle_on(self):
     try:
         op = self.oplist.selection()[0]
     except IndexError:
         return False
     if self.oplist.item(op, 'tags')[0] == "NoSource":
         return False
     pc = self.root.pcMap[op]
     for key, value in sorted(self.root.pcMap.items(),
                              key=lambda k: int(k[0])):
         if ('path' not in value or value['path'] != pc['path']
                 or not is_inside_offset(value['offset'], pc['offset'])):
             self.oplist.detach(key)
         else:
             self.oplist.move(key, '', key)
     self.oplist.see(op)
     self.root.main.note.apply_scope(*pc['offset'])
     return True
예제 #4
0
def _generate_coverage_data(source_map_str: str, opcodes_str: str,
                            contract_name: str, ast_json: List) -> Tuple:
    if not opcodes_str:
        return {}, {}, {}

    source_map = deque(expand_source_map(source_map_str))
    opcodes = deque(opcodes_str.split(" "))

    fn_nodes = [i for i in ast_json if i["ast_type"] == "FunctionDef"]
    fn_offsets = dict((i["name"], _convert_src(i["src"])) for i in fn_nodes)
    stmt_nodes = set(
        _convert_src(i["src"]) for i in _get_statement_nodes(fn_nodes))

    statement_map: Dict = {}
    branch_map: Dict = {}

    pc_list: List = []
    count, pc = 0, 0

    while opcodes:
        # format of source is [start, stop, contract_id, jump code]
        source = source_map.popleft()
        pc_list.append({"op": opcodes.popleft(), "pc": pc})

        if source[3] != "-":
            pc_list[-1]["jump"] = source[3]

        pc += 1
        if opcodes and opcodes[0][:2] == "0x":
            pc_list[-1]["value"] = opcodes.popleft()
            pc += int(pc_list[-1]["op"][4:])

        # set source offset (-1 means none)
        if source[0] == -1:
            if (len(pc_list) > 6 and pc_list[-7]["op"] == "CALLVALUE"
                    and pc_list[-1]["op"] == "REVERT"):
                # special case - initial nonpayable check on vyper >=0.2.5
                pc_list[-1]["dev"] = "Cannot send ether to nonpayable function"
                # hackiness to prevent the source highlight from showing the entire contract
                pc_list[-2].update(path="0", offset=[0, 0])
            continue
        offset = (source[0], source[0] + source[1])
        pc_list[-1]["path"] = "0"
        pc_list[-1]["offset"] = offset

        try:
            if "offset" in pc_list[-2] and offset == pc_list[-2]["offset"]:
                pc_list[-1]["fn"] = pc_list[-2]["fn"]
            else:
                # statement coverage
                fn = next(k for k, v in fn_offsets.items()
                          if is_inside_offset(offset, v))
                pc_list[-1]["fn"] = f"{contract_name}.{fn}"
                stmt_offset = next(i for i in stmt_nodes
                                   if is_inside_offset(offset, i))
                stmt_nodes.remove(stmt_offset)
                statement_map.setdefault(pc_list[-1]["fn"],
                                         {})[count] = stmt_offset
                pc_list[-1]["statement"] = count
                count += 1
        except (KeyError, IndexError, StopIteration):
            pass

        if pc_list[-1]["op"] not in ("JUMPI", "REVERT"):
            continue

        node = _find_node_by_offset(ast_json, offset)
        if pc_list[-1]["op"] == "REVERT":
            # custom revert error strings
            if node["ast_type"] == "FunctionDef" and pc_list[-7][
                    "op"] == "CALLVALUE":
                pc_list[-1]["dev"] = "Cannot send ether to nonpayable function"
            elif node["ast_type"] == "Subscript":
                pc_list[-1]["dev"] = "Index out of range"
            elif node["ast_type"] in ("AugAssign", "BinOp"):
                if node["op"]["ast_type"] == "Sub":
                    pc_list[-1]["dev"] = "Integer underflow"
                elif node["op"]["ast_type"] == "Div":
                    pc_list[-1]["dev"] = "Division by zero"
                elif node["op"]["ast_type"] == "Mod":
                    pc_list[-1]["dev"] = "Modulo by zero"
                else:
                    pc_list[-1]["dev"] = "Integer overflow"
            continue

        if node["ast_type"] in ("Assert", "If") or (
                node["ast_type"] == "Expr" and node["value"]["func"].get(
                    "id", None) == "assert_modifiable"):
            # branch coverage
            pc_list[-1]["branch"] = count
            branch_map.setdefault(pc_list[-1]["fn"], {})
            if node["ast_type"] == "If":
                branch_map[pc_list[-1]["fn"]][count] = _convert_src(
                    node["test"]["src"]) + (False, )
            else:
                branch_map[pc_list[-1]["fn"]][count] = offset + (True, )
            count += 1

    pc_list[0]["path"] = "0"
    pc_list[0]["offset"] = [0, _convert_src(ast_json[-1]["src"])[1]]

    pc_map = dict((i.pop("pc"), i) for i in pc_list)

    return pc_map, {"0": statement_map}, {"0": branch_map}