def evaluate(self) : """ evaluate the request using the enclave service """ encrypted_session_key = self.__encrypt_session_key() # Encrypt the request serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption()) encrypted_request_raw = crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array) encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw) try : self.contract_state.push_state_to_eservice(self.enclave_service) encoded_encrypted_response = self.enclave_service.send_to_contract(encrypted_session_key, encrypted_request) logger.debug("raw response from enclave: %s", encoded_encrypted_response) except Exception as e: logger.warn('contract invocation failed; %s', str(e)) raise InvocationException('contract invocation failed') from e try : decrypted_response = self.__decrypt_response(encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.warn('contract response is invalid; %s', str(e)) raise InvocationException('contract response is invalid') from e return contract_response
def evaluate(self): encrypted_session_key = self.__encrypt_session_key() encrypted_request = self.__encrypt_request() try: encoded_encrypted_response = self.enclave_service.send_to_contract( encrypted_session_key, encrypted_request) assert encoded_encrypted_response logger.debug("raw response from enclave: %s", encoded_encrypted_response) except: logger.exception('contract invocation failed') raise try: decrypted_response = self.__decrypt_response( encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except: logger.exception('contract response is invalid') raise return contract_response
def LocalMain(config): shell = ContractController(config) # if there is a script file, process it; the interactive # shell will start unless there is an explicit exit in the script script_file = config.get("ScriptFile") if script_file: logger.info("Processing script file %s", str(script_file)) if not ContractController.ProcessScript(shell, script_file): ContractResponse.exit_commit_workers() sys.exit(shell.exit_code) shell.cmdloop() print("") ContractResponse.exit_commit_workers() sys.exit(shell.exit_code)
def evaluate(self): encrypted_session_key = self.__encrypt_session_key() # Encrypt the request serialized_byte_array = crypto.string_to_byte_array( self.__serialize_for_encryption()) encrypted_request_raw = crypto.SKENC_EncryptMessage( self.session_key, serialized_byte_array) encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw) try: # Check and conditionally put the encrypted state into the block store if it is non-empty state_hash_b64 = self.contract_state.getStateHash(encoding='b64') if state_hash_b64: block_store_len = self.enclave_service.block_store_head( state_hash_b64) if block_store_len <= 0: # This block wasn't present in the block store of this enclave service - need to send it logger.debug( "Block store did not contain block '%s' - sending it", state_hash_b64) ret = self.enclave_service.block_store_put( state_hash_b64, self.contract_state.encrypted_state) if ret != True: logger.exception("block_store_put failed for key %s", state_hash_b64) raise encoded_encrypted_response = self.enclave_service.send_to_contract( encrypted_session_key, encrypted_request) if encoded_encrypted_response == None: logger.exception( "send_to_contract failed but no exception was thrown") raise logger.debug("raw response from enclave: %s", encoded_encrypted_response) except: logger.exception('contract invocation failed') raise try: decrypted_response = self.__decrypt_response( encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.exception('contract response is invalid: ' + str(e)) raise return contract_response
def ErrorShutdown(): """ Perform a clean shutdown after an error """ try: if block_store is not None: block_store.close() except Exception as e: logger.exception('failed to close block_store') try: enclave_helper.shutdown_enclave() except Exception as e: logger.exception('shutdown failed') # Send termination signal to commit tasks ContractResponse.exit_commit_workers() sys.exit(-1)
def evaluate(self) : """ evaluate the request using the enclave service """ assert self.operation == 'update' # Encrypt the request serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption()) encrypted_request = bytes(crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array)) encrypted_key = bytes(self.enclave_keys.encrypt(self.session_key)) try : self.contract_state.push_state_to_eservice(self.enclave_service) encrypted_response = self.enclave_service.send_to_contract(encrypted_key, encrypted_request) except Exception as e: logger.warn('contract invocation failed; %s', str(e)) raise InvocationException('contract invocation failed') from e try : decrypted_response = crypto.SKENC_DecryptMessage(self.session_key, encrypted_response) except Exception as e: logger.exception('failed to decrypt response; %s', encrypted_response) raise InvocationException('contract response cannot be decrypted') try : response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) except Exception as e: logger.exception('contract response is invalid; %s', str(e)) raise InvocationException('failed to parse contract response') from e # if response_parsed['Status'] is False : # raise InvocationException(response_parsed['InvocationResponse']) try : if response_parsed['Status'] and response_parsed['StateChanged'] : contract_response = UpdateStateResponse(self, response_parsed) else : contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.exception('contract response is invalid; %s', str(e)) raise InvocationException('contract response is invalid') from e return contract_response
def RunService(): @defer.inlineCallbacks def shutdown_twisted(): logger.info("Stopping Twisted") yield reactor.callFromThread(reactor.stop) reactor.addSystemEventTrigger('before', 'shutdown', shutdown_twisted) atexit.register(lambda: ContractResponse.exit_commit_workers()) try: reactor.run() except ReactorNotRunning: logger.warn('shutdown') except: logger.warn('shutdown') sys.exit(0)
def UpdateTheContract(config, enclaves, contract, contract_invoker_keys): commit_dependenices = [] last_response_committed = None ledger_config = config.get('Sawtooth') contract_invoker_id = contract_invoker_keys.identity # Decide if the contract use a fixed enclave or a randomized one for each update. if use_eservice and config['Service']['Randomize_Eservice']: enclave_to_use = 'random' else: enclave_to_use = enclaves[0] start_time = time.time() total_tests = 0 total_failed = 0 test_list = [] test_file = config['expressions'] with open(test_file, "r") as efile: if test_file.endswith('.exp'): fieldnames = ['expression', 'expected', 'invert'] reader = csv.DictReader(filter(lambda row: row[0] != '#', efile), fieldnames, quoting=csv.QUOTE_NONE, escapechar='\\', skipinitialspace=True) test_list = list(reader) elif test_file.endswith('.json'): # there is currently no support to set these values outside of the # configuration file and that is not going to change soon test_max_level = config.get('Test', {}).get('MaxLevel', 0) reader = json.load(efile) for test in reader: if test.get('test-level', 0) > test_max_level: continue method = test['MethodName'] pparms = test.get('PositionalParameters', []) kparms = test.get('KeywordParameters', {}) test['expression'] = contract_helper.invocation_request( method, *pparms, **kparms) test_list.append(test) else: logger.error('unknown test file format; %s', test_file) ErrorShutdown() for test in test_list: expression = test['expression'] if test.get('description'): logger.log( plogger.HIGHLIGHT, "TEST[{0}] : {1}".format(total_tests, test['description'].format(**test))) try: total_tests += 1 update_request = contract.create_update_request( contract_invoker_keys, expression, enclave_to_use) update_response = update_request.evaluate() raw_result = str(update_response.invocation_response) result = raw_result[:15] if len(raw_result) >= 15: result += "..." unpacked_response = contract_helper.invocation_response(raw_result) if update_response.status is False: logger.info('failed: {0} --> {1}'.format(expression, result)) if test.get('invert') is None or test.get('invert') != 'fail': total_failed += 1 logger.warn('inverted test failed: %s instead of %s', result, test['expected']) elif test.get('expected') and not re.match( test.get('expected'), raw_result): total_failed += 1 logger.warn('test failed: %s instead of %s', result, test['expected']) continue logger.info('{0} --> {1}'.format(expression, result)) if test.get('expected') and not re.match(test.get('expected'), raw_result): total_failed += 1 logger.warn('test failed: %s instead of %s', result, test['expected']) except Exception as e: logger.error('enclave failed to evaluate expression; %s', str(e)) ErrorShutdown() # if this operation did not change state then there is nothing to commit if update_response.state_changed: # asynchronously submit the commit task: (a commit task replicates # change-set and submits the corresponding transaction) try: logger.info( "asynchronously replicate change set and submit transaction in the background" ) update_response.commit_asynchronously(ledger_config) last_response_committed = update_response except Exception as e: logger.error('failed to submit commit: %s', str(e)) ErrorShutdown() logger.debug('update state') contract.set_state(update_response.raw_state) if total_failed > 0: logger.warn('failed %d of %d tests', total_failed, total_tests) ErrorShutdown() # wait for the last commit to finish. if last_response_committed is not None: try: txn_id = last_response_committed.wait_for_commit() if use_ledger and txn_id is None: logger.error("Did not receive txn id for the final commit") ErrorShutdown() except Exception as e: logger.error("Error while waiting for final commit: %s", str(e)) ErrorShutdown() logger.info('completed in %s', time.time() - start_time) logger.info('passed %d of %d tests', total_tests - total_failed, total_tests) #shutdown commit workers ContractResponse.exit_commit_workers()
def UpdateTheContract(config, contract, enclaves, contract_invoker_keys) : ledger_config = config.get('Sawtooth') contract_invoker_id = contract_invoker_keys.identity last_response_committed = None # Decide if the contract use a fixed enclave or a randomized one for each update. if use_eservice and config['Service']['Randomize_Eservice']: enclave_to_use = 'random' else: enclave_to_use = enclaves[0] start_time = time.time() for x in range(config['iterations']) : if tamper_block_order : # in this evaluation we tamper with the state, so it should fail with a bad authenticator error logger.info('the following evaluation should fail with a bad authenticator error') temp_saved_state_hash = contract.contract_state.get_state_hash(encoding='b64') test_state.TamperWithStateBlockOrder(contract.contract_state) try : expression = contract_helper.invocation_request('inc_value') update_request = contract.create_update_request(contract_invoker_keys, expression, enclave_to_use) update_response = update_request.evaluate() if update_response.status is False : logger.info('failed: {0} --> {1}'.format(expression, update_response.invocation_response)) continue logger.info('{0} --> {1}'.format(expression, update_response.invocation_response)) except Exception as e: logger.error('enclave failed to evaluate expression; %s', str(e)) ErrorShutdown() # if this operation did not change state then there is nothing to commit if update_response.state_changed : # asynchronously submit the commit task: (a commit task replicates change-set and submits the corresponding transaction) try: update_response.commit_asynchronously(ledger_config) last_response_committed = update_response except Exception as e: logger.error('failed to submit commit: %s', str(e)) ErrorShutdown() logger.debug('update state') contract.set_state(update_response.raw_state) # wait for the last commit to finish. if last_response_committed is not None: try: txn_id = last_response_committed.wait_for_commit() if use_ledger and txn_id is None: logger.error("Did not receive txn id for the last response committed") ErrorShutdown() except Exception as e: logger.error("Error while waiting for the last response committed: %s", str(e)) ErrorShutdown() logger.info("All commits completed") logger.info('completed in %s', time.time() - start_time) # shutdown commit workers ContractResponse.exit_commit_workers()