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))