text: """This module contains the detection code SWC-128 - DOS with block gas limit."""
  
  import logging
  from typing import Dict, cast, List
  
  from mythril.analysis.swc_data import DOS_WITH_BLOCK_GAS_LIMIT
  from mythril.analysis.report import Issue
  from mythril.analysis.modules.base import DetectionModule
  from mythril.analysis.solver import get_transaction_sequence, UnsatError
  from mythril.analysis.analysis_args import analysis_args
  from mythril.laser.ethereum.state.global_state import GlobalState
  from mythril.laser.ethereum.state.annotation import StateAnnotation
  from mythril.laser.ethereum import util
  from copy import copy
  
  log = logging.getLogger(__name__)
  
  
  class VisitsAnnotation(StateAnnotation):
      """State annotation that stores the addresses of state-modifying operations"""
  
      def __init__(self) -> None:
          self.loop_start = None  # type: int
          self.jump_targets = {}  # type: Dict[int, int]
  
      def __copy__(self):
          result = VisitsAnnotation()
  
          result.loop_start = self.loop_start
          result.jump_targets = copy(self.jump_targets)
          return result
  
  
  class DosModule(DetectionModule):
      """This module consists of a makeshift loop detector that annotates the state with
      a list of byte ranges likely to be loops. If a CALL or SSTORE detection is found in
      one of the ranges it creates a low-severity issue. This is not super precise but
      good enough to identify places that warrant a closer look. Checking the loop condition
      would be a possible improvement.
       """
  
      def __init__(self) -> None:
          """"""
          super().__init__(
              name="DOS",
              swc_id=DOS_WITH_BLOCK_GAS_LIMIT,
              description="Check for DOS",
              entrypoint="callback",
              pre_hooks=["JUMP", "JUMPI", "CALL", "SSTORE"],
          )
  
      def _execute(self, state: GlobalState) -> None:
  
          """
          :param state:
          :return:
          """
          issues = self._analyze_state(state)
          self._issues.extend(issues)
  
      def _analyze_state(self, state: GlobalState) -> List[Issue]:
          """
          :param state: the current state
          :return: returns the issues for that corresponding state
          """
  
          opcode = state.get_current_instruction()["opcode"]
          address = state.get_current_instruction()["address"]
  
          annotations = cast(
              List[VisitsAnnotation], list(state.get_annotations(VisitsAnnotation))
          )
  
          if len(annotations) == 0:
              annotation = VisitsAnnotation()
              state.annotate(annotation)
          else:
              annotation = annotations[0]
  
          if opcode in ["JUMP", "JUMPI"]:
  
              if annotation.loop_start is not None:
                  return []
              try:
                  target = util.get_concrete_int(state.mstate.stack[-1])
              except TypeError:
                  log.debug("Symbolic target encountered in dos module")
                  return []
              if target in annotation.jump_targets:
                  annotation.jump_targets[target] += 1
              else:
                  annotation.jump_targets[target] = 1
  
              if annotation.jump_targets[target] > min(2, analysis_args.loop_bound - 1):
                  annotation.loop_start = address
  
          elif annotation.loop_start is not None:
  
              if opcode == "CALL":
                  operation = "A message call"
              else:
                  operation = "A storage modification"
  
              description_head = (
                  "Potential denial-of-service if block gas limit is reached."
              )
              description_tail = "{} is executed in a loop. Be aware that the transaction may fail to execute if the loop is unbounded and the necessary gas exceeds the block gas limit.".format(
                  operation
              )
  
              try:
                  transaction_sequence = get_transaction_sequence(
                      state, state.mstate.constraints
                  )
              except UnsatError:
                  return []
  
              issue = Issue(
                  contract=state.environment.active_account.contract_name,
                  function_name=state.environment.active_function_name,
                  address=annotation.loop_start,
                  swc_id=DOS_WITH_BLOCK_GAS_LIMIT,
                  bytecode=state.environment.code.bytecode,
                  title="Potential denial-of-service if block gas limit is reached",
                  severity="Low",
                  description_head=description_head,
                  description_tail=description_tail,
                  gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
                  transaction_sequence=transaction_sequence,
              )
  
              return [issue]
  
          return []
  
  
  detector = DosModule()
  