text: #!/usr/bin/env python3
  # Copyright (c) 2017 The Bitcoin Core developers
  # Distributed under the MIT software license, see the accompanying
  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  """Class for Human_Charity_Coin_Protocold node under test"""
  
  import decimal
  import errno
  import http.client
  import json
  import logging
  import os
  import re
  import subprocess
  import time
  
  from .authproxy import JSONRPCException
  from .util import (
      assert_equal,
      delete_cookie_file,
      get_rpc_proxy,
      rpc_url,
      wait_until,
      p2p_port,
  )
  
  # For Python 3.4 compatibility
  JSONDecodeError = getattr(json, "JSONDecodeError", ValueError)
  
  BITCOIND_PROC_WAIT_TIMEOUT = 600
  
  class TestNode():
      """A class for representing a Human_Charity_Coin_Protocold node under test.
  
      This class contains:
  
      - state about the node (whether it's running, etc)
      - a Python subprocess.Popen object representing the running process
      - an RPC connection to the node
      - one or more P2P connections to the node
  
  
      To make things easier for the test writer, any unrecognised messages will
      be dispatched to the RPC connection."""
  
      def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mocktime, coverage_dir, use_cli=False):
          self.index = i
          self.datadir = os.path.join(dirname, "node" + str(i))
          self.rpchost = rpchost
          if timewait:
              self.rpc_timeout = timewait
          else:
              # Wait for up to 60 seconds for the RPC server to respond
              self.rpc_timeout = 600
          if binary is None:
              self.binary = os.getenv("BITCOIND", "Human_Charity_Coin_Protocold")
          else:
              self.binary = binary
          self.stderr = stderr
          self.coverage_dir = coverage_dir
          # Most callers will just need to add extra args to the standard list below. For those callers that need more flexibity, they can just set the args property directly.
          self.extra_args = extra_args
          self.args = [
              self.binary,
              "-datadir=" + self.datadir,
              "-rest",
              "-debug",
              "-debugexclude=libevent",
              "-debugexclude=leveldb",
              "-mocktime=" + str(mocktime),
              "-uacomment=testnode%d" % i
          ]
  
          self.cli = TestNodeCLI(os.getenv("BITCOINCLI", "Human_Charity_Coin_Protocol-cli"), self.datadir)
          self.use_cli = use_cli
  
          self.running = False
          self.process = None
          self.rpc_connected = False
          self.rpc = None
          self.url = None
          self.log = logging.getLogger('TestFramework.node%d' % i)
          self.cleanup_on_exit = True # Whether to kill the node when this object goes away
  
          self.p2ps = []
  
      def __del__(self):
          # Ensure that we don't leave any bitcoind processes lying around after
          # the test ends
          if self.process and self.cleanup_on_exit:
              # Should only happen on test failure
              # Avoid using logger, as that may have already been shutdown when
              # this destructor is called.
              print("Cleaning up leftover process")
              self.process.kill()
  
      def __getattr__(self, name):
          """Dispatches any unrecognised messages to the RPC connection or a CLI instance."""
          if self.use_cli:
              return getattr(self.cli, name)
          else:
              assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection"
              return getattr(self.rpc, name)
  
      def start(self, extra_args=None, stderr=None, *args, **kwargs):
          """Start the node."""
          if extra_args is None:
              extra_args = self.extra_args
          if stderr is None:
              stderr = self.stderr
          # Delete any existing cookie file -- if such a file exists (eg due to
          # unclean shutdown), it will get overwritten anyway by bitcoind, and
          # potentially interfere with our attempt to authenticate
          delete_cookie_file(self.datadir)
          self.process = subprocess.Popen(self.args + extra_args, stderr=stderr, *args, **kwargs)
          self.running = True
          self.log.debug("Human_Charity_Coin_Protocold started, waiting for RPC to come up")
  
      def wait_for_rpc_connection(self):
          """Sets up an RPC connection to the Human_Charity_Coin_Protocold process. Returns False if unable to connect."""
          # Poll at a rate of four times per second
          poll_per_s = 4
          time.sleep(5)
          for _ in range(poll_per_s * self.rpc_timeout):
              assert self.process.poll() is None, "Human_Charity_Coin_Protocold exited with status %i during initialization" % self.process.returncode
              try:
                  self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
                  while self.rpc.getblockcount() < 0:
                      time.sleep(1)
                  # If the call to getblockcount() succeeds then the RPC connection is up
                  self.rpc_connected = True
                  self.url = self.rpc.url
                  self.log.debug("RPC successfully started")
                  return
              except IOError as e:
                  if e.errno != errno.ECONNREFUSED:  # Port not yet open?
                      raise  # unknown IO error
              except JSONRPCException as e:  # Initialization phase
                  if e.error['code'] != -28:  # RPC in warmup?
                      raise  # unknown JSON RPC exception
              except ValueError as e:  # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
                  if "No RPC credentials" not in str(e):
                      raise
              time.sleep(1.0 / poll_per_s)
          raise AssertionError("Unable to connect to Human_Charity_Coin_Protocold")
  
      def get_wallet_rpc(self, wallet_name):
          if self.use_cli:
              return self.cli("-rpcwallet={}".format(wallet_name))
          else:
              assert self.rpc_connected
              assert self.rpc
              wallet_path = "wallet/%s" % wallet_name
              return self.rpc / wallet_path
  
      def stop_node(self):
          """Stop the node."""
          if not self.running:
              return
          self.log.debug("Stopping node")
          try:
              self.stop()
          except http.client.CannotSendRequest:
              self.log.exception("Unable to stop node.")
          del self.p2ps[:]
  
      def is_node_stopped(self):
          """Checks whether the node has stopped.
  
          Returns True if the node has stopped. False otherwise.
          This method is responsible for freeing resources (self.process)."""
          time.sleep(20)
          if not self.running:
              return True
          return_code = self.process.poll()
          if return_code is None:
              return False
  
          # process has stopped. Assert that it didn't return an error code.
          assert_equal(return_code, 0)
          self.running = False
          self.process = None
          self.rpc_connected = False
          self.rpc = None
          self.log.debug("Node stopped")
          return True
  
      def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
          wait_until(self.is_node_stopped, timeout=timeout)
  
      def node_encrypt_wallet(self, passphrase):
          """"Encrypts the wallet.
  
          This causes Human_Charity_Coin_Protocold to shutdown, so this method takes
          care of cleaning up resources."""
          self.encryptwallet(passphrase)
          self.wait_until_stopped()
  
      def add_p2p_connection(self, p2p_conn, *args, **kwargs):
          """Add a p2p connection to the node.
  
          This method adds the p2p connection to the self.p2ps list and also
          returns the connection to the caller."""
          if 'dstport' not in kwargs:
              kwargs['dstport'] = p2p_port(self.index)
          if 'dstaddr' not in kwargs:
              kwargs['dstaddr'] = '127.0.0.1'
  
          p2p_conn.peer_connect(*args, **kwargs)
          self.p2ps.append(p2p_conn)
  
          return p2p_conn
  
      @property
      def p2p(self):
          """Return the first p2p connection
  
          Convenience property - most tests only use a single p2p connection to each
          node, so this saves having to write node.p2ps[0] many times."""
          assert self.p2ps, "No p2p connection"
          return self.p2ps[0]
  
      def disconnect_p2ps(self):
          """Close all p2p connections to the node."""
          for p in self.p2ps:
              p.peer_disconnect()
          del self.p2ps[:]
  
  class TestNodeCLIAttr:
      def __init__(self, cli, command):
          self.cli = cli
          self.command = command
  
      def __call__(self, *args, **kwargs):
          return self.cli.send_cli(self.command, *args, **kwargs)
  
      def get_request(self, *args, **kwargs):
          return lambda: self(*args, **kwargs)
  
  class TestNodeCLI():
      """Interface to Human_Charity_Coin_Protocol-cli for an individual node"""
  
      def __init__(self, binary, datadir):
          self.options = []
          self.binary = binary
          self.datadir = datadir
          self.input = None
          self.log = logging.getLogger('TestFramework.bitcoincli')
  
      def __call__(self, *options, input=None):
          # TestNodeCLI is callable with Human_Charity_Coin_Protocol-cli command-line options
          cli = TestNodeCLI(self.binary, self.datadir)
          cli.options = [str(o) for o in options]
          cli.input = input
          return cli
  
      def __getattr__(self, command):
          return TestNodeCLIAttr(self, command)
  
      def batch(self, requests):
          results = []
          for request in requests:
             try:
                 results.append(dict(result=request()))
             except JSONRPCException as e:
                 results.append(dict(error=e))
          return results
  
      def send_cli(self, command=None, *args, **kwargs):
          """Run Human_Charity_Coin_Protocol-cli command. Deserializes returned string as python object."""
  
          pos_args = [str(arg) for arg in args]
          named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()]
          assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same Human_Charity_Coin_Protocol-cli call"
          p_args = [self.binary, "-datadir=" + self.datadir] + self.options
          if named_args:
              p_args += ["-named"]
          if command is not None:
              p_args += [command]
          p_args += pos_args + named_args
          self.log.debug("Running bitcoin-cli command: %s" % command)
          process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
          cli_stdout, cli_stderr = process.communicate(input=self.input)
          returncode = process.poll()
          if returncode:
              match = re.match(r'error code: ([-0-9]+)\nerror message:\n(.*)', cli_stderr)
              if match:
                  code, message = match.groups()
                  raise JSONRPCException(dict(code=int(code), message=message))
              # Ignore cli_stdout, raise with cli_stderr
              raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)
          try:
              return json.loads(cli_stdout, parse_float=decimal.Decimal)
          except JSONDecodeError:
              return cli_stdout.rstrip("\n")
  