github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/integration/sawtooth_integration/tests/node_controller.py (about)

     1  # Copyright 2017 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  # --------------------------------------------------------------------------
    15  
    16  import os
    17  import subprocess
    18  import shlex
    19  import time
    20  import logging
    21  import signal
    22  
    23  from sawtooth_integration.tests.integration_tools import wait_for_rest_apis
    24  
    25  
    26  LOGGER = logging.getLogger(__name__)
    27  
    28  
    29  # peering arrangements
    30  
    31  def peer_with_genesis_only(num):
    32      if num > 0:
    33          return '--peers {}'.format(
    34              endpoint(0))
    35  
    36      return ''
    37  
    38  
    39  def peer_to_preceding_only(num):
    40      if num > 0:
    41          return '--peers {}'.format(
    42              endpoint(num - 1))
    43  
    44      return ''
    45  
    46  
    47  def everyone_peers_with_everyone(num):
    48      if num > 0:
    49          peers = ','.join(endpoint(i) for i in range(num))
    50          return '--peers {}'.format(peers)
    51  
    52      return ''
    53  
    54  
    55  # processor arrangements
    56  
    57  def intkey_config_registry(num):
    58      # all nodes get the same processors
    59      return 'intkey-tp-python', 'settings-tp', 'poet-validator-registry-tp'
    60  
    61  
    62  def intkey_config_identity_registry(num):
    63      return (
    64          'intkey-tp-python',
    65          'settings-tp',
    66          'identity-tp',
    67          'poet-validator-registry-tp',
    68      )
    69  
    70  
    71  def intkey_xo_config_registry(num):
    72      # all nodes get the same processors
    73      return (
    74          'intkey-tp-python',
    75          'xo-tp-python',
    76          'settings-tp',
    77          'poet-validator-registry-tp'
    78      )
    79  
    80  
    81  # scheduler arrangements
    82  
    83  def all_serial(num):
    84      return 'serial'
    85  
    86  
    87  def all_parallel(num):
    88      return 'parallel'
    89  
    90  
    91  def even_parallel_odd_serial(num):
    92      return 'parallel' if num % 2 == 0 else 'serial'
    93  
    94  
    95  def even_serial_odd_parallel(num):
    96      return 'parallel' if num % 2 == 1 else 'serial'
    97  
    98  
    99  # node
   100  
   101  def start_node(num,
   102                 processor_func,
   103                 peering_func,
   104                 scheduler_func,
   105                 sawtooth_home,
   106                 validator_cmd_func,
   107                 poet_kwargs):
   108      rest_api = start_rest_api(num)
   109      processors = start_processors(num, processor_func)
   110      validator = start_validator(num,
   111                                  peering_func,
   112                                  scheduler_func,
   113                                  sawtooth_home,
   114                                  validator_cmd_func,
   115                                  poet_kwargs)
   116  
   117      wait_for_rest_apis(['127.0.0.1:{}'.format(8008 + num)])
   118  
   119      return [rest_api] + processors + [validator]
   120  
   121  
   122  def stop_node(process_list):
   123      # This may seem a little dramatic, but seriously,
   124      # validators don't go down without a fight.
   125      for _ in range(2):
   126          for process in process_list:
   127              pid = process.pid
   128              LOGGER.debug('Stopping process %s', pid)
   129              process.send_signal(signal.SIGINT)
   130          time.sleep(15)
   131  
   132  
   133  # validator
   134  
   135  def validator_cmds(num,
   136                     peering_func,
   137                     scheduler_func,
   138                     sawtooth_home,
   139                     initial_wait_time=3000.0,
   140                     minimum_wait_time=1.0,
   141                     target_wait_time=20.0,
   142                     block_claim_delay=1,
   143                     key_block_claim_limit=25,
   144                     population_estimate_sample_size=50,
   145                     signup_commit_maximum_delay=0,
   146                     ztest_maximum_win_deviation=3.075,
   147                     ztest_minimum_win_count=3,
   148                     ):
   149      '''
   150      Return a list consisting of the commands
   151      needed to start the validator for the num-th node.
   152  
   153      If num == 0, the command will start the genesis validator.
   154  
   155      Args:
   156          num (int): the num-th node
   157          peering_func (int -> str): a function of one argument n
   158              returning a string specifying the peers of the num-th node
   159      '''
   160      keygen = 'sawadm keygen {}'.format(
   161          os.path.join(sawtooth_home, 'keys', 'validator'))
   162  
   163      validator = ' '.join([
   164          'sawtooth-validator -v',
   165          '--scheduler {}'.format(scheduler_func(num)),
   166          '--endpoint {}'.format(endpoint(num)),
   167          '--bind component:{}'.format(bind_component(num)),
   168          '--bind network:{}'.format(bind_network(num)),
   169          '--bind consensus:{}'.format(bind_consensus(num)),
   170          peering_func(num)])
   171  
   172      # genesis stuff
   173      priv = os.path.join(sawtooth_home, 'keys', 'validator.priv')
   174  
   175      config_genesis = ' '.join([
   176          'sawset genesis',
   177          '-k {}'.format(priv),
   178          '-o {}'.format(os.path.join(
   179              sawtooth_home, 'data', 'config-genesis.batch'))
   180      ])
   181  
   182      with open(
   183          '/project/sawtooth-core/consensus/poet/simulator/packaging/'
   184              'simulator_rk_pub.pem') as fd:
   185          public_key_pem = fd.read()
   186  
   187      # Use the poet CLI to get the enclave measurement so that we can put the
   188      # value in the settings config for the validator registry transaction
   189      # processor
   190      result = \
   191          subprocess.run(
   192              ['poet', 'enclave', 'measurement'],
   193              stdout=subprocess.PIPE)
   194      enclave_measurement = result.stdout.decode('utf-8')
   195  
   196      # Use the poet CLI to get the enclave basename so that we can put the
   197      # value in the settings config for the validator registry transaction
   198      # processor
   199      result = \
   200          subprocess.run(
   201              ['poet', 'enclave', 'basename'],
   202              stdout=subprocess.PIPE)
   203      enclave_basename = result.stdout.decode('utf-8')
   204  
   205      config_proposal = ' '.join([
   206          'sawset proposal create',
   207          '-k {}'.format(priv),
   208          'sawtooth.consensus.algorithm=poet',
   209          'sawtooth.poet.report_public_key_pem="{}"'.format(public_key_pem),
   210          'sawtooth.poet.valid_enclave_measurements={}'.format(
   211              enclave_measurement),
   212          'sawtooth.poet.valid_enclave_basenames={}'.format(enclave_basename),
   213          'sawtooth.poet.target_wait_time={}'.format(target_wait_time),
   214          'sawtooth.poet.initial_wait_time={}'.format(initial_wait_time),
   215          'sawtooth.poet.minimum_wait_time={}'.format(minimum_wait_time),
   216          '-o {}'.format(os.path.join(sawtooth_home, 'data', 'config.batch'))
   217      ])
   218  
   219      poet = 'poet registration create -k {} -o {}'.format(priv, os.path.join(
   220          sawtooth_home, 'data', 'poet.batch'))
   221  
   222      genesis = ' '.join([
   223          'sawadm genesis',
   224          '{} {} {}'.format(
   225              os.path.join(sawtooth_home, 'data', 'config-genesis.batch'),
   226              os.path.join(sawtooth_home, 'data', 'config.batch'),
   227              os.path.join(sawtooth_home, 'data', 'poet.batch'))
   228      ])
   229  
   230      validator_cmd_list = (
   231          [keygen, validator] if num > 0
   232          else [
   233              keygen,
   234              config_genesis,
   235              config_proposal,
   236              poet,
   237              genesis,
   238              validator,
   239          ]
   240      )
   241  
   242      return validator_cmd_list
   243  
   244  
   245  def simple_validator_cmds(*args, **kwargs):
   246      """Used with SetSawtoothHome in integrationtools, to have more control
   247      at the test file level over how the validator is started.
   248  
   249      Returns:
   250          str : The validator startup command.
   251      """
   252      return ['sawtooth-validator -v']
   253  
   254  
   255  def start_validator(num,
   256                      peering_func,
   257                      scheduler_func,
   258                      sawtooth_home,
   259                      validator_cmd_func,
   260                      poet_kwargs):
   261      cmds = validator_cmd_func(num, peering_func, scheduler_func,
   262                                sawtooth_home, **poet_kwargs)
   263      for cmd in cmds[:-1]:
   264          process = start_process(cmd)
   265          process.wait(timeout=60)
   266          if process.returncode != 0:
   267              raise subprocess.CalledProcessError(process.returncode, cmd)
   268  
   269      # only return the validator process (the rest are completed)
   270      return start_process(cmds[-1])
   271  
   272  
   273  # transaction processors
   274  
   275  def processor_cmds(num, processor_func):
   276      '''
   277      Return a list of the commands needed to start
   278      the transaction processors for the num-th node.
   279  
   280      Args:
   281          num (int): the num-th node
   282          processor_func (int -> tuple): a function of one argument n
   283              returning a tuple specifying the processors that should
   284              be started for the n-th node
   285      '''
   286      processors = processor_func(num)
   287  
   288      processor_cmd_list = [
   289          '{p} {v} -C {a}'.format(
   290              p=processor,
   291              v=(processor_verbosity(processor)),
   292              a=connection_address(num))
   293          for processor in processors
   294      ]
   295  
   296      return processor_cmd_list
   297  
   298  
   299  def processor_verbosity(processor_name):
   300      '''
   301      Transactions processors like intkey and xo are very talkative,
   302      so start them with minimal verbosity. Other TPs can be started
   303      with -v or even -vv if so desired.
   304      '''
   305      acceptably_quiet = 'config', 'registry'
   306  
   307      for keyword in acceptably_quiet:
   308          if keyword in processor_name:
   309              return '-v'
   310  
   311      return ''
   312  
   313  
   314  def start_processors(num, processor_func):
   315      return [
   316          start_process(cmd)
   317          for cmd in processor_cmds(num, processor_func)
   318      ]
   319  
   320  
   321  # rest_api
   322  
   323  def rest_api_cmd(num):
   324      return 'sawtooth-rest-api --connect {s} --bind 127.0.0.1:{p}'.format(
   325          s=connection_address(num),
   326          p=(8008 + num)
   327      )
   328  
   329  
   330  def start_rest_api(num):
   331      return start_process(
   332          rest_api_cmd(num))
   333  
   334  
   335  # addresses
   336  def endpoint(num):
   337      return 'tcp://127.0.0.1:{}'.format(8800 + num)
   338  
   339  
   340  def connection_address(num):
   341      return 'tcp://127.0.0.1:{}'.format(4004 + num)
   342  
   343  
   344  def http_address(num):
   345      return 'http://127.0.0.1:{}'.format(8008 + num)
   346  
   347  
   348  def bind_component(num):
   349      return 'tcp://127.0.0.1:{}'.format(4004 + num)
   350  
   351  
   352  def bind_network(num):
   353      return 'tcp://127.0.0.1:{}'.format(8800 + num)
   354  
   355  
   356  def bind_consensus(num):
   357      return 'tcp://127.0.0.1:{}'.format(5050 + num)
   358  
   359  
   360  # execution
   361  
   362  def start_process(cmd):
   363      LOGGER.debug('Running command %s', cmd)
   364      return subprocess.Popen(
   365          shlex.split(cmd))