code: def call_contract_function(
          web3,
          address,
          normalizers,
          function_identifier,
          transaction,
          block_id=None,
          contract_abi=None,
          fn_abi=None,
          *args,
          **kwargs):
      
      call_transaction = prepare_transaction(
          address,
          web3,
          fn_identifier=function_identifier,
          contract_abi=contract_abi,
          fn_abi=fn_abi,
          transaction=transaction,
          fn_args=args,
          fn_kwargs=kwargs,
      )
  
      if block_id is None:
          return_data = web3.eth.call(call_transaction)
      else:
          return_data = web3.eth.call(call_transaction, block_identifier=block_id)
  
      if fn_abi is None:
          fn_abi = find_matching_fn_abi(contract_abi, function_identifier, args, kwargs)
  
      output_types = get_abi_output_types(fn_abi)
  
      try:
          output_data = decode_abi(output_types, return_data)
      except DecodingError as e:
          # Provide a more helpful error message than the one provided by
          # eth-abi-utils
          is_missing_code_error = (
              return_data in ACCEPTABLE_EMPTY_STRINGS and
              web3.eth.getCode(address) in ACCEPTABLE_EMPTY_STRINGS
          )
          if is_missing_code_error:
              msg = (
                  "Could not transact with/call contract function, is contract "
                  "deployed correctly and chain synced?"
              )
          else:
              msg = (
                  "Could not decode contract function call {} return data {} for "
                  "output_types {}".format(
                      function_identifier,
                      return_data,
                      output_types
                  )
              )
          raise BadFunctionCallOutput(msg) from e
  
      _normalizers = itertools.chain(
          BASE_RETURN_NORMALIZERS,
          normalizers,
      )
      normalized_data = map_abi_data(_normalizers, output_types, output_data)
  
      if len(normalized_data) == 1:
          return normalized_data[0]
      else:
          return normalized_data
docs: Helper function for interacting with a contract function using the
      `eth_call` API.