def gogogox(todo, amount, account_no): print('gogogo') context = create_context('secp256k1') # conn = sqlite3.connect('bank.db') # cursor = conn.execute("SELECT private_key from key") # for row in cursor: # privatek=row[0] # conn.close() # private_key = Secp256k1PrivateKey.from_hex(privatek) conn = sqlite3.connect('bank.db') cursor = conn.execute( "SELECT code from BANK WHERE account_no='{}'".format(account_no)) for row in cursor: code = row[0] conn.close() private_key = context.new_random_private_key() signer = CryptoFactory(context).new_signer(private_key) input = hash("bankregister".encode('utf-8'))[0:6] + hash( "overclockedbrain".encode('utf-8'))[0:58] + hash( code.encode('utf-8'))[0:6] payload = "{},{},{}".format(todo, amount, code) payload_bytes = cbor.dumps(payload) txn_header_bytes = TransactionHeader( family_name='bankregister', family_version='1.0', inputs=[input], outputs=[input], signer_public_key=signer.get_public_key().as_hex(), batcher_public_key=signer.get_public_key().as_hex(), dependencies=[], payload_sha512=sha512(payload_bytes).hexdigest()).SerializeToString() signature = signer.sign(txn_header_bytes) txn = Transaction(header=txn_header_bytes, header_signature=signature, payload=payload_bytes) txns = [txn] batch_header_bytes = BatchHeader( signer_public_key=signer.get_public_key().as_hex(), transaction_ids=[txn.header_signature for txn in txns], ).SerializeToString() signature = signer.sign(batch_header_bytes) batch = Batch(header=batch_header_bytes, header_signature=signature, transactions=txns) batch_list_bytes = BatchList(batches=[batch]).SerializeToString() return batch_list_bytes
class XoClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException('Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError: try: private_key = Secp256k1PrivateKey.from_wif(private_key_str) except ParseError as e: raise XoException('Unable to load private key: {}'.format( str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn(name, "create", wait=wait, auth_user=auth_user, auth_password=auth_password) def delete(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn(name, "delete", wait=wait, auth_user=auth_user, auth_password=auth_password) def take(self, name, space, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn(name, "take", space, wait=wait, auth_user=auth_user, auth_password=auth_password) def list(self, auth_user=None, auth_password=None): xo_prefix = self._get_prefix() result = self._send_request("state?address={}".format(xo_prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def show(self, name, auth_user=None, auth_password=None): address = self._get_address(name) result = self._send_request("state/{}".format(address), name=name, auth_user=auth_user, auth_password=auth_password) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise XoException(err) def _get_prefix(self): return _sha512('xo'.encode('utf-8'))[0:6] def _get_address(self, name): xo_prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[0:64] return xo_prefix + game_address def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such game: {}".format(name)) elif not result.ok: raise XoException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_xo_txn(self, name, action, space="", wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string payload = ",".join([name, action, str(space)]).encode() # Construct the address address = self._get_address(name) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="xo", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status(batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class Client: def __init__(self, url, keyfile=None): self.url = url if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise CrdtClientException( 'Failed to read private key: {}'.format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise CrdtClientException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def add_user(self, imsi, public_key, home_network, wait=None): action = ActionTypes.ADD_USER.value action_payload = cbor.dumps({ 'imsi': imsi, 'pub_key': public_key, 'home_net': home_network }) address = make_user_address(imsi) return self._send_transaction(action, action_payload, [address], wait=wait) def list(self): result = self._send_request("state?address={}".format( self._get_prefix())) try: encoded_entries = yaml.safe_load(result)["data"] return [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] except BaseException: return None def show_user(self, imsi): address = make_user_address(imsi) result = self._send_request( "state/{}".format(address), name=imsi, ) try: print("Got to the load data part!") return cbor.loads(base64.b64decode(yaml.safe_load(result)["data"])) except BaseException: return None def _get_status(self, batch_id, wait): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), ) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise CrdtClientException(err) @staticmethod def _get_prefix(): return _sha512('billing-crdt'.encode('utf-8'))[0:6] def _get_address(self, name): prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[64:] return prefix + game_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise CrdtClientException("No such key: {}".format(name)) elif not result.ok: raise CrdtClientException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise CrdtClientException( 'Failed to connect to REST API: {}'.format(err)) except BaseException as err: raise CrdtClientException(err) return result.text def _send_transaction(self, action, action_payload, addresses, wait=None): payload = cbor.dumps({'action': action, 'payload': action_payload}) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="billing-crdt", family_version="0.0.1", inputs=addresses, outputs=addresses, dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), ) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class HealthClient: """ construct and send health transaction. """ def __init__(self, base_url, work_path, keyfile=None): self._base_url = base_url self._work_path = work_path if keyfile is None: self._signer = None return try: with open(keyfile) as file_ptr: private_key_str = file_ptr.read().strip() except OSError as err: raise HealthException('Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as parser_error: raise HealthException('Unable to load private key: {}'.format( str(parser_error))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def code_analysis(self, github_url, github_user, commit_date, client_key): """ send github url to code analysis to generate new health Args: github_url (str): commit url github_user (str): github user id """ #get time txn_date = _get_date() #get host ip adress process_flag = 1 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) my_ip = s.getsockname()[0] s.close() if my_ip == client_key[6:].split(':')[0]: process_flag = 0 #if process is zero then check latest health #get latest health if process_flag == 0: result = self._send_request("transactions") transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] for entry in encoded_entries: #try to pull the specific transaction, if the format is not right #the transaction corresponds to the consesus family try: transaction_type = base64.b64decode( entry["payload"]).decode().split(',')[0] if transaction_type == "health": transactions[ entry["header_signature"]] = base64.b64decode( entry["payload"]) #assuming we got all transactions in order break except: pass except BaseException: return None for entry in transactions: previous_commit = transactions[entry].decode().split(',')[4] if previous_commit == github_url: #if the commit url of the previous health is equal to the new commit url #then ignore the transaction process_flag == 1 break #we got a new commit, calculate health if process_flag == 0: work_path = os.path.dirname( os.path.dirname( os.path.dirname(os.path.dirname( os.path.realpath(__file__))))) sawtooth_home = work_path + "/results" #get repo path conf_file = work_path + '/etc/.repo' try: with open(conf_file, 'r') as path: repo_path = path.read() path.close() except IOError as error: raise HealthException( "Unable to open configuration file {}".format(error)) repo_path = repo_path.replace( '\n', '' ) + '/CodeAnalysis/SourceMeter_Interface/src/sourceMeterWrapper.py' print('CALLING ANLSYIS WITH:', ['python2.7', repo_path, github_url, sawtooth_home]) subprocess.check_output( ['python2.7', repo_path, github_url, sawtooth_home]) for filename in os.listdir(sawtooth_home): csv_path = sawtooth_home + '/' + filename break try: suse_config = _get_config_file() suse_config = suse_config["code_smells"] health = calculate_health(suse_config=suse_config, csv_path=csv_path) if health > 0: do_suse(url=self._base_url, health=health, github_id=github_user) response = self._send_health_txn(txn_type='health', txn_id=github_user, data=str(health), state='processed', url=github_url, client_key=client_key, txn_date=txn_date) return response except Exception as error: return error def commit(self, commit_url, github_id, commit_date, client_key): """ Send commit url to code analysis Args: commit_url (str), git url to do a pull github_id (str), user github ID """ response = self._send_health_txn(txn_type='commit', txn_id=github_id, data=commit_url, state='new', url=self._base_url, client_key=client_key, txn_date=commit_date) return response def list(self, txn_type=None, limit=None): """ list all transactions. Args: txn_type (str), transaction type limit (int), number of transactions to pull """ #pull all transactions of health family if limit is None: result = self._send_request("transactions") else: result = self._send_request("transactions?limit={}".format(limit)) transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] if txn_type is None: for entry in encoded_entries: transactions[entry["header_signature"]] = base64.b64decode( entry["payload"]) else: for entry in encoded_entries: #try to pull the specific transaction, if the format is not right #the transaction corresponds to the consesus family try: transaction_type = base64.b64decode( entry["payload"]).decode().split(',')[0] if transaction_type == txn_type: transactions[ entry["header_signature"]] = base64.b64decode( entry["payload"]) except: pass return transactions except BaseException: return None def _get_prefix(self): """ get health family address prefix """ return _sha512('health'.encode('utf-8'))[0:6] def _get_address(self, txn_id): """ get transaction address Args: id (str): trasaction id """ health_prefix = self._get_prefix() health_address = _sha512(txn_id.encode('utf-8'))[0:64] return health_prefix + health_address def _send_request(self, suffix, data=None, content_type=None, auth_user=None, auth_password=None): """ send request to health processor` """ if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise HealthException("No such transaction") elif not result.ok: raise HealthException("Error {}:{}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise HealthException('Failed to connect to {}:{}'.format( url, str(err))) except BaseException as err: raise HealthException(err) return result.text def _send_health_txn(self, txn_type=None, txn_id=None, data=None, state=None, url=None, client_key=None, txn_date=None): """ serialize payload and create header transaction Args: type (str): type of transaction id (str): asset id, will depend on type of transaction data (object): transaction data state (str): all transactions must have a state """ #serialization is just a delimited utf-8 encoded strings payload = ",".join( [txn_type, txn_id, data, state, url, client_key, str(txn_date)]).encode() #pprint("payload: {}".format(payload)) #construct the address address = self._get_address(txn_id) #construct header key_path = os.path.expanduser('~') key_path = key_path + "/.sawtooth/keys" print(key_path) print("hash:" + self._signer.get_public_key().as_hex()) for pub_file in os.listdir(key_path): if "root.pub" in pub_file: print("File:" + pub_file) line = open(key_path + '/' + pub_file, 'r') key = line.read().strip() line.close() print("user key: " + key) break header = TransactionHeader( signer_public_key=str(key), family_name="health", family_version="0.1", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) #create transaction transaction = Transaction(header=header, payload=payload, header_signature=signature) #create batch list, suserum policy: one transaction per batch batch_list = self._create_batch_list([transaction]) return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') def _create_batch_list(self, transactions): """ Create the list of batches that the client will send to the REST API Args: transactions (transaction): transaction(s) included in the batch Returns: BatchList: a list of batches to send to the REST API """ transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class CookieJarClient(object): '''Client Cookie Jar class Supports "bake", "eat", and "count" functions. ''' def __init__(self, base_url, key_file=None): '''Initialize the client class. This is mainly getting the key pair and computing the address. ''' self._base_url = base_url if key_file is None: self._signer = None return try: with open(key_file) as key_fd: private_key_str = key_fd.read().strip() except OSError as err: raise Exception('Failed to read private key {}: {}'.format( key_file, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as err: raise Exception( \ 'Failed to load private key: {}'.format(str(err))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self._public_key = self._signer.get_public_key().as_hex() # Address is 6-char TF prefix + hash of "mycookiejar"'s public key self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(self._public_key.encode('utf-8'))[0:64] # For each CLI command, add a method to: # 1. Do any additional handling, if required # 2. Create a transaction and a batch # 2. Send to REST API def bake(self, amount): '''Bake amount cookies for the cookie jar.''' return self._wrap_and_send("bake", amount, wait=10) def eat(self, amount): '''Eat amount cookies from the cookie jar.''' try: ret_amount = self._wrap_and_send("eat", amount, wait=10) except Exception: raise Exception('Encountered an error during eat') return ret_amount def count(self): '''Count the number of cookies in the cookie jar.''' result = self._send_to_rest_api("state/{}".format(self._address)) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _send_to_rest_api(self, suffix, data=None, content_type=None): '''Send a REST command to the Validator via the REST API. Called by count() & _wrap_and_send(). The latter caller is made on the behalf of bake() & eat(). ''' url = "{}/{}".format(self._base_url, suffix) print("URL to send to REST API is {}".format(url)) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def _wait_for_status(self, batch_id, wait, result): '''Wait until transaction status is not PENDING (COMMITTED or error). 'wait' is time to wait for status, in seconds. ''' if wait and wait > 0: waited = 0 start_time = time.time() while waited < wait: result = self._send_to_rest_api( "batch_statuses?id={}&wait={}".format(batch_id, wait)) status = yaml.safe_load(result)['data'][0]['status'] waited = time.time() - start_time if status != 'PENDING': return result return "Transaction timed out after waiting {} seconds." \ .format(wait) else: return result def _wrap_and_send(self, action, amount, wait=None): '''Create a transaction, then wrap it in a batch. Even single transactions must be wrapped into a batch. Called by bake() and eat(). ''' # Generate a CSV UTF-8 encoded string as the payload. raw_payload = ",".join([action, str(amount)]) payload = raw_payload.encode() # Convert Unicode to bytes # Construct the address where we'll store our state. # We just have one input and output address (the same one). input_and_output_address_list = [self._address] # Create a TransactionHeader. header = TransactionHeader( signer_public_key=self._public_key, family_name=FAMILY_NAME, family_version="1.0", inputs=input_and_output_address_list, outputs=input_and_output_address_list, dependencies=[], payload_sha512=_hash(payload), batcher_public_key=self._public_key, nonce=random.random().hex().encode()).SerializeToString() # Create a Transaction from the header and payload above. transaction = Transaction(header=header, payload=payload, header_signature=self._signer.sign(header)) transaction_list = [transaction] # Create a BatchHeader from transaction_list above. header = BatchHeader( signer_public_key=self._public_key, transaction_ids=[txn.header_signature for txn in transaction_list]).SerializeToString() # Create Batch using the BatchHeader and transaction_list above. batch = Batch(header=header, transactions=transaction_list, header_signature=self._signer.sign(header)) # Create a Batch List from Batch above batch_list = BatchList(batches=[batch]) batch_id = batch_list.batches[0].header_signature # Send batch_list to the REST API result = self._send_to_rest_api("batches", batch_list.SerializeToString(), 'application/octet-stream') # Wait until transaction status is COMMITTED, error, or timed out return self._wait_for_status(batch_id, wait, result)
class SuseClient: """ construct and send health transaction. """ def __init__(self, base_url, work_path, keyfile=None): self._base_url = base_url self._work_path = work_path if keyfile is None: self._signer = None return try: with open(keyfile) as file_ptr: private_key_str = file_ptr.read().strip() except OSError as err: raise SuseException('Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as parser_error: raise SuseException('Unable to load private key: {}'.format( str(parser_error))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def suse(self, new_health, github_id): """ Send commit url to code analysis Args: commit_url (str), git url to do a pull github_id (str), user github ID """ txn_date = _get_date() #get latest health result = self._send_request("transactions") transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] for entry in encoded_entries: #try to pull the specific transaction, if the format is not right #the transaction corresponds to the consesus family try: transaction_type = base64.b64decode( entry["payload"]).decode().split(',')[0] if transaction_type == "health": transactions[ entry["header_signature"]] = base64.b64decode( entry["payload"]) #assuming we got all transactions in order break except: pass #return transactions except BaseException: return None for entry in transactions: previous_heatlh = transactions[entry].decode().split(',')[2] break suse = float(new_health) - float(previous_heatlh) #the amount of suse is related to the amount of health, with a realtion of 1-to-1 #we also provide negative suses response = self._send_suse_txn(txn_type='suse', txn_id=github_id, data=str(suse), state='new', txn_date=txn_date) return response def list(self, txn_type=None, limit=None): """ list all transactions. Args: txn_type (str), transaction type limit (int), number of transactions to pull """ #pull all transactions of health family if limit is None: result = self._send_request("transactions") else: result = self._send_request("transactions?limit={}".format(limit)) transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] if txn_type is None: for entry in encoded_entries: transactions[entry["header_signature"]] = base64.b64decode( entry["payload"]) else: for entry in encoded_entries: #try to pull the specific transaction, if the format is not right #the transaction corresponds to the consesus family try: transaction_type = base64.b64decode( entry["payload"]).decode().split(',')[0] if transaction_type == txn_type: transactions[ entry["header_signature"]] = base64.b64decode( entry["payload"]) except: pass return transactions except BaseException: return None def _get_prefix(self): """ get suse family address prefix """ return _sha512('suse'.encode('utf-8'))[0:6] def _get_address(self, txn_id): """ get transaction address Args: id (str): trasaction id """ suse_prefix = self._get_prefix() suse_address = _sha512(txn_id.encode('utf-8'))[0:64] return suse_prefix + suse_address def _send_request(self, suffix, data=None, content_type=None, auth_user=None, auth_password=None): """ send request to code smell processor` """ if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise SuseException("No such transaction") elif not result.ok: raise SuseException("Error {}:{}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise SuseException('Failed to connect to {}:{}'.format( url, str(err))) except BaseException as err: raise SuseException(err) return result.text def _send_suse_txn(self, txn_type=None, txn_id=None, data=None, state=None, txn_date=None): """ serialize payload and create header transaction Args: type (str): type of transaction id (str): asset id, will depend on type of transaction data (object): transaction data state (str): all transactions must have a state """ #serialization is just a delimited utf-8 encoded strings payload = ",".join([txn_type, txn_id, data, state, str(txn_date)]).encode() #pprint("payload: {}".format(payload)) #construct the address address = self._get_address(txn_id) #construct header header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="suse", family_version="0.1", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) #create transaction transaction = Transaction(header=header, payload=payload, header_signature=signature) #create batch list, suserum policy: one transaction per batch batch_list = self._create_batch_list([transaction]) return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') def _create_batch_list(self, transactions): """ Create the list of batches that the client will send to the REST API Args: transactions (transaction): transaction(s) included in the batch Returns: BatchList: a list of batches to send to the REST API """ transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class Client(): def __init__(self, base_url, private_key): self._base_url = base_url private_key = Secp256k1PrivateKey.from_hex(private_key) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self._public_key = self._signer.get_public_key().as_hex() self._address = generate_address(self._public_key) def deposit(self, amount): return self.construct_payload_and_send("deposit", amount, 10) def withdraw(self, amount): return self.construct_payload_and_send("withdraw", amount, 10) def zero_balance(self, amount=0): return self.construct_payload_and_send("zero_balance", amount, 10) def check_balance(self): result = self.talk_to_validator("state/{}".format(self._address)) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def talk_to_validator(self, endpoint, payload=None, content_type=None): url = "{}/{}".format(self._base_url, endpoint) print("END POINT: {}".format(url)) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if payload is not None: result = requests.post(url, headers=headers, data=payload) else: result = requests.get(url, headers=headers) if not result.ok: raise Exception("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise Exception(err) return result.text def _wait_for_status(self, batch_id, wait, result): '''Wait until transaction status is not PENDING (COMMITTED or error). 'wait' is time to wait for status, in seconds. ''' if wait and wait > 0: waited = 0 start_time = time.time() while waited < wait: result = self.talk_to_validator("batch_statuses?id={}&wait={}" .format(batch_id, wait)) status = yaml.safe_load(result)['data'][0]['status'] waited = time.time() - start_time if status != 'PENDING': return result return "Transaction timed out after waiting {} seconds." \ .format(wait) else: return result def construct_payload_and_send(self, action, amount, wait_time=None): raw_payload = ",".join([action, str(amount)]) input_and_output_address_list = [self._address] print(self._address) header = TransactionHeader( signer_public_key=self._public_key, family_name=constants.FAMILY_NAME, family_version="1.0", inputs=input_and_output_address_list, outputs=input_and_output_address_list, dependencies=[], payload_sha512=generate_hash(raw_payload), batcher_public_key=self._public_key, nonce=random.random().hex().encode() ).SerializeToString() transaction = Transaction( header=header, payload=raw_payload.encode(), header_signature=self._signer.sign(header) ) transaction_list = [transaction] header = BatchHeader( signer_public_key=self._public_key, transaction_ids=[txn.header_signature for txn in transaction_list] ).SerializeToString() batch = Batch( header=header, transactions=transaction_list, header_signature=self._signer.sign(header)) batch_list = BatchList(batches=[batch]) batch_id = batch_list.batches[0].header_signature print(batch_id) result = self.talk_to_validator("batches", batch_list.SerializeToString(), 'application/octet-stream') # Wait until transaction status is COMMITTED, error, or timed out return self._wait_for_status(batch_id, wait_time, result)
class SawtoothHelper: def __init__(self, base_url, validator_url=None, pk=None, context=None): self.base_url = base_url self.validator_url = validator_url if validator_url else f"{base_url}:4004" self.context = context if context else create_context("secp256k1") self.pk = pk if pk else self.context.new_random_private_key() self.signer = CryptoFactory(self.context).new_signer(self.pk) self.family_name = "DECODE_PETITION" self.family_version = "1.0" @property def private_key(self): return self.pk.secp256k1_private_key.serialize() def set_url(self, url): self.base_url = url def create_transaction(self, payload, family_name, family_version, address): payload_bytes = cbor2.dumps(payload) txn_header = TransactionHeader( batcher_public_key=self.signer.get_public_key().as_hex(), inputs=[address], outputs=[address], dependencies=[], family_name=family_name, family_version=family_version, nonce=hex(randint(0, 2**64)), payload_sha512=sha512(payload_bytes).hexdigest(), signer_public_key=self.signer.get_public_key().as_hex(), ).SerializeToString() txn = Transaction( header=txn_header, header_signature=self.signer.sign(txn_header), payload=payload_bytes, ) return [txn] def create_batch(self, transactions): batch_header = BatchHeader( signer_public_key=self.signer.get_public_key().as_hex(), transaction_ids=[txn.header_signature for txn in transactions], ).SerializeToString() batch = Batch( header=batch_header, header_signature=self.signer.sign(batch_header), transactions=transactions, ) return BatchList(batches=[batch]).SerializeToString() def get_state(self, payload, address): petition_address = self.generate_address(self.family_name, payload) r = requests.get(f"{address}/state?address={petition_address}") return r.json() def get_batches(self, payload, address): state = self.get_state(payload, address) r = requests.get(f"{address}/blocks/{state['head']}") batches = r.json()["data"]["batches"] return batches def _post(self, payload, family_name, family_version, address): transactions = self.create_transaction(payload, family_name, family_version, address) batches = self.create_batch(transactions) response = requests.post( f"{self.base_url}", data=batches, headers={"Content-Type": "application/octet-stream"}, ) return response.json() def post(self, payload): address = self.generate_address(self.family_name, payload) return self._post(payload, self.family_name, self.family_version, address) @staticmethod def generate_address(family_name, payload): namespace = sha512(family_name.encode("utf-8")).hexdigest()[0:6] petition = sha512( payload["petition_id"].encode("utf-8")).hexdigest()[-64:] return namespace + petition
class SupplierBatch: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise SupplierException( 'Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise SupplierException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self,supplier_id,short_id,supplier_name,passwd,supplier_url, auth_user=None, auth_password=None): return self.create_supplier_transaction(supplier_id,short_id,supplier_name,passwd,supplier_url, "create", auth_user=auth_user, auth_password=auth_password) def add_part(self,supplier_id,part_id): return self.create_supplier_transaction(supplier_id,"","","","","AddPart",part_id) def list_supplier(self, auth_user=None, auth_password=None): supplier_prefix = self._get_prefix() result = self._send_request( "state?address={}".format(supplier_prefix), auth_user=auth_user, auth_password=auth_password ) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def retrieve_supplier(self, supplier_id, auth_user=None, auth_password=None): address = self._get_address(supplier_id) result = self._send_request("state/{}".format(address), supplier_id=supplier_id, auth_user=auth_user, auth_password=auth_password) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise SupplierException(err) def _get_prefix(self): return _sha512('supplier'.encode('utf-8'))[0:6] def _get_address(self, supplier_id): supplier_prefix = self._get_prefix() address = _sha512(supplier_id.encode('utf-8'))[0:64] return supplier_prefix + address def _send_request( self, suffix, data=None, content_type=None, supplier_id=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise SupplierException("No such supplier: {}".format(supplier_id)) elif not result.ok: raise SupplierException("Error {}: {}".format( result.status_code, result.reason)) except BaseException as err: raise SupplierException(err) return result.text def create_supplier_transaction(self, supplier_id,short_id="",supplier_name="",passwd="",supplier_url="", action="",part_id="", auth_user=None, auth_password=None): payload = ",".join([supplier_id,str(short_id),str(supplier_name),str(passwd),str(supplier_url), action,str(part_id)]).encode() # Construct the address address = self._get_address(supplier_id) header = TransactionHeader( signer_pubkey=self._signer.get_public_key().as_hex(), family_name="supplier", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_encoding="csv-utf8", payload_sha512=_sha512(payload), batcher_pubkey=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode() ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature ) return BatchList(batches=[batch])
class FakeClient(object): '''Client fake product identification class. This supports add, buy, sign, show, rm, verify products functions. ''' def __init__(self, baseUrl, keyFile=None): '''Initialize the client class. This is mainly getting the key pair and computing the address. ''' self._baseUrl = baseUrl if keyFile is None: self._signer = None return try: with open(keyFile) as fd: privateKeyStr = fd.read().strip() except OSError as err: raise Exception('Failed to read private key {}: {}'.format( keyFile, str(err))) try: privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr) except ParseError as err: raise Exception('Failed to load private key: {}'.format(str(err))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(privateKey) self._publicKey = self._signer.get_public_key().as_hex() self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(self._publicKey.encode('utf-8'))[0:64] def add(self, product_id, product_name): return self._wrap_and_send("add", product_id, product_name) def sign(self, product_id, product_name): sig = self._signer.sign("{}:{}".format(product_id, product_name).encode('utf-8')) return self._wrap_and_send("sign", product_id, product_name, sig) def fake_sign(self, product_id, product_name): sig = self._signer.sign("{}:{}".format(product_id, product_name).encode('utf-8')) fake_sig = ''.join( ["{}".format(randint(0, 9)) for num in range(0, len(sig))]) return self._wrap_and_send("sign", product_id, product_name, fake_sig) def verify(self, product_id, product_name, signature): msg = bytes("{}:{}".format(product_id, product_name), 'utf-8') return Secp256k1Context().verify(signature, msg, self._signer.get_public_key()) def remove(self, product_id, product_name, clientKey): try: with open(clientKey) as fd: publicKeyFromStr = fd.read().strip() retValue = self._wrap_and_send("rm", product_id, product_name, clientKey) except Exception: raise Exception('Encountered an error during remove command') return retValue def transfer(self, product_id, product_name, clientKey): try: with open(clientKey) as fd: publicKeyStr = fd.read().strip() retValue = self._wrap_and_send("buy", product_id, product_name, publicKeyStr) except OSError as err: raise Exception('Failed to read public key {}: {}'.format( clientToKey, str(err))) except Exception as err: raise Exception('Encountered an error during transfer', err) return retValue def show(self): result = self._send_to_restapi("state/{}".format(self._address)) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _send_to_restapi(self, suffix, data=None, contentType=None): '''Send a REST command to the Validator via the REST API.''' if self._baseUrl.startswith("http://"): url = "{}/{}".format(self._baseUrl, suffix) else: url = "http://{}/{}".format(self._baseUrl, suffix) headers = {} if contentType is not None: headers['Content-Type'] = contentType try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def _wrap_and_send(self, action, *values): '''Create a transaction, then wrap it in a batch. Even single transactions must be wrapped into a batch. ''' # Generate a csv utf-8 encoded string as payload rawPayload = action for val in values: rawPayload = ",".join([rawPayload, str(val)]) payload = rawPayload.encode() # Construct the address where we'll store our state address = self._address inputAddressList = [address] outputAddressList = [address] if "buy" == action: toAddress = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(values[1].encode('utf-8'))[0:64] inputAddressList.append(toAddress) outputAddressList.append(toAddress) # Create a TransactionHeader header = TransactionHeader( signer_public_key=self._publicKey, family_name=FAMILY_NAME, family_version="1.0", inputs=inputAddressList, outputs=outputAddressList, dependencies=[], payload_sha512=_hash(payload), batcher_public_key=self._publicKey, nonce=random.random().hex().encode()).SerializeToString() # Create a Transaction from the header and payload above transaction = Transaction(header=header, payload=payload, header_signature=self._signer.sign(header)) transactionList = [transaction] # Create a BatchHeader from transactionList above header = BatchHeader( signer_public_key=self._publicKey, transaction_ids=[txn.header_signature for txn in transactionList]).SerializeToString() #Create Batch using the BatchHeader and transactionList above batch = Batch(header=header, transactions=transactionList, header_signature=self._signer.sign(header)) #Create a Batch List from Batch above batch_list = BatchList(batches=[batch]) # Send batch_list to rest-api return self._send_to_restapi("batches", batch_list.SerializeToString(), 'application/octet-stream')
class BattleshipClient: def __init__(self, base_url, keyfile, wait=None): """ Member variables: _base_url _private_key _public_key _transaction_family _family_version _wait """ self._base_url = base_url try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise IOError("Failed to read keys: {}.".format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise BattleshipException('Unable to load private key: {}'.format( str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) self._transaction_family = "battleship" self._family_version = "1.0" self._wait = wait def _send_battleship_txn(self, update): """The client needs to have the same defaults as the Transaction subclass before it is signed inside sendtxn """ if 'Name' not in update: raise BattleshipException('Game name required') if 'Action' not in update: update['Action'] = None if 'Ships' not in update: update['Ships'] = None if update['Action'] == 'JOIN': if 'Board' not in update: update['Board'] = None if update['Action'] == 'FIRE': if 'Column' not in update: update['Column'] = None if 'Row' not in update: update['Row'] = None payload = json.dumps(update).encode() address = self._get_address(update['Name']) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name=self._transaction_family, family_version=self._family_version, inputs=[address], outputs=[address], dependencies=[], payload_sha512=self._sha512(payload), batcher_public_key=self.signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if self._wait and self._wait > 0: wait_time = 0 start_time = time.time() response = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') while wait_time < self._wait: status = self._get_status(batch_id, self._wait - int(wait_time)) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') def create(self, name, ships): """ Create battleship game """ update = {'Action': 'CREATE', 'Name': name, 'Ships': ships} return self._send_battleship_txn(update) def join(self, name, board): """ User joins battleship game """ update = {'Action': 'JOIN', 'Name': name, 'Board': board} return self._send_battleship_txn(update) def fire(self, name, column, row, reveal_space, reveal_nonce): """ Fire at (column, row) """ update = {'Action': 'FIRE', 'Name': name, 'Column': column, 'Row': row} if reveal_space is not None: update['RevealSpace'] = reveal_space if reveal_nonce is not None: update['RevealNonce'] = reveal_nonce return self._send_battleship_txn(update) def list_games(self, auth_user=None, auth_password=None): prefix = self._get_prefix() result = self._send_request("state?address={}".format(prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] ret = {} for entry in encoded_entries: d = json.loads(b64decode(entry["data"]).decode()) for k, v in d.items(): ret[k] = v return ret except BaseException: return None def _sha512(self, data): return hashlib.sha512(data).hexdigest() def _get_prefix(self): return self._sha512(self._transaction_family.encode('utf-8'))[0:6] def _get_address(self, name): prefix = self._get_prefix() game_address = self._sha512(name.encode('utf-8'))[0:64] return prefix + game_address def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch]) def _get_status(self, batch_id, wait): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait)) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise BattleshipException(err) def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise BattleshipException("No such game: {}".format(name)) elif not result.ok: raise BattleshipException("Error {}: {}".format( result.status_code, result.reason)) except BaseException as err: raise BattleshipException(err) return result.text
class Client: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise Exception('Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise Exception('Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def _send_txn( self, # name_id='', # _id='', # action='', # addresses=[""], # value='', # signed_value='', # remove_signed_value='', # message_text='', # new_owner='', # handle_pk='', # fork_head_pk='', # id_plate_pk='', # handle_id='', # fork_head_id='', # id_plate_id='', # retainer_thread_batch="", # retainer_washer_batch="", # retainer_nut_batch="", # screw1_batch="", # screw2_batch="", # usage="", # repairs="", # security_tag_public_key='', action='', licenceId='', videoId='', licenceOwner='', region='', date_from='', date_until='', addresses=[""], wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string payload = ",".join([ action, licenceId, videoId, licenceOwner, region, date_from, date_until ]).encode() print(f'encodedPayload:{payload}\n') print(f'payloadSha512:{_sha512(payload)}\n') print(f'addresses:{addresses}\n') header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name=addresser.FAMILY_NAME, family_version=addresser.FAMILY_VERSION, inputs=addresses, outputs=addresses, dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), # nonce=time.time().hex().encode() ).SerializeToString() print(f'header:{header}\n') #print(f'hash(header):{_sha512(header)}\n') signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) print(f'transaction:{transaction}\n') #print(f'hash(transaction):{_sha512(transaction)}\n') # def _create_batch_list(self, transactions): # transaction_signatures = [t.header_signature for t in transactions] # header = BatchHeader( # signer_public_key=self._signer.get_public_key().as_hex(), # transaction_ids=transaction_signatures # ).SerializeToString() # signature = self._signer.sign(header) # batch = Batch( # header=header, # transactions=transactions, # header_signature=signature) # return BatchList(batches=[batch]) batch_list = self._create_batch_list([transaction]) print(f'batch_list:{batch_list}\n') print(f'batch_list(encoded):{batch_list.SerializeToString()}\n') print(f'generates a list of codes from the characters of bytes') print( f'list(batch_list(encoded)):{list(batch_list.SerializeToString())}\n' ) print(f'hash(batch_list):{_sha512(batch_list.SerializeToString())}\n') batch_id = batch_list.batches[0].header_signature newFileBytes = batch_list.SerializeToString() # make file newFile = open(f"{batch_id}.batches", "wb") # write to file newFile.write(newFileBytes) # if wait and wait > 0: # wait_time = 0 # start_time = time.time() # response = self._send_request( # "batches", batch_list.SerializeToString(), # 'application/octet-stream', # auth_user=auth_user, # auth_password=auth_password) # while wait_time < wait: # status = self._get_status( # batch_id, # wait - int(wait_time), # auth_user=auth_user, # auth_password=auth_password) # wait_time = time.time() - start_time # if status != 'PENDING': # return response # return response # return self._send_request( # "batches", batch_list.SerializeToString(), # 'application/octet-stream', # auth_user=auth_user, # auth_password=auth_password) def create_video_licence_contract(self, licenceId, videoId, licenceOwner, region, date_from, date_until, wait=None, auth_user=None, auth_password=None): return self._send_txn(action="create_video_licence_contract", licenceId=licenceId, videoId=videoId, licenceOwner=licenceOwner, region=region, date_from=date_from, date_until=date_until, wait=wait, auth_user=auth_user, auth_password=auth_password) def list_msg(self, auth_user=None, auth_password=None): list(type=addresser.MESSAGE, auth_user=auth_user, auth_password=auth_password) def list_gfc_fork(self, auth_user=None, auth_password=None): list(type=addresser.GFC_FORK, auth_user=auth_user, auth_password=auth_password) def list(self, _type, auth_user=None, auth_password=None): prefix = addresser.NAMESPACE + _type result = self._send_request("state?address={}".format(prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def get_addresses_of_children(self, parent, auth_user=None, auth_password=None): print('get_addresses_of_children') print('address of parent = {}'.format( addresser._make_address_assembly_map_parent(parent))) print('address of parent + child = {}'.format( addresser._make_address_assembly_map( parent, '1111013a941a4b495a929f0ce35cb8b780b3c74734aafdddccaaf3b05923a8608f' ))) _rest_api = "state?address={}".format( addresser._make_address_assembly_map_parent(parent)) print('getting result from send request with format: {}'.format( _rest_api)) result = self._send_request( _rest_api, # NOTE this can only be a maximum of 12 hex long!! auth_user=auth_user, auth_password=auth_password) print( 'success: getting result from send request with format: {}'.format( _rest_api)) data_with_first_12_hex_matching_parent = self._yaml_load_data(result) print('loading the data: {}'.format( data_with_first_12_hex_matching_parent)) obj_list = [ obj.split(',') for objs in data_with_first_12_hex_matching_parent for obj in objs.decode().split('|') ] asset_maps_of_parents_list = [] parent_hash = addresser._hash(parent, 31) for addresses in obj_list: if addresses[0][8:39] == parent_hash: print('true- addresses[0][8:39]: {}\n parent: {}'.format( addresses[0][8:39], parent_hash)) asset_maps_of_parents_list.append(addresses[0]) else: print('false- addresses[0][8:39]: {}\n parent: {}'.format( addresses[0][8:39], parent_hash)) print('asset_maps_of_parents_list: \n{}'.format( asset_maps_of_parents_list)) return asset_maps_of_parents_list #print('\n printing obj_list \n{}'.format(obj_list)) def _yaml_load_data(self, result): try: encoded_entries = yaml.safe_load(result)["data"] return [ # [base64.b64decode(entry['address']), base64.b64decode(entry['data'])] for entry in encoded_entries base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None #TODO make sure its not a 404 error/ if statement that says there are no children in that case def show(self, name, address, auth_user=None, auth_password=None): print('doing show') result = self._send_request("state/{}".format(address), name=name, auth_user=auth_user, auth_password=auth_password) print('SUCCESS: doing show') try: print('Returning show data') return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def history(self, name, address, auth_user=None, auth_password=None): print('doing history') #TODO using this method will only show one block to another bocks' history. #This will skip history within a block. (e.g. in a block remove & add component = history not showing part removed only that the # new part is now there) _blocks = self._send_request( "blocks?", # ./{}".format(address) name=name, auth_user=auth_user, auth_password=auth_password) # if _blocks is not None: # block_list = [] # # for block in _blocks.split() # owner, msg = { # name: (owner, msg) # for name, owner, msg in [ # hw.split(',') # for hw in data.decode().split('|') # ] # }[name] #_batches, _header, _header_signature _blocks # result = self._send_request( # "state/{}".format(address), # name=name, # auth_user=auth_user, # auth_password=auth_password) # print('SUCCESS: doing show') try: print('Returning history data') return yaml.safe_load(_blocks)['data'] except BaseException: return None def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise Exception(err) # response = self._send_request( # "batches", batch_list.SerializeToString(), # 'application/octet-stream', # auth_user=auth_user, # auth_password=auth_password) def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) print(f'suffix:{suffix}') print(f'data:{data}\n') headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise Exception("No such message: {}".format(name)) elif not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class codeSmellClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise codeSmellException('Failed to read private key {}: {}'.format(keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise codeSmellException('Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')).new_signer(private_key) def list(self): code_smell_prefix = self._get_prefix() result = self._send_request( "state?address={}".format(code_smell_prefix) ) #pprint (result) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def create(self, name, value, action, wait=None, auth_user=None, auth_password=None): print ("on client", name, value, action) return self._send_codeSmell_txn( name, value, action, wait=wait, auth_user=auth_user, auth_password=auth_password) def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_status?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise codeSmellException(err) def _get_prefix(self): return _sha512('code-smell'.encode('utf-8'))[0:6] def _get_address(self, name): codeSmell_prefix = self._get_prefix() codeSmell_address = _sha512(name.encode('utf-8'))[0:64] return codeSmell_prefix + codeSmell_address def _send_request(self, suffix, data=None, content_type=None, name=None, value=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: #print (data) if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) #print (result.status_code) if result.status_code == 404: raise codeSmellException("No such code Smell: {}".format(name)) elif not result.ok: raise codeSmellException("Error {}:{}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise codeSmellException ('Failed to connect to {}:{}'.format(url, str(err))) except BaseException as err: raise codeSmellException(err) return result.text def _send_codeSmell_txn(self, name, value, action, wait=None, auth_user=None, auth_password=None): #serialization is just a delimited utf-8 encoded strings payload = ",".join([name, value, action]).encode() pprint(payload) #construct the address address = self._get_address(name) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="code-smell", family_version="0.1", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction ( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature print (wait) if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) if status != 'PENDING': return response return response return self._send_request( "batches" , batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): """ Create the list of batches that the client will send to the REST API Args: transactions (transaction): transaction(s) included in the batch Returns: BatchList: a list of batches to send to the REST API """ transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class XoClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException( 'Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise XoException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name, "create", wait=wait, auth_user=auth_user, auth_password=auth_password) def delete(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name, "delete", wait=wait, auth_user=auth_user, auth_password=auth_password) def take(self, name, space, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name, "take", space, wait=wait, auth_user=auth_user, auth_password=auth_password) def list(self, auth_user=None, auth_password=None): xo_prefix = self._get_prefix() result = self._send_request( "state?address={}".format(xo_prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def show(self, name, auth_user=None, auth_password=None): address = self._get_address(name) result = self._send_request( "state/{}".format(address), name=name, auth_user=auth_user, auth_password=auth_password) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise XoException(err) def _get_prefix(self): return _sha512('xo'.encode('utf-8'))[0:6] def _get_address(self, name): xo_prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[0:64] return xo_prefix + game_address def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such game: {}".format(name)) elif not result.ok: raise XoException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_xo_txn(self, name, action, space="", wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string payload = ",".join([name, action, str(space)]).encode() # Construct the address address = self._get_address(name) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="xo", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode() ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class Client: def __init__(self, base_url, pri_key_str=None): self._base_url = base_url if pri_key_str is None: self._signer = None return try: self.private_key_str = pri_key_str except OSError as err: raise Exception('Failed to read private key {}: {}'.format( pri_key_str, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(self.private_key_str) except ParseError as e: raise Exception('Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self.public_key = self._signer.get_public_key().as_hex() def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise Exception(err) def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise Exception("No such game: {}".format(name)) if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def send_txn(self, payload, order_numbers=None, anotherUser=None, setting=False, station=None, mobiles=None, wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string # Construct the address change_adress = [ make_user_address(self._signer.get_public_key().as_hex()) ] if order_numbers is not None: for o in order_numbers: change_adress.append(make_oder_address(o)) if anotherUser is not None: change_adress.append(make_user_address(anotherUser)) if setting: change_adress.append(SETTING_ADDRESS) if station is not None: change_adress.append(make_station_adress(station)) print(make_station_adress(station)) if mobiles is not None: for m in mobiles: change_adress.append(make_mobile_adress(m)) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="pacel_chain", family_version="1.0", inputs=change_adress, outputs=change_adress, dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status(batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
outputs=['19d832'], signer_public_key=signer.get_public_key().as_hex(), # In this example, we're signing the batch with the same private key, # but the batch can be signed by another party, in which case, the # public key will need to be associated with that key. batcher_public_key=signer.get_public_key().as_hex(), # In this example, there are no dependencies. This list should include # an previous transaction header signatures that must be applied for # this transaction to successfully commit. # For example, # dependencies=['540a6803971d1880ec73a96cb97815a95d374cbad5d865925e5aa0432fcf1931539afe10310c122c5eaae15df61236079abbf4f258889359c4d175516934484a'], dependencies=[], payload_sha512=sha512(payload_bytes).hexdigest()).SerializeToString() #create transaction signature = signer.sign(txn_header_bytes) txn = Transaction(header=txn_header_bytes, header_signature=signature, payload=payload_bytes) #create batch headers txns = [txn] batch_header_bytes = BatchHeader( signer_public_key=signer.get_public_key().as_hex(), transaction_ids=[txn.header_signature for txn in txns], ).SerializeToString() #create the batch signature = signer.sign(batch_header_bytes) batch = Batch(header=batch_header_bytes,
family_version='1.0', inputs=[tx_addr[i][j]], outputs=[tx_addr[i][j]], signer_public_key = signer.get_public_key().as_hex(), batcher_public_key = signer.get_public_key().as_hex(), dependencies=[], payload_sha512 = sha512(payload_bytes_arr[i][j]).hexdigest() ).SerializeToString() for j in range(NUM_TX_PER_BATCH) ] for i in range(NUM_BATCHES) ] #Signer signs the header: signature_arr = [ [ signer.sign(tx_header_arr[i][j]) for j in range(NUM_TX_PER_BATCH) ] for i in range(NUM_BATCHES) ] #Generate an array with all the transactions tx_arr= [ [Transaction( header=tx_header_arr[i][j], header_signature=signature_arr[i][j], payload = payload_bytes_arr[i][j] ) for j in range(NUM_TX_PER_BATCH) ] for i in range(NUM_BATCHES) ]
class CCellularClient: def __init__(self, conf: DistributedManagerConfig): self.conf = conf self.url = conf.CLIENT_URL # Transaction batcher self.transaction_queue = queue.Queue() self.pending_transactions = [] self.run_check = None self.transaction_batcher_thread = None self.last_batch_time = 0 # Get the key from the local machine keyfile = conf.CLIENT_KEY_PATH # The signer requires a key from the local user/machine # See sawtooth documentation for producing a key if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise Exception('Failed to read private key at {}'.format(err)) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise Exception( 'Unable to load the private key correctly {}'.format( str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) self.logger = None # Spawns a thread that handles the creation of transactions and batching # Run check function is used by the batcher to check if parent module is still running def start_batcher(self, run_check_function): if run_check_function is None: raise ValueError("Run check function must be specified") self.run_check = run_check_function self.transaction_batcher_thread = threading.Thread( target=self._transaction_batcher) self.transaction_batcher_thread.start() # Creates a transaction and sends to sawtooth validator def set_entry(self, entry: DatabaseEntry): self.log("Set entry called, queueing transaction") self.transaction_queue.put(('set', entry)) # Get value of the entry corresponding to the key def get(self, key): self.log("Get entry called with key: " + str(key)) address = make_ccellular_address(key) result = self._send_request("state/{}".format(address), name=key) if result != None: try: json_result = json.loads(result) data_response = json_result['data'] b64data = yaml.safe_load(data_response) b64decoded = base64.b64decode(b64data) cbor_decoded = cbor.loads(b64decoded) return DatabaseEntry(cbor_decoded[key]) except BaseException as e: print("Received a base exception:", e) return None # Will likely get all data, may need to be optimized def get_all(self): self.log("Getting all keys") prefix = get_prefix() # For the transaction family result = self._send_request("state", name="GET_ALL_KEYS", params={"address": prefix}) if result != None: try: self.log("json result: " + str(json.loads(result))) next_page = json.loads(result)['paging'].get('next') json_result_list = json.loads(result)['data'] entry_key_set = set() for result in json_result_list: data_response = result['data'] b64data = yaml.safe_load(data_response) b64decoded = base64.b64decode(b64data) cbor_decoded = cbor.loads(b64decoded) entry_key_set.update(set(cbor_decoded.keys())) # Get paginated elements while next_page != None: self.log("Getting paginated element") result_obj = requests.get(next_page) if result_obj != None: if not result_obj.ok: self.log("Error getting paginated list -- {}: {}". format(result_obj.status_code, result_obj.reason)) break result = result_obj.text next_page = json.loads(result)['paging'].get('next') json_result_list = json.loads(result)['data'] self.log("json result (pag): " + str(json.loads(result))) for result in json_result_list: data_response = result['data'] b64data = yaml.safe_load(data_response) b64decoded = base64.b64decode(b64data) cbor_decoded = cbor.loads(b64decoded) entry_key_set.update(set(cbor_decoded.keys())) return entry_key_set except BaseException as e: self.log("Received a base exception: " + str(e)) return None # Processes available transactions into batches # Batch size and timeout can be configured def _transaction_batcher(self): self.log("Batcher thread entering") while self.run_check(): # get any new transactions (up to batch size) while self.transaction_queue.qsize() > 0: # get the next pending transaction and add it to pending action, entry = self.transaction_queue.get() self._build_transaction(action, entry) # stop adding new messages if batch size is reached # TODO: possible overloading option? if len(self.pending_transactions) >= self.conf.BATCH_SIZE: break # if there are no transactions, reset the batch timeout if len(self.pending_transactions) == 0: self.last_batch_time = time.time() # check for a new full size batch or a batch timeout with at least one transaction elif len(self.pending_transactions) >= self.conf.BATCH_SIZE or\ (time.time() - self.last_batch_time >= self.conf.BATCH_TIMEOUT and\ len(self.pending_transactions) > 0): self.log("Creating and sending new batch") if len(self.pending_transactions) >= self.conf.BATCH_SIZE: self.log(" Batch size reached") else: self.log(" Batch timeout exceeded, sending with {0}/{1}"\ .format(len(self.pending_transactions), self.conf.BATCH_SIZE)) # build batch from available transactions batch_list = self._create_batch_list(self.pending_transactions) # continue and retry later if there is no batch to send if batch_list is None: self.log("No batch list to send") continue # clear the pending list of transactions self.pending_transactions = [] # Send new batch (TODO save output?) self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) # wait a little before checking again (for performance) time.sleep(self.conf.BATCH_CHECK_DELAY) self.log("Batcher thread exiting") self.transaction_batcher_thread = None # Builds a transaction from the provided info and adds to pending def _build_transaction(self, action, entry): payload = build_payload(action, entry) address = make_ccellular_address(entry.key()) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name=self.conf.FAMILY_NAME, family_version=self.conf.FAMILY_VERSION, inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) self.pending_transactions.append(transaction) # Creates a transaction batch of one or more transactions # All transactions must be included in a batch def _create_batch_list(self, transactions): if len(transactions) < 1: self.log( "Attempting to create batch with no transactions, ignoring") return None transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch]) # Sends the request to the validator def _send_request(self, suffix, data=None, content_type=None, name=None, params={}): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers, params=params) if result.status_code == 404: self.log("No such Key Exists: {}".format(name)) return None if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception( "Failed to connect to the REST API services : {}".format(err)) except BaseException as err: raise Exception("Failed {}".format(err)) return result.text def log(self, message): if self.logger: self.logger("(Client) " + message)
class SawtoothClient(object): def __init__(self, url, keyfile=None): self.base_url = url if keyfile is not None: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() sawtooth_signing_key = Secp256k1PrivateKey.from_hex( private_key_str) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(sawtooth_signing_key) def add_net(self, network_id, payload, wait=None): address = make_network_address(network_id) return self._send_transaction(ActionTypes.ADD_NET.value, payload, [address], wait=wait) def _send_transaction(self, action, action_payload, addresses, wait=None): payload = cbor.dumps({'action': action, 'payload': action_payload}) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="billing-crdt", family_version="0.0.1", inputs=addresses, outputs=addresses, dependencies=[], payload_sha512=self._sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=self._nonce()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), ) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) def _send_request(self, suffix, data=None, content_type=None, name=None): url = "{}/{}".format(self.base_url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise CrdtClientException( "Error url={} name={} - {}: {}".format( suffix, name, result.status_code, result.reason)) except requests.ConnectionError as err: raise CrdtClientException( 'Failed to connect to REST API: {}'.format(err)) except BaseException as err: raise CrdtClientException(err) return result.text def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch]) @staticmethod def _sha512(data): return hashlib.sha512(data).hexdigest() @staticmethod def _nonce(): return time.time().hex().encode()
class SimpleWalletClient(object): '''Client simple wallet class. This supports deposit, withdraw, transfer, and balance functions. ''' def __init__(self, baseUrl, keyFile=None): '''Initialize the client class. This is mainly getting the key pair and computing the address. ''' self._baseUrl = baseUrl if keyFile is None: self._signer = None return try: with open(keyFile) as fd: privateKeyStr = fd.read().strip() except OSError as err: raise Exception('Failed to read private key {}: {}'.format( keyFile, str(err))) try: privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr) except ParseError as err: raise Exception('Failed to load private key: {}'.format(str(err))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(privateKey) self._publicKey = self._signer.get_public_key().as_hex() self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(self._publicKey.encode('utf-8'))[0:64] # For each valid cli command in _cli.py file, # add methods to: # 1. Do any additional handling, if required # 2. Create a transaction and a batch # 2. Send to rest-api def deposit(self, value): return self._wrap_and_send("deposit", value) def withdraw(self, value): try: retValue = self._wrap_and_send("withdraw", value) except Exception: raise Exception('Encountered an error during withdrawal') return retValue def make_driver(self, value): try: retValue = self._wrap_and_send("makeDriver", value) except Exception: raise Exception('Encountered an error during make driver') return retValue def transfer(self, value, clientToKey): try: with open(clientToKey) as fd: publicKeyStr = fd.read().strip() retValue = self._wrap_and_send("transfer", value, publicKeyStr) except OSError as err: raise Exception('Failed to read public key {}: {}'.format( clientToKey, str(err))) except Exception as err: raise Exception('Encountered an error during transfer', err) return retValue def balance(self): result = self._send_to_restapi("state/{}".format(self._address)) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _send_to_restapi(self, suffix, data=None, contentType=None): '''Send a REST command to the Validator via the REST API.''' if self._baseUrl.startswith("http://"): url = "{}/{}".format(self._baseUrl, suffix) else: url = "http://{}/{}".format(self._baseUrl, suffix) headers = {} if contentType is not None: headers['Content-Type'] = contentType try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def _wrap_and_send(self, action, *values): '''Create a transaction, then wrap it in a batch. Even single transactions must be wrapped into a batch. ''' # Generate a csv utf-8 encoded string as payload rawPayload = action for val in values: rawPayload = ",".join([rawPayload, str(val)]) payload = rawPayload.encode() # Construct the address where we'll store our state address = self._address inputAddressList = [address] outputAddressList = [address] if "transfer" == action: toAddress = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(values[1].encode('utf-8'))[0:64] inputAddressList.append(toAddress) outputAddressList.append(toAddress) # Create a TransactionHeader header = TransactionHeader( signer_public_key=self._publicKey, family_name=FAMILY_NAME, family_version="1.0", inputs=inputAddressList, outputs=outputAddressList, dependencies=[], payload_sha512=_hash(payload), batcher_public_key=self._publicKey, nonce=random.random().hex().encode()).SerializeToString() # Create a Transaction from the header and payload above transaction = Transaction(header=header, payload=payload, header_signature=self._signer.sign(header)) transactionList = [transaction] # Create a BatchHeader from transactionList above header = BatchHeader( signer_public_key=self._publicKey, transaction_ids=[txn.header_signature for txn in transactionList]).SerializeToString() #Create Batch using the BatchHeader and transactionList above batch = Batch(header=header, transactions=transactionList, header_signature=self._signer.sign(header)) #Create a Batch List from Batch above batch_list = BatchList(batches=[batch]) # Send batch_list to rest-api return self._send_to_restapi("batches", batch_list.SerializeToString(), 'application/octet-stream')
class HealthCareClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise HealthCareException( 'Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise HealthCareException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create_clinic(self, name, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() address = helper.make_clinic_address(clinic_pkey=txn_key) clinic = payload_pb2.CreateClinic( public_key=txn_key, name=name) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_CLINIC, create_clinic=clinic) return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def create_doctor(self, name, surname, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() address = helper.make_doctor_address(doctor_pkey=txn_key) doctor = payload_pb2.CreateDoctor( public_key=txn_key, name=name, surname=surname) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_DOCTOR, create_doctor=doctor) return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def create_patient(self, name, surname, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() address = helper.make_patient_address(patient_pkey=txn_key) patient = payload_pb2.CreatePatient( public_key=txn_key, name=name, surname=surname) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_PATIENT, create_patient=patient) return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def add_claim(self, claim_id, patient_pkey, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) claim = payload_pb2.CreateClaim( claim_id=claim_id, clinic_pkey=txn_key, patient_pkey=patient_pkey, ) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_CLAIM, create_claim=claim) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, clinic_hex], [claim_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def assign_doctor(self, claim_id, doctor_pkey, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) assign = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description="Doctor pkey: {}, assigned to claim: {}".format(doctor_pkey, claim_hex), event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.ASSIGN_DOCTOR, assign_doctor=assign) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def first_visit(self, claim_id, description, doctor_pkey, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) first_visit = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description="Doctor pkey: {}, claim hex: {}, description: {}".format(doctor_pkey, claim_hex, description), event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.FIRST_VISIT, first_visit=first_visit) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def pass_tests(self, claim_id, description, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) pass_tests = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description=description, event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.PASS_TESTS, pass_tests=pass_tests) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def attend_procedures(self, claim_id, description, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) attend_procedures = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description=description, event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.ATTEND_PROCEDURES, attend_procedures=attend_procedures) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def eat_pills(self, claim_id, description, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) address = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) eat_pills = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description=description, event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.EAT_PILLS, eat_pills=eat_pills) return self._send_healthcare_txn(txn_key, batch_key, [address, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def next_visit(self, claim_id, description, doctor_pkey, wait=None, auth_user=None, auth_password=None): batch_key = txn_key = self._signer.get_public_key().as_hex() clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key) claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key) current_times_str = str(time.time()) event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str) next_visit = payload_pb2.ActionOnClaim( claim_id=claim_id, clinic_pkey=txn_key, description="Doctor pkey: {}, claim hex: {}, description: {}".format(doctor_pkey, claim_hex, description), event_time=current_times_str) payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.NEXT_VISIT, next_visit=next_visit) return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload, wait=wait, auth_user=auth_user, auth_password=auth_password) def list_claims(self, auth_user=None, auth_password=None): claim_list_prefix = helper.make_claim_list_address() result = self._send_request( "state?address={}".format(claim_list_prefix), auth_user=auth_user, auth_password=auth_password) orders = {} try: data = yaml.safe_load(result)["data"] if data is not None: for value in data: dec_ord = base64.b64decode(value["data"]) o = payload_pb2.CreateClaim() o.ParseFromString(dec_ord) orders[value["address"]] = o except BaseException: pass return orders def list_patients(self, auth_user=None, auth_password=None): patient_list_prefix = helper.make_patient_list_address() result = self._send_request( "state?address={}".format(patient_list_prefix), auth_user=auth_user, auth_password=auth_password) patients = {} try: data = yaml.safe_load(result)["data"] if data is not None: for value in data: dec_pt = base64.b64decode(value["data"]) pt = payload_pb2.CreatePatient() pt.ParseFromString(dec_pt) patients[value["address"]] = pt except BaseException: pass return patients def list_clinics(self, auth_user=None, auth_password=None): operator_list_prefix = helper.make_clinic_list_address() result = self._send_request( "state?address={}".format(operator_list_prefix), auth_user=auth_user, auth_password=auth_password) clinics = {} try: data = yaml.safe_load(result)["data"] if data is not None: for value in data: dec_cl = base64.b64decode(value["data"]) cl = payload_pb2.CreateClinic() cl.ParseFromString(dec_cl) clinics[value["address"]] = cl except BaseException: pass return clinics def list_doctors(self, auth_user=None, auth_password=None): doctor_list_prefix = helper.make_doctor_list_address() result = self._send_request( "state?address={}".format(doctor_list_prefix), auth_user=auth_user, auth_password=auth_password) doctors = [] try: data = yaml.safe_load(result)["data"] if data is not None: for value in data: dec_dc = base64.b64decode(value["data"]) dc = payload_pb2.CreateDoctor() dc.ParseFromString(dec_dc) doctors.append(dc) except BaseException: pass return doctors def list_claim_details(self, claim_id, clinic_hex, auth_user=None, auth_password=None): claim_details_prefix = helper.make_event_list_address(claim_id=claim_id, clinic_pkey=clinic_hex) result = self._send_request( "state?address={}".format(claim_details_prefix), auth_user=auth_user, auth_password=auth_password) orders = {} try: data = yaml.safe_load(result)["data"] if data is not None: for value in data: dec_ord = base64.b64decode(value["data"]) o = payload_pb2.ActionOnClaim() o.ParseFromString(dec_ord) orders[value["address"]] = o except BaseException: pass return orders def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = base64.b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise HealthCareException("No such operator: {}".format(name)) elif not result.ok: raise HealthCareException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise HealthCareException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise HealthCareException(err) return result.text def _send_healthcare_txn(self, txn_key, batch_key, inputs, outputs, payload, wait, auth_user, auth_password): txn_header_bytes, signature = self._transaction_header(txn_key, inputs, outputs, payload) txn = Transaction( header=txn_header_bytes, header_signature=signature, payload=payload.SerializeToString() ) transactions = [txn] batch_header_bytes, signature = self._batch_header(batch_key, transactions) batch = Batch( header=batch_header_bytes, header_signature=signature, transactions=transactions ) batch_list = BatchList(batches=[batch]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise HealthCareException(err) def _transaction_header(self, txn_key, inputs, outputs, payload): txn_header_bytes = TransactionHeader( family_name=helper.TP_FAMILYNAME, family_version=helper.TP_VERSION, inputs=inputs, outputs=outputs, signer_public_key=txn_key, # signer.get_public_key().as_hex(), # In this example, we're signing the batch with the same private key, # but the batch can be signed by another party, in which case, the # public key will need to be associated with that key. batcher_public_key=txn_key, # signer.get_public_key().as_hex(), # In this example, there are no dependencies. This list should include # an previous transaction header signatures that must be applied for # this transaction to successfully commit. # For example, # dependencies=['540a6803971d1880ec73a96cb97815a95d374cbad5d865925e5aa0432fcf1931539afe10310c122c5eaae15df61236079abbf4f258889359c4d175516934484a'], dependencies=[], nonce=random.random().hex().encode(), payload_sha512=hashlib.sha512(payload.SerializeToString()).hexdigest() ).SerializeToString() signature = self._signer.sign(txn_header_bytes) return txn_header_bytes, signature def _batch_header(self, batch_key, transactions): batch_header_bytes = BatchHeader( signer_public_key=batch_key, transaction_ids=[txn.header_signature for txn in transactions], ).SerializeToString() signature = self._signer.sign(batch_header_bytes) return batch_header_bytes, signature
class BattleshipClient: def __init__(self, base_url, keyfile, wait=None): """ Member variables: _base_url _private_key _public_key _transaction_family _family_version _wait """ self._base_url = base_url try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise IOError("Failed to read keys: {}.".format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise BattleshipException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) self._transaction_family = "battleship" self._family_version = "1.0" self._wait = wait def _send_battleship_txn(self, update): """The client needs to have the same defaults as the Transaction subclass before it is signed inside sendtxn """ if 'Name' not in update: raise BattleshipException('Game name required') if 'Action' not in update: update['Action'] = None if 'Ships' not in update: update['Ships'] = None if update['Action'] == 'JOIN': if 'Board' not in update: update['Board'] = None if update['Action'] == 'FIRE': if 'Column' not in update: update['Column'] = None if 'Row' not in update: update['Row'] = None payload = json.dumps(update).encode() address = self._get_address(update['Name']) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name=self._transaction_family, family_version=self._family_version, inputs=[address], outputs=[address], dependencies=[], payload_sha512=self._sha512(payload), batcher_public_key=self.signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if self._wait and self._wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream' ) while wait_time < self._wait: status = self._get_status( batch_id, self._wait - int(wait_time) ) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream') def create(self, name, ships): """ Create battleship game """ update = { 'Action': 'CREATE', 'Name': name, 'Ships': ships } return self._send_battleship_txn(update) def join(self, name, board): """ User joins battleship game """ update = { 'Action': 'JOIN', 'Name': name, 'Board': board } return self._send_battleship_txn(update) def fire(self, name, column, row, reveal_space, reveal_nonce): """ Fire at (column, row) """ update = { 'Action': 'FIRE', 'Name': name, 'Column': column, 'Row': row } if reveal_space is not None: update['RevealSpace'] = reveal_space if reveal_nonce is not None: update['RevealNonce'] = reveal_nonce return self._send_battleship_txn(update) def list_games(self, auth_user=None, auth_password=None): prefix = self._get_prefix() result = self._send_request( "state?address={}".format(prefix), auth_user=auth_user, auth_password=auth_password ) try: encoded_entries = yaml.safe_load(result)["data"] ret = {} for entry in encoded_entries: d = json.loads(b64decode(entry["data"]).decode()) for k, v in d.items(): ret[k] = v return ret except BaseException: return None def _sha512(self, data): return hashlib.sha512(data).hexdigest() def _get_prefix(self): return self._sha512(self._transaction_family.encode('utf-8'))[0:6] def _get_address(self, name): prefix = self._get_prefix() game_address = self._sha512(name.encode('utf-8'))[0:64] return prefix + game_address def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature ) return BatchList(batches=[batch]) def _get_status(self, batch_id, wait): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait)) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise BattleshipException(err) def _send_request( self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise BattleshipException("No such game: {}".format(name)) elif not result.ok: raise BattleshipException("Error {}: {}".format( result.status_code, result.reason)) except BaseException as err: raise BattleshipException(err) return result.text
class IntkeyClient: def __init__(self, url, keyfile=None): self.url = url if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise IntkeyClientException( 'Failed to read private key: {}'.format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise IntkeyClientException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) print(self._signer) def set(self, name, value, wait=None): return self._send_transaction('set', name, value, wait=wait) def inc(self, name, value, wait=None): return self._send_transaction('inc', name, value, wait=wait) def dec(self, name, value, wait=None): return self._send_transaction('dec', name, value, wait=wait) def mul(self, name, value, wait=None): return self._send_transaction('mul', name, value, wait=wait) def list(self): result = self._send_request("state?address={}".format( self._get_prefix())) try: encoded_entries = yaml.safe_load(result)["data"] return [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] except BaseException: return None def show(self, name): address = self._get_address(name) result = self._send_request( "state/{}".format(address), name=name, ) try: return cbor.loads(base64.b64decode( yaml.safe_load(result)["data"]))[name] except BaseException: return None def _get_status(self, batch_id, wait): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), ) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise IntkeyClientException(err) def _get_prefix(self): return _sha512('intkey'.encode('utf-8'))[0:6] def _get_address(self, name): prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[64:] return prefix + game_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise IntkeyKeyNotFoundException( "No such key: {}".format(name)) elif not result.ok: raise IntkeyClientException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise IntkeyClientException( 'Failed to connect to REST API: {}'.format(err)) except BaseException as err: raise IntkeyClientException(err) return result.text def _send_transaction(self, verb, name, value, wait=None): payload = cbor.dumps({ 'Verb': verb, 'Name': name, 'Value': value, }) # Construct the address address = self._get_address(name) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="intkey", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), ) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class IoTClient: def __init__(self, url, keyfile=None): self.url = url if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise IoTException('Failed to read private key: {}'.format( str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise IoTException('Unable to load private key: {}'.format( str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def send(self, path): #get user public, we will use as ID device_id = self._signer.get_public_key().as_hex()[:4] #get image metadata metadata = _get_metadata(path) #get timestamp timestamp = _get_date() if metadata is None: return "Unable to open Image" return self._send_transaction(device_id, metadata, timestamp) def list(self): result = self._send_request("state?address={}".format( self._get_prefix())) try: encoded_entries = yaml.safe_load(result)["data"] return [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] except BaseException: return None def _get_prefix(self): return _sha512('iot-tp'.encode('utf-8'))[0:6] def _get_address(self, metadata): prefix = self._get_prefix() txn_address = _sha512(yaml.dump(metadata).encode('utf-8'))[64:] return prefix + txn_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 4004: raise IoTClient("No such key: {}".format(name)) elif not result.ok: raise IoTClient("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise IoTClient('Failed to connect to REST API: {}'.format(err)) except BaseException as err: raise IoTClient(err) return result.text def _send_transaction(self, device_id, metadata, timestamp): payload = cbor.dumps({ 'device_id': device_id, 'metadata': metadata, 'timestamp': timestamp, }) address = self._get_address(metadata) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="iot-tp", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class CodeSmellClient: """ construct and send code smell transaction. """ def __init__(self, base_url, work_path, keyfile=None): self._base_url = base_url self._work_path = work_path if keyfile is None: self._signer = None return try: with open(keyfile) as fileptr: private_key_str = fileptr.read().strip() except OSError as err: raise CodeSmellException( 'Failed to read private key {}: {}'.format(keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as error: raise CodeSmellException('Unable to load private key: {}'.format( str(error))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def default(self): """ load a defautl code smell configuration """ #identify code_smell family configuration file conf_file = self._work_path + '/etc/.suse' response = "" if os.path.isfile(conf_file): try: with open(conf_file) as config: raw_config = config.read() except IOError as error: raise CodeSmellException( "Unable to load code smell family configuration file: {}". format(error)) #load toml config into a dict parsed_toml_config = toml.loads(raw_config) #get default code smells code_smells_config = parsed_toml_config['code_smells'] #code_smells_config = parsed_toml_config """traverse dict and process each code smell nested for loop to procces level two dict.""" for code_smells in code_smells_config.values(): for name, metric in code_smells.items(): #send trasaction response = self._send_code_smell_txn( txn_type='code_smell', txn_id=name, data=str(metric[0]), ## TODO: add weigth value state='create') code_smells_config = parsed_toml_config['vote_setting'] """traverse dict and process each code smell nested for loop to procces level two dict.""" for name, metric in code_smells_config.items(): #send transaction response = self._send_code_smell_txn(txn_type='code_smell', txn_id=name, data=str(metric[0]), state='create') else: raise CodeSmellException( "Configuration File {} does not exists".format(conf_file)) return response def list(self, txn_type=None, active_flag=None): """ list all transactions. Args: type (str), asset that we want to list (code smells, proposals, votes) """ #pull all transactions of code smell family result = self._send_request("transactions") transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] if txn_type is None: for entry in encoded_entries: transactions[entry["header_signature"]] = base64.b64decode( entry["payload"]) else: for entry in encoded_entries: transaction_type = base64.b64decode( entry["payload"]).decode().split(',')[0] if transaction_type == txn_type: transactions[ entry["header_signature"]] = base64.b64decode( entry["payload"]) if txn_type == 'proposal' and active_flag == 1: return sorted(transactions) else: return transactions except BaseException: return None def show(self, address): """ list a specific transaction, based on its address Args: address (str), transaction's address """ result = self._send_request("transactions/{}".format(address)) transactions = {} try: encoded_entries = yaml.safe_load(result)["data"] transactions["payload"] = base64.b64decode( encoded_entries["payload"]) transactions["header_signature"] = encoded_entries[ "header_signature"] return transactions except BaseException: return None def propose(self, code_smells): """ propose new metrics for the code smell families the function assumes that all code smells have been updated even if they don't Args: code_smells (dict), dictionary of code smells and metrics """ #get code smell family address prefix code_smell_prefix = self._get_prefix() #check for an active proposal, transactions are return in sequential order. proposal_result = self._send_request( "state?address={}".format(code_smell_prefix)) encoded_entries = yaml.safe_load(proposal_result)["data"] for entry in encoded_entries: #look for the first proposal transactiosn if base64.b64decode( entry["data"]).decode().split(',')[0] == "proposal": last_proposal = base64.b64decode( entry["data"]).decode().split(',') break try: if last_proposal[3] == "active": return "Invalid Operation, another proposal is Active" except BaseException: pass localtime = time.localtime(time.time()) transac_time = str(localtime.tm_year) + str(localtime.tm_mon) + str( localtime.tm_mday) propose_date = str(transac_time) response = self._send_code_smell_txn( txn_id=_sha512(str(code_smells).encode('utf-8'))[0:6], txn_type='proposal', data=str(code_smells).replace(",", ";"), state='active', date=propose_date) return response def update_proposal(self, proposal_id, state): """ update proposal state Args: proposal_id (str), proposal ID state (Str), new proposal ID """ proposal = self.show(proposal_id) self._update_proposal(proposal, state) def _update_proposal(self, proposal, state): """ update proposal, update state. Args: proposal (dict), proposal data sate (str), new proposal's state """ localtime = time.localtime(time.time()) transac_time = str(localtime.tm_year) + str(localtime.tm_mon) + str( localtime.tm_mday) propose_date = str(transac_time) response = self._send_code_smell_txn(txn_id=proposal[1], txn_type='proposal', data=proposal[2], state=state, date=propose_date) work_path = os.path.dirname( os.path.dirname( os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) conf_file = work_path + '/etc/.suse' if os.path.isfile(conf_file): try: with open(conf_file) as config: raw_config = config.read() except IOError as error: raise CodeSmellException( "Unable to load code smell family configuration file: {}". format(error)) #load toml config into a dict toml_config = toml.loads(raw_config) self._send_git_request(toml_config) def _send_git_request(self, toml_config): """ send new code smell configuration to github Args: toml_config (dict): code smells to send """ wrapper_json = {} wrapper_json["sender"] = "Sawtooth" wrapper_json["repo"] = "157484644" ## TODO: update with dynamic repo wrapper_json["suse_file"] = toml_config data = json.dumps(wrapper_json) requests.post('http://129.108.7.2:3000', data=data) def update_config(self, proposal): """ update code smell configuration metrics, after the proposal is accepted the configuration file needs to be updated. Args: toml_config (dict), current configuration proposal (str), proposal that contains new configuration """ #get proposal payload proposal_payload = yaml.safe_load(proposal[2].replace(";", ",")) work_path = os.path.dirname( os.path.dirname( os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) #identify code_smell family configuration file conf_file = work_path + '/etc/.suse' if os.path.isfile(conf_file): try: with open(conf_file) as config: raw_config = config.read() except IOError as error: raise CodeSmellException( "Unable to load code smell family configuration file: {}". format(error)) #load toml config into a dict toml_config = toml.loads(raw_config) """ start by traversing the proposal, get the code smell and the metric """ for proposal_key, proposal_metric in proposal_payload.items(): tmp_type = "" """ we don't know where on the toml file is the code smell, traverse the toml dictionary looking for the same code smell. """ for code_type in toml_config["code_smells"]: """ once you found the code smell, break the loop and return a pseudo location """ if proposal_key in toml_config["code_smells"][code_type].keys( ): tmp_type = code_type break #update configuration toml_config["code_smells"][tmp_type][proposal_key][0] = int( proposal_metric) #save new configuration try: with open(conf_file, 'w+') as config: toml.dump(toml_config, config) #self._send_git_request(toml_config) except IOError as error: raise CodeSmellException( "Unable to open configuration file {}".format(error)) def check_votes(self, proposal_id): """ review the votes of a proposal Args: proposal_id (str), proposal id """ result = self._send_request("transactions/{}".format(proposal_id)) encoded_result = yaml.safe_load(result)["data"] proposal = base64.b64decode( encoded_result["payload"]).decode().split(',') proposal_id = proposal[1] transactions = self.list(txn_type='vote') votes = [] for vote in transactions: #for all votes of proposal if transactions[vote].decode().split(',')[2] == proposal_id: #get vote and count, only accepted votes #if transactions[vote].decode().split(',')[3] == '1': votes.append(int(transactions[vote].decode().split(',')[3])) return votes ################## #NO NEED THE SERVER WILL HANDLE THIS #get treshold #identify code_smell family configuration file # conf_file = self._work_path + '/etc/.suse' # # if flag is not None: # if os.path.isfile(conf_file): # try: # with open(conf_file) as config: # raw_config = config.read() # config.close() # except IOError as error: # raise CodeSmellException( # "Unable to load code smell family configuration file {}".format(error)) # # #load toml config into a dict # parsed_toml_config = toml.loads(raw_config) # # #get treshold # code_smells_config = parsed_toml_config['vote_setting'] # # vote_treshold = int(code_smells_config['approval_treshold']) # # if total_votes >= vote_treshold: # self._update_config(parsed_toml_config, proposal) # #you need this, you commented out to test the github stuff # #self._update_proposal(proposal, "accepted") # else: # return "Total votes (accepted): " + str(total_votes) def vote(self, proposal_id, vote): """ vote to accept or reject a proposal Args: proposal_id (str), id of proposal vote (int), value of vote 1=accept, 0=reject """ #verify active proposal result = self._send_request("transactions/{}".format(proposal_id)) encoded_result = yaml.safe_load(result)["data"] proposal = base64.b64decode( encoded_result["payload"]).decode().split(',') if proposal[3] != 'active': return "Proposal not active" #verify double voting # proposal_id = proposal[1] # result = self._send_request("transactions") # encoded_entries = yaml.safe_load(result)["data"] # for entry in encoded_entries: # transaction_type = base64.b64decode(entry["payload"]).decode().split(',')[0] # if transaction_type == 'vote': # if entry['header']['signer_public_key'] == self._signer.get_public_key().as_hex(): # return ("User already submitted a vote") #active proposal, record vote response = self._send_code_smell_txn(txn_id=str( random.randrange(1, 99999)), txn_type='vote', data=proposal[1], state=str(vote)) # conf_file = '/home/mrwayne/Desktop/Susereum/Sawtooth/etc/.suse' # # if os.path.isfile(conf_file): # try: # with open(conf_file) as config: # raw_config = config.read() # config.close() # except IOError as error: # raise CodeSmellException( # "Unable to load code smell family configuration file {}".format(error)) # # #load toml config into a dict # parsed_toml_config = toml.loads(raw_config) # self._send_git_request(parsed_toml_config) return response def send_config(self, config=None): """ function to send an update configuration transaction to the chain after the code smell configuration is update al peers in the network must update the local configuration file. Args: config (dictionary), code smell configuration """ #read .suse configuration file toml_config = self._get_config_file() print(toml_config) def _get_config_file(self): work_path = os.path.dirname( os.path.dirname( os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) #identify code_smell family configuration file conf_file = work_path + '/etc/.suse' if os.path.isfile(conf_file): try: with open(conf_file) as config: raw_config = config.read() except IOError as error: raise CodeSmellException( "Unable to load code smell family configuration file: {}". format(error)) #load toml config into a dict toml_config = toml.loads(raw_config) return toml_config def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request('batch_status?id={}&wait={}'.format( batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise CodeSmellException(err) def _get_prefix(self): """ get code smell family address prefix """ return _sha512('code-smell'.encode('utf-8'))[0:6] def _get_address(self, transaction_id): """ get transaction address Args: id (str): trasaction id """ code_smell_prefix = self._get_prefix() code_smell_address = _sha512(transaction_id.encode('utf-8'))[0:64] return code_smell_prefix + code_smell_address def _send_request(self, suffix, data=None, content_type=None, auth_user=None, auth_password=None): """ send request to code smell processor` """ if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise CodeSmellException("No such transaction") elif not result.ok: raise CodeSmellException("Error {}:{}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise CodeSmellException('Failed to connect to {}:{}'.format( url, str(err))) except BaseException as err: raise CodeSmellException(err) return result.text def _send_code_smell_txn(self, txn_type=None, txn_id=None, data=None, state=None, date=None): """ serialize payload and create header transaction Args: type (str): type of transaction id (str): asset id, will depend on type of transaction data (object): transaction data state (str): all transactions must have a state wait (int): delay to process transactions """ #serialization is just a delimited utf-8 encoded strings if txn_type == 'proposal': payload = ",".join([txn_type, txn_id, data, state, str(date)]).encode() else: payload = ",".join([txn_type, txn_id, data, state]).encode() pprint("payload: {}".format( payload)) ######################################## pprint #construct the address address = self._get_address(txn_id) #construct header` header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="code-smell", family_version="0.1", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64))).SerializeToString() signature = self._signer.sign(header) #create transaction transaction = Transaction(header=header, payload=payload, header_signature=signature) #create batch list, suserum policy: one transaction per batch batch_list = self._create_batch_list([transaction]) return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') def _create_batch_list(self, transactions): """ Create the list of batches that the client will send to the REST API Args: transactions (transaction): transaction(s) included in the batch Returns: BatchList: a list of batches to send to the REST API """ transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class TransferClient: def __init__(self, base_url , keyfile = None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as f: private_key_str = f.read().strip() except OSError as err: raise TransferException('Failed to read private key {} : {}'.format(keyfile , str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise TransferException('Failed to load private key : {}'.format(str(err))) self._signer = CryptoFactory(create_context('secp256k1')).new_signer(private_key) def createBox(self, medicineName, medicineID, units, wait = None, auth_user = None, auth_password = None): boxID = ''.join(random.sample('0123456789', 5)) return self._send_transfer_txn( medicineName, medicineID, units, '', '', boxID, self._signer.get_public_key().as_hex(), '', '', '', 'createBox', wait, auth_user, auth_password ) def updateBox(self, medicineName, medicineID, units, boxID, wait = None, auth_user = None, auth_password = None): return self._send_transfer_txn( medicineName, medicineID, units, '', '', boxID, self._signer.get_public_key().as_hex(), '', '', '', 'updateBox', wait, auth_user, auth_password ) def createShipment(self, boxIDArray, origin, destination, wait = None, auth_user = None, auth_password = None): shipmentID = ''.join(random.sample('0123456789', 5)) shipmentStatus = 'CREATED' return self._send_transfer_txn( '', '', '', origin, destination, '', self._signer.get_public_key().as_hex(), shipmentID, boxIDArray, shipmentStatus, 'createShipment', wait, auth_user, auth_password ) def updateShipmentStatus(self, shipmentID, shipmentStatus, wait = None, auth_user = None, auth_password = None): return self._send_transfer_txn( '', '', '', '', '', '', self._signer.get_public_key().as_hex(), shipmentID, '', shipmentStatus, 'updateShipmentStatus', wait, auth_user, auth_password ) def deleteShipment(self, shipmentID, wait = None, auth_user = None, auth_password = None): return self._send_transfer_txn( '', '', '', '', '', '', self._signer.get_public_key().as_hex(), shipmentID, '', '', 'deleteShipment', wait, auth_user, auth_password ) def list(self, auth_user=None, auth_password=None): transfer_prefix = self._get_prefix() result = self._send_request( "state?address={}".format(transfer_prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def show(self, name, auth_user=None, auth_password=None): address = self._get_address(name) result = self._send_request( "state/{}".format(address), name=name, auth_user=auth_user, auth_password=auth_password) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise TransferException(err) def _get_prefix(self): return(_sha512('transfer'.encode('utf-8'))[0:6]) def _get_address(self, name): transfer_prefix = self._get_prefix() transfer_address = _sha512(name.encode('utf-8'))[0:64] return(transfer_prefix + transfer_address) def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise TransferException("No such transfers: {}".format(name)) if not result.ok: raise TransferException("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise TransferException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise TransferException(err) return(result.text) def _send_transfer_txn(self, medicineName, medicineID, units, origin, destination, boxID, logisticsID, shipmentID, boxIDArray, shipmentStatus, action, wait = None, auth_user = None, auth_password =None): payload = ",".join([medicineName, str(medicineID), str(units), origin, destination, str(boxID), str(logisticsID), str(shipmentID), str(boxIDArray), shipmentStatus, action]).encode() addresss = self._get_address(str(shipmentID)) addressb = self._get_address(str(boxID)) if(boxID is None): address = self._get_address(str(shipmentID)) else: address = self._get_address(str(boxID)) med_address = _make_medicine_address(medicineName) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="transfer", family_version="1.0", inputs=[addresss, addressb, address, med_address], outputs=[addresss, addressb, address, med_address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class WalClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException('Failed to read private key {} : {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise XoException('Unable to load priv key') self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self, name, pubkey, wait=None): return self._send_wal_txn(name, "create", pubkey=pubkey, wait=wait) def delete(self, name, pubkey, wait=None): return self._send_wal_txn(name, "delete", pubkey=pubkey, wait=wait) def prof(self, name, profile, wait=None): return self._send_wal_txn(name, "profile", pubkey=profile, wait=wait) def show(self, name): address = self._get_address(name) result = self._send_request("state/{}".format(address), name=name) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait)) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise XoException(err) def _get_prefix(self): return _sha512('wal'.encode('utf-8'))[0:6] def _get_address(self, name): wal_prefix = self._get_prefix() pair_address = _sha512(name.encode('utf-8'))[0:64] return wal_prefix + pair_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such item: {}".format(name)) elif not result.ok: raise XoException("Error {}:{}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException('Failed to connect to {}:{}'.format( url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_wal_txn(self, name, action, pubkey, wait=None): payload = ",".join([name, action, pubkey]).encode() address = self._get_address(name) sec_address = self._get_address(pubkey) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="wal", family_version="1.0", inputs=[address, sec_address], outputs=[address, sec_address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') while wait_time < wait: status = self._get_status(batch_id, wait - int(wait_time)) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class CarLoggerClient(object): '''Client car logger class. This supports create, add, delete, history functions. ''' def __init__(self, baseUrl, private_key=None, vin=''): '''Initialize the client class. This is mainly getting the key pair and computing the address. ''' self._baseUrl = baseUrl try: privateKey = Secp256k1PrivateKey.from_hex(private_key) except ParseError as err: raise Exception('Failed to load private key: {}'.format(str(err))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(privateKey) self._publicKey = self._signer.get_public_key().as_hex() self.VIN = vin self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(self.VIN.encode('utf-8'))[0:64] # For each valid cli command in _cli.py file, # add methods to: # 1. Do any additional handling, if required # 2. Create a transaction and a batch # 2. Send to rest-api def create(self, VIN, keyfile, work_date, brand, model, description): return self._wrap_and_send("create", VIN, keyfile, work_date, brand, model, description) def add(self, VIN, keyfile, work_date, work, km_status, description): return self._wrap_and_send("add", VIN, keyfile, work_date, work, km_status, description) def delete(self, VIN, keyfile, work_date, work, km_status, description): return self._wrap_and_send("delete", VIN, keyfile, work_date, work, km_status, description) def history(self): result = self._send_to_restapi("state/{}".format(self._address)) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _send_to_restapi(self, suffix, data=None, contentType=None): '''Send a REST command to the Validator via the REST API.''' if self._baseUrl.startswith("http://"): url = "{}/{}".format(self._baseUrl, suffix) else: url = "http://{}/{}".format(self._baseUrl, suffix) headers = {} if contentType is not None: headers['Content-Type'] = contentType try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise Exception("Error {}: {}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise Exception('Failed to connect to {}: {}'.format( url, str(err))) except BaseException as err: raise Exception(err) return result.text def _wrap_and_send(self, action, *values): '''Create a transaction, then wrap it in a batch. Even single transactions must be wrapped into a batch. ''' # Generate a csv utf-8 encoded string as payload rawPayload = action for val in values: rawPayload = ",".join([rawPayload, str(val)]) payload = rawPayload.encode() # Construct the address where we'll store our state address = self._address inputAddressList = [address] outputAddressList = [address] # Create a TransactionHeader header = TransactionHeader( signer_public_key=self._publicKey, family_name=FAMILY_NAME, family_version="1.0", inputs=inputAddressList, outputs=outputAddressList, dependencies=[], payload_sha512=_hash(payload), batcher_public_key=self._publicKey, nonce=random.random().hex().encode()).SerializeToString() # Create a Transaction from the header and payload above transaction = Transaction(header=header, payload=payload, header_signature=self._signer.sign(header)) transactionList = [transaction] # Create a BatchHeader from transactionList above header = BatchHeader( signer_public_key=self._publicKey, transaction_ids=[txn.header_signature for txn in transactionList]).SerializeToString() # Create Batch using the BatchHeader and transactionList above batch = Batch(header=header, transactions=transactionList, header_signature=self._signer.sign(header)) # Create a Batch List from Batch above batch_list = BatchList(batches=[batch]) # Send batch_list to rest-api return self._send_to_restapi("batches", batch_list.SerializeToString(), 'application/octet-stream')
class HwClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException('Failed to read private key {} : {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise XoException('Unable to load priv key') self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self, name, cu_add=None, wait=None): return self._send_hw_txn(name, "create", cu_add=self._signer.get_public_key().as_hex(), nxt_add='no', wait=wait) def delete(self, name, wait=None): return self._send_hw_txn(name, "delete", cu_add=self._signer.get_public_key().as_hex(), nxt_add='no', wait=wait) def send(self, name, nxt_add, wait=None): return self._send_hw_txn(name, "send", cu_add=self._signer.get_public_key().as_hex(), nxt_add=nxt_add, wait=wait) def check(self, name, check_no, cu_add, wait=None): return self._send_hw_txn( name, check_no, cu_add=cu_add, nxt_add=self._signer.get_public_key().as_hex(), wait=wait) def show(self, name): address = self._get_address(name) result = self._send_request("state/{}".format(address), name=name) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def _get_status(self, batch_id, wait): try: result = self._send_request('batch_statuses?id={}&wait={}'.format( batch_id, wait)) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise XoException(err) def _get_prefix(self): return _sha512('hw'.encode('utf-8'))[0:6] def _get_address(self, name): hw_prefix = self._get_prefix() item_address = _sha512(name.encode('utf-8'))[0:64] return hw_prefix + item_address def _get_key_address(self, name): wal_prefix = _sha512('wal'.encode('utf-8'))[0:6] key_address = _sha512(name.encode('utf-8'))[0:64] return wal_prefix + key_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such item: {}".format(name)) elif not result.ok: raise XoException("Error {}:{}".format(result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException('Failed to connect to {}:{}'.format( url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_hw_txn(self, name, action, cu_add, nxt_add, wait=None): payload = ",".join([name, action, cu_add, nxt_add]).encode() key_add = self._get_key_address(nxt_add) cli_add = self._get_key_address(cu_add) address = self._get_address(name) #for a transaction processor to access an address in the state database, we have to specify it in #inputs of the transaction header. For a transaction processor to change an element at an address, #we have to specify that address in outputs if key_add is not None: header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="hw", family_version="1.0", inputs=[address, key_add, cli_add], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() else: header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="hw", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode()).SerializeToString() signature = self._signer.sign(header) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') while wait_time < wait: status = self._get_status(batch_id, wait - int(wait_time)) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') #transactions are wrapped as batches. We wait some time to recieve any transactions to come by #If wait time is over , we complete the batch with the transactions recieved until that point and #wrap up the batch creation and push it into the validator rest-api def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures).SerializeToString() signature = self._signer.sign(header) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class CapBACClient: def __init__(self, url, keyfile=None): self.url = url if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise CapBACClientException( 'Failed to read private key: {}'.format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise CapBACClientException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) # For each valid cli commands in _cli.py file # Add methods to: # 1. Do any additional handling, if required # 2. Create a transaction and a batch # 2. Send to rest-api def issue(self, token, is_root): try: token = json.loads(token) except: raise CapBACClientException('Invalid token: serialization failed') return self.issue_from_dict(token, is_root) def issue_from_dict(self,token, is_root): # check the formal validity of the incomplete token subset = set(CAPABILITY_FORMAT) - {'II','SI','VR'} if is_root: subset -= {'IC','SU'} _check_format(token,'capabiliy token',CAPABILITY_FORMAT,subset) for access_right in token['AR']: _check_format(access_right,'capability token: access right',ACCESS_RIGHT_FORMAT) # time interval logical check try: not_before = int(token['NB']) not_after = int(token['NA']) except: raise CapBACClientException('Invalid capability: timestamp not a number') if not_before > not_after: raise CapBACClientException("Invalid capability: incorrect time interval") now = int(time.time()) if now > not_after: raise CapBACClientException("Capability already expired") if is_root: token['IC'] = None token['SU'] = self._signer.get_public_key().as_hex() # add signature token= self.sign_dict(token) # now the token is complete payload = cbor.dumps({ 'AC': "issue", 'OB': token }) return self._send_transaction(payload, token['DE']) def revoke(self, token): try: token = json.loads(token) except: raise CapBACClientException('Invalid revocation token: serialization failed') return self.revoke_from_dict(token) def revoke_from_dict(self, token): # check the formal validity of the incomplete revocation token subset = set(REVOCATION_FORMAT) - {'II','SI','VR'} _check_format(token,'revocation token',REVOCATION_FORMAT,subset) # add signature token = self.sign_dict(token) # now the revocation token is complete payload = cbor.dumps({ 'AC': "revoke", 'OB': token }) return self._send_transaction(payload, token['DE']) def list(self,device): if len(device) > MAX_URI_LENGTH: raise CapBACClientException( 'Invalid URI: max length exceeded, should be less than {}' .format(MAX_URI_LENGTH)) result = self._send_request( "state?address={}".format( self._get_address(device))) try: encoded_entries = yaml.safe_load(result)["data"] data_list = [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] return json.dumps({ x:y[x] for y in data_list for x in y }, indent=4, sort_keys=True) except BaseException: return None def validate(self,token): try: token = json.loads(token) except: raise CapBACClientException('Invalid access token: serialization failed') return self.validate_from_dict(token) def validate_from_dict(self,token): _check_format(token,"access token",VALIDATION_FORMAT) # state retrival device = token['DE'] result = self._send_request( "state?address={}".format( self._get_address(device))) try: encoded_entries = yaml.safe_load(result)["data"] data_list = [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] state = {x:y[x] for y in data_list for x in y} except BaseException: return None LOGGER.info('checking authorization') # check authorization capability = token['IC'] if capability not in state: return False LOGGER.info('checking delegation chain') # delegation chain check now = int(time.time()) resource = token['RE'] action = token['AC'] current_token = state[capability] parent = current_token['IC'] while parent != None: if parent not in state: raise BaseException parent_token = state[parent] # check time interval if now >= int(parent_token['NA']): return False if now < int(parent_token['NB']): return False # check access rights if resource not in parent_token["AR"]: return False if action not in parent_token["AR"][resource]: return False # next current_token = parent_token parent = current_token['IC'] LOGGER.info('checking signature') # check signature signature = token.pop('SI') if not create_context('secp256k1').verify( signature, str(cbor.dumps(token,sort_keys=True)).encode('utf-8'), Secp256k1PublicKey.from_hex(state[capability]['SU']) ): return False return True def sign(self, token): try: token = json.loads(token) except: raise CapBACClientException('Invalid token: serialization failed') token = self.sign_dict(token) return json.dumps(token) def sign_dict(self, token): # add version token['VR'] = FAMILY_VERSION # add issue time now = int(time.time()) token['II'] = str(now) # add signature token_serialized = str(cbor.dumps(token,sort_keys=True)).encode('utf-8') token['SI'] = self._signer.sign(token_serialized) return token def _get_prefix(self): return _sha512(FAMILY_NAME.encode('utf-8'))[0:6] def _get_address(self, device): prefix = self._get_prefix() device_address = _sha512(device.encode('utf-8'))[64:] return prefix + device_address def _send_request(self, suffix, data=None, contentType=None): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if contentType is not None: headers['Content-Type'] = contentType try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: raise CapBACClientException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise CapBACClientException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise CapBACClientException(err) return result.text def _send_transaction(self, payload, device): # Get the unique address for the device's tokens address = self._get_address(device) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name=FAMILY_NAME, family_version=FAMILY_VERSION, inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=time.time().hex().encode() ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream' ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class IntkeyClient: def __init__(self, url, keyfile=None): self.url = url if keyfile is not None: try: with open(keyfile) as fd: private_key_str = fd.read().strip() fd.close() except OSError as err: raise IntkeyClientException( 'Failed to read private key: {}'.format(str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise IntkeyClientException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory( create_context('secp256k1')).new_signer(private_key) def set(self, name, value, wait=None): return self._send_transaction('set', name, value, wait=wait) def inc(self, name, value, wait=None): return self._send_transaction('inc', name, value, wait=wait) def dec(self, name, value, wait=None): return self._send_transaction('dec', name, value, wait=wait) def list(self): result = self._send_request( "state?address={}".format( self._get_prefix())) try: encoded_entries = yaml.safe_load(result)["data"] return [ cbor.loads(base64.b64decode(entry["data"])) for entry in encoded_entries ] except BaseException: return None def show(self, name): address = self._get_address(name) result = self._send_request("state/{}".format(address), name=name,) try: return cbor.loads( base64.b64decode( yaml.safe_load(result)["data"]))[name] except BaseException: return None def _get_status(self, batch_id, wait): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait),) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise IntkeyClientException(err) def _get_prefix(self): return _sha512('intkey'.encode('utf-8'))[0:6] def _get_address(self, name): prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[64:] return prefix + game_address def _send_request(self, suffix, data=None, content_type=None, name=None): if self.url.startswith("http://"): url = "{}/{}".format(self.url, suffix) else: url = "http://{}/{}".format(self.url, suffix) headers = {} if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise IntkeyClientException("No such key: {}".format(name)) elif not result.ok: raise IntkeyClientException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise IntkeyClientException( 'Failed to connect to REST API: {}'.format(err)) except BaseException as err: raise IntkeyClientException(err) return result.text def _send_transaction(self, verb, name, value, wait=None): payload = cbor.dumps({ 'Verb': verb, 'Name': name, 'Value': value, }) # Construct the address address = self._get_address(name) header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="intkey", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), ) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', ) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
class SimpleTestClient: def __init__(self, baseUrl): self._baseUrl = baseUrl privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(privateKey) self._publicKey = self._signer.get_public_key().as_hex() self.publicKey = self._signer.get_public_key().as_hex() self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] # _hash(self._publicKey.encode('utf-8'))[0:64] def wrap_and_send(self, data_dict): # rawPayload = action # for val in values: # rawPayload = ",".join([rawPayload, str(val)]) payload = json.dumps(data_dict).encode() address = self._address inputAddressList = [address] outputAddressList = [address] header = TransactionHeader( signer_public_key=self._publicKey, family_name=FAMILY_NAME, family_version="1.0", inputs=inputAddressList, outputs=outputAddressList, dependencies=[], payload_sha512=_hash(payload), batcher_public_key=self._publicKey, nonce=time.time().hex().encode() ).SerializeToString() transaction = Transaction( header=header, payload=payload, header_signature=self._signer.sign(header) ) transactionList = [transaction] header = BatchHeader( signer_public_key=self._publicKey, transaction_ids=[txn.header_signature for txn in transactionList] ).SerializeToString() batch = Batch( header=header, transactions=transactionList, header_signature=self._signer.sign(header)) batch_list = BatchList(batches=[batch]) return self._send_to_restapi( "batches", batch_list.SerializeToString(), 'application/octet-stream') def _send_to_restapi(self, suffix, data=None, contentType=None): if self._baseUrl.startswith("http://"): url = "{}/{}".format(self._baseUrl, suffix) else: url = "http://{}/{}".format(self._baseUrl, suffix) headers = {} if contentType is not None: headers['Content-Type'] = contentType try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if not result.ok: print('服务器错误') except requests.ConnectionError as err: print('连接失败',err) # raise SimpleWalletException( # 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: # raise SimpleWalletException(err) print(err) return result.text def get_state(self): result = self._send_to_restapi( "state/{}".format(self._address)) print(result) try: return base64.b64decode(yaml.safe_load(result)["data"]) except BaseException: return None def get_block(self): result = requests.get(self._baseUrl+'/blocks') datas = result.json()['data'] for data in datas: # print(data) payload = data['batches'][0]['transactions'][0]['payload'] # print(payload) p = base64.b64decode(payload.encode()).decode() try: print(json.loads(p)) except: pass
class HdfssbClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException( 'Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise XoException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self._publicKey = self._signer.get_public_key().as_hex() self._address_file = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \ _hash(self._publicKey.encode('utf-8'))[0:64] def get_public_key(self): return self._publicKey def _get_prefix(self): return _sha512('hdfssb'.encode('utf-8'))[0:6] def _get_prefix_file(self): return _sha512('file'.encode('utf-8'))[0:4] def _get_prefix_node(self): return _sha512('node'.encode('utf-8'))[0:4] def _get_address_file(self, name): hdfssb_prefix = self._get_prefix() file_prefix = self._get_prefix_file() name_hash = _sha512(name.encode('utf-8'))[0:60] return hdfssb_prefix + file_prefix + name_hash def _get_address_node(self, name): hdfssb_prefix = self._get_prefix() node_prefix = self._get_prefix_node() name_hash = _sha512(name.encode('utf-8'))[0:60] return hdfssb_prefix + node_prefix + name_hash def add_file(self, name, payload_object, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name=name, address=self._get_address_file(name), payload_object=payload_object, action="add_file", wait=wait, auth_user=auth_user, auth_password=auth_password) def delete_file(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name, None, "delete_file", wait=wait, auth_user=auth_user, auth_password=auth_password) def add_node(self, name, payload_object, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name=name, address=self._get_address_node(name), payload_object=payload_object, action="add_node", wait=wait, auth_user=auth_user, auth_password=auth_password) def delete_node(self, name, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name, None, "delete_node", wait=wait, auth_user=auth_user, auth_password=auth_password) def update_node(self, name, taken_space, wait=None, auth_user=None, auth_password=None): return self._send_xo_txn( name=name, payload_object={'taken_space': taken_space}, action="update_node", wait=wait, auth_user=auth_user, auth_password=auth_password) def list_files(self, auth_user=None, auth_password=None): hdfssb_prefix = self._get_prefix() file_prefix = self._get_prefix_file() result = self._send_request( "state?address={}".format(hdfssb_prefix + file_prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def list_files_decoded(self): list_files = self.list_files() files = {} try: for node in list_files: file_name, owner, state, state, size, file_hash, blocks_str, checksums, data_bytes, oti_common, oti_scheme, last_update = node.decode().split(",") blocks = blocks_str.split("+") blocks_of_file = {} for pair in blocks: block, node = pair.split(":") blocks_of_file[block] = node files[file_name] = [file_name, owner, state, size, file_hash, blocks_of_file, checksums, data_bytes, oti_common, oti_scheme, last_update] except ValueError: raise InternalError("Failed to deserialize game data") return files def list_nodes(self, auth_user=None, auth_password=None): hdfssb_prefix = self._get_prefix() node_prefix = self._get_prefix_node() result = self._send_request( "state?address={}".format(hdfssb_prefix + node_prefix), auth_user=auth_user, auth_password=auth_password) try: encoded_entries = yaml.safe_load(result)["data"] return [ base64.b64decode(entry["data"]) for entry in encoded_entries ] except BaseException: return None def list_nodes_decoded(self, auth_user=None, auth_password=None): list_nodes = self.list_nodes(auth_user, auth_password) nodes = {} try: for node in list_nodes: node_name, cluster, capacity, taken_space, reversed_space, last_update = node.decode().split( ",") nodes[node_name] = {'node_name': node_name, 'cluster': cluster, 'capacity': capacity, 'taken_space': taken_space, 'reversed_space': reversed_space, 'last_update': last_update} except ValueError: raise InternalError("Failed to deserialize game data") return nodes def show_file(self, name, auth_user=None, auth_password=None): address = self._get_address_file(name) result = self._send_request( "state/{}".format(address), name=name, auth_user=auth_user, auth_password=auth_password) try: file = base64.b64decode(yaml.safe_load(result)["data"]) file_name, owner, state, state, size, file_hash, blocks_str, checksums, data_bytes, oti_common, oti_scheme, last_update = file.decode().split(",") blocks = blocks_str.split("+") blocks_of_file = {} for pair in blocks: block, node = pair.split(":") blocks_of_file[block] = node file_json = {"file_name": file_name, 'owner': owner, 'state': state, 'size': size, 'file_hash': file_hash, 'blocks_of_file': blocks_of_file, 'checksums': checksums, 'data_bytes': data_bytes, 'oti_common': oti_common, 'oti_scheme': oti_scheme, 'last_update': last_update} #head = {'checksums': {"sha256": checksums}, 'data_bytes': int(data_bytes), 'oti_common': int(oti_common), 'oti_scheme': int(oti_scheme)} return file_json except BaseException: return None except ValueError: raise InternalError("Failed to deserialize game data") def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such game: {}".format(name)) if not result.ok: raise XoException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_xo_txn(self, name, address, payload_object, action, wait=None, auth_user=None, auth_password=None): if payload_object is None: payload_object = name json_payload = json.dumps({'action': action, 'payload': payload_object}) payload = json_payload.encode() header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="hdfssb", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2 ** 64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch]) def wait_for_transaction(self, link): link = json.loads(link)["link"] status = "PENDING" limit = 30 numer_attamps = 0 while status == "PENDING" and numer_attamps < limit: result = requests.get(link) text_result = json.loads(result.text) status = text_result["data"][0]["status"] print(status) numer_attamps += 1 time.sleep(1)
class CaClient: def __init__(self, base_url, keyfile=None): self._base_url = base_url if keyfile is None: self._signer = None return try: with open(keyfile) as fd: private_key_str = fd.read().strip() except OSError as err: raise XoException( 'Failed to read private key {}: {}'.format( keyfile, str(err))) try: private_key = Secp256k1PrivateKey.from_hex(private_key_str) except ParseError as e: raise XoException( 'Unable to load private key: {}'.format(str(e))) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) def create(self, csr, wait=None, auth_user=None, auth_password=None): return self._send_ca_txn( "create", value=csr, wait=wait, auth_user=auth_user, auth_password=auth_password) def init(self, pkey, wait=None, auth_user=None, auth_password=None): return self._send_ca_txn( "init", value=pkey, wait=wait, auth_user=auth_user, auth_password=auth_password) def simple(self, data, wait=None, auth_user=None, auth_password=None): return self._send_simple_txn( value=data, wait=wait, auth_user=auth_user, auth_password=auth_password) def get(self, serial: str, wait=None, auth_user=None, auth_password=None): return self._send_ca_txn( "get", value=serial, wait=wait, auth_user=auth_user, auth_password=auth_password) def status(self, serial: str, wait=None, auth_user=None, auth_password=None): return self._send_ca_txn( "status", value=serial, wait=wait, auth_user=auth_user, auth_password=auth_password) def revoke(self, serial: str, wait=None, auth_user=None, auth_password=None): return self._send_ca_txn( "revoke", value=serial, wait=wait, auth_user=auth_user, auth_password=auth_password) def _get_status(self, batch_id, wait, auth_user=None, auth_password=None): try: result = self._send_request( 'batch_statuses?id={}&wait={}'.format(batch_id, wait), auth_user=auth_user, auth_password=auth_password) return yaml.safe_load(result)['data'][0]['status'] except BaseException as err: raise XoException(err) def _get_prefix(self): return _sha512('ca_1'.encode('utf-8'))[:6] def _get_address(self, name): xo_prefix = self._get_prefix() game_address = _sha512(name.encode('utf-8'))[:64] return xo_prefix + game_address def _get_simple_address(self, data): prefix = hashlib.sha512('simple'.encode('utf-8')).hexdigest()[:6] address = hashlib.sha512(data.encode('utf-8')).hexdigest()[:64] return prefix + address def _send_request(self, suffix, data=None, content_type=None, name=None, auth_user=None, auth_password=None): if self._base_url.startswith("http://"): url = "{}/{}".format(self._base_url, suffix) else: url = "http://{}/{}".format(self._base_url, suffix) headers = {} if auth_user is not None: auth_string = "{}:{}".format(auth_user, auth_password) b64_string = b64encode(auth_string.encode()).decode() auth_header = 'Basic {}'.format(b64_string) headers['Authorization'] = auth_header if content_type is not None: headers['Content-Type'] = content_type try: if data is not None: result = requests.post(url, headers=headers, data=data) else: result = requests.get(url, headers=headers) if result.status_code == 404: raise XoException("No such game: {}".format(name)) elif not result.ok: raise XoException("Error {}: {}".format( result.status_code, result.reason)) except requests.ConnectionError as err: raise XoException( 'Failed to connect to {}: {}'.format(url, str(err))) except BaseException as err: raise XoException(err) return result.text def _send_ca_txn(self, action, value="", wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string payload = "|".join([action, datetime.datetime.utcnow().isoformat(), str(value)]).encode('utf-8') # Construct the address address = self._get_prefix() header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name="CA", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _send_simple_txn(self, value="", wait=None, auth_user=None, auth_password=None): # Serialization is just a delimited utf-8 encoded string payload = str(value).encode() # Construct the address address = self._get_simple_address('Simple Data Value 1') header = TransactionHeader( signer_public_key=self._signer.get_public_key().as_hex(), family_name='SIMPLE', family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_sha512=_sha512(payload), batcher_public_key=self._signer.get_public_key().as_hex(), nonce=hex(random.randint(0, 2**64)) ).SerializeToString() signature = self._signer.sign(header) transaction = Transaction( header=header, payload=payload, header_signature=signature ) batch_list = self._create_batch_list([transaction]) batch_id = batch_list.batches[0].header_signature if wait and wait > 0: wait_time = 0 start_time = time.time() response = self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) while wait_time < wait: status = self._get_status( batch_id, wait - int(wait_time), auth_user=auth_user, auth_password=auth_password) wait_time = time.time() - start_time if status != 'PENDING': return response return response return self._send_request( "batches", batch_list.SerializeToString(), 'application/octet-stream', auth_user=auth_user, auth_password=auth_password) def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_public_key=self._signer.get_public_key().as_hex(), transaction_ids=transaction_signatures ).SerializeToString() signature = self._signer.sign(header) batch = Batch( header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch]) def subscribe(self, event_name: str, is_write_to_file=False, file_name='certificate.pem'): subscription = EventSubscription(event_type="ca_1/{}".format(event_name)) # Setup a connection to the validator ctx = zmq.Context() socket = ctx.socket(zmq.DEALER) socket.connect('tcp://127.0.0.1:4004') # Construct the request request = ClientEventsSubscribeRequest( subscriptions=[subscription]).SerializeToString() # Construct the message wrapper correlation_id = "123" # This must be unique for all in-process requests msg = Message( correlation_id=correlation_id, message_type=Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST, content=request) # Send the request socket.send_multipart([msg.SerializeToString()]) # Receive the response resp = socket.recv_multipart()[-1] # Parse the message wrapper msg = Message() msg.ParseFromString(resp) # Validate the response type if msg.message_type != Message.CLIENT_EVENTS_SUBSCRIBE_RESPONSE: print("Unexpected message type") return # Parse the response response = ClientEventsSubscribeResponse() response.ParseFromString(msg.content) # Validate the response status if response.status != ClientEventsSubscribeResponse.OK: print("Subscription failed: {}".format(response.response_message)) return resp = socket.recv_multipart()[-1] # Parse the message wrapper msg = Message() msg.ParseFromString(resp) # Validate the response type if msg.message_type != Message.CLIENT_EVENTS: print("Unexpected message type") return # Parse the response events = EventList() events.ParseFromString(msg.content) for event in events.events: if event.data is not None: if is_write_to_file: write_to_file(file_name, event.data) else: print(event.data) # Construct the request request = ClientEventsUnsubscribeRequest().SerializeToString() # Construct the message wrapper correlation_id = "124" # This must be unique for all in-process requests msg = Message( correlation_id=correlation_id, message_type=Message.CLIENT_EVENTS_UNSUBSCRIBE_REQUEST, content=request) # Send the request socket.send_multipart([msg.SerializeToString()]) # Receive the response resp = socket.recv_multipart()[-1] # Parse the message wrapper msg = Message() msg.ParseFromString(resp) # Validate the response type if msg.message_type != Message.CLIENT_EVENTS_UNSUBSCRIBE_RESPONSE: print("Unexpected message type") # Parse the response response = ClientEventsUnsubscribeResponse() response.ParseFromString(msg.content) # Validate the response status if response.status != ClientEventsUnsubscribeResponse.OK: print("Unsubscription failed: {}".format(response.response_message)) # Close the connection to the validator socket.close()