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
async def create_account(request): """Creates a new Account and corresponding authorization token""" required_fields = ['email', 'password'] common.validate_fields(required_fields, request.json) private_key = request.app.config.CONTEXT.new_random_private_key() signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key) public_key = signer.get_public_key().as_hex() auth_entry = _create_auth_dict(request, public_key, private_key.as_hex()) await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry) account = _create_account_dict(request.json, public_key) batches, batch_id = transaction_creation.create_account( txn_key=signer, batch_key=request.app.config.SIGNER, label=account.get('label'), description=account.get('description')) await messaging.send(request.app.config.VAL_CONN, request.app.config.TIMEOUT, batches) try: await messaging.check_batch_status(request.app.config.VAL_CONN, batch_id) except (ApiBadRequest, ApiInternalError) as err: await auth_query.remove_auth_entry(request.app.config.DB_CONN, request.json.get('email')) raise err token = common.generate_auth_token(request.app.config.SECRET_KEY, account.get('email'), public_key) return response.json({'authorization': token, 'account': account})
async def create_account(request): """Creates a new Account and corresponding authorization token""" # required_fields = ['email', 'password'] # common.validate_fields(required_fields, request.json) privateKey = request.app.config.CONTEXT.new_random_private_key() signer = CryptoFactory(request.app.config.CONTEXT).new_signer(privateKey) public_key = signer.get_public_key().as_hex() private_key = signer.get_public_key().as_hex() # auth_entry = _create_auth_dict( # request, public_key, private_key.as_hex()) # await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry) # account = _create_account_dict(request.json, public_key) # batches, batch_id = transaction_creation.create_account( # txn_key=signer, # batch_key=request.app.config.SIGNER, # label=account.get('label'), # description=account.get('description')) # await messaging.send( # request.app.config.VAL_CONN, # request.app.config.TIMEOUT, # batches) # try: # await messaging.check_batch_status( # request.app.config.VAL_CONN, batch_id) # except (ApiBadRequest, ApiInternalError) as err: # await auth_query.remove_auth_entry( # request.app.config.DB_CONN, request.json.get('email')) # raise err # token = common.generate_auth_token( # request.app.config.SECRET_KEY, # account.get('email'), # public_key) print('private_key', private_key) print('public_key', public_key) return response.json({ 'private_key': private_key, 'public_key': public_key })
def apply(self, transaction, context): '''This implements the apply function for this transaction handler. This function does most of the work for this class by processing a single transaction for the carLogger transaction family. ''' LOGGER.debug("start" ) # Get the payload and extract carLogger-specific information. header = transaction.header from_key = header.signer_public_key payload_list = transaction.payload.decode().split(",") operation = payload_list[0] VIN = payload_list[1] signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(Secp256k1PrivateKey.from_hex(payload_list[2])) work_date = payload_list[3] company = signer.get_public_key().as_hex() log = VehicleLog(VIN=VIN, worker=company, work_date=work_date) # Perform the operation. LOGGER.info("Operation = "+ operation) if operation == "add": work = payload_list[4] km_status = payload_list[5] description = payload_list[6] log.work = work log.mileage = km_status log.description = description log.timestamp = str(time.strftime("%Y-%m-%d %H:%M")) self._add(context, log) elif operation == "delete": work = payload_list[4] km_status = payload_list[5] description = payload_list[6] log.mileage = km_status log.description = description log.timestamp = str(time.strftime("%Y-%m-%d %H:%M")) deleted_work='' for number in work.split("|"): deleted_work = deleted_work + str(-1*int(number)) log.work = deleted_work self._delete(context, log) elif operation == "create": brand = payload_list[4] model = payload_list[5] description = payload_list[6] log.mileage = 0 log.work = '0' log.description = description log.brand = brand log.model = model log.timestamp = str(time.strftime("%Y-%m-%d %H:%M")) self._create(context,log) else: LOGGER.info("Unhandled action. Operation should be add, delete, create or history")
async def create_asset(request): required_fields = [ "user_id", "password", "file_name", "file_hash", "base64_file_bytes" ] common.validate_fields(required_fields, request.json) file_exist = await asset_query.fetch_info_by_filehash( request.app.config.DB_CONN, request.json["file_hash"]) if file_exist: raise ApiInternalError("file already exist. Try again later") file_bytes = base64.b64decode(request.json["base64_file_bytes"]) mnemonic, address, account = await accounts_utils.get_account_details( request) childkey_index = common.gen_childkey_index() child_private_key, child_public_key = await remote_api.get_child_key( mnemonic, childkey_index) private_hex_key, public_hex_key = await remote_api.get_child_key( mnemonic, request.app.config.ROOT_KEY_INDEX) private_key = Secp256k1PrivateKey.from_hex(private_hex_key) signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key) public_key = signer.get_public_key().as_hex() aes_key = encryption.generate_aes_key(16) ciphertext, tag, nonce = encryption.aes_encrypt(aes_key, file_bytes) ciphertext = b"".join([tag, ciphertext, nonce]) secrets = binascii.hexlify(ciphertext) struct = { "file_hash": request.json["file_hash"], "file_name": request.json["file_name"], "file_cipher_hex": secrets.decode() } s3_key = amazon_s3.generate_s3_key(request.json["user_id"], request.json["file_name"]) s3_url = amazon_s3.store_s3(request, s3_key, request.json["user_id"], struct)
async def generate_asset_address(request): required_fields = ["user_id", "password"] common.validate_fields(required_fields, request.json) mnemonic, address, account = await accounts_utils.get_account_details( request) # print(type(account)) childkey_index = common.gen_childkey_index() if "keys" in account.keys(): while childkey_index in account["keys"]: childkey_index = common.gen_childkey_index() else: childkey_index = common.gen_childkey_index() child_private_key, child_public_key = await remote_api.get_child_key( mnemonic, childkey_index) private_hex_key, public_hex_key = await remote_api.get_child_key( mnemonic, request.app.config.ROOT_KEY_INDEX) private_key = Secp256k1PrivateKey.from_hex(private_hex_key) # private_key = request.app.config.CONTEXT.new_random_private_key() signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key) public_key = signer.get_public_key().as_hex() batches, batch_id, batch_list_bytes = transaction_creation.create_empty_asset( txn_key=signer, batch_key=request.app.config.SIGNER, key_index=childkey_index, child_public_key=child_public_key, is_empty_asset=True) # print(batch_list_bytes) data = await messaging.send(batch_list_bytes, request) try: await messaging.wait_for_status(batch_id, 300, request) except (ApiBadRequest, ApiInternalError) as err: raise err token = common.generate_auth_token(request.app.config.SECRET_KEY, child_private_key, public_key) # print(token) return response.json({'authorization': token, 'key_index': childkey_index})
def generate_signer(keyfile=None, pubkey_file=None): context = create_context('secp256k1') private_key = context.new_random_private_key() signer = None if keyfile: try: with open(keyfile, 'w') as fd: fd.write(private_key.as_hex()) with open(pubkey_file, 'w') as fd: signer = CryptoFactory(context).new_signer(private_key) fd.write(signer.get_public_key().as_hex()) except OSError as err: raise ClientException(f'Failed to write private key: {err}') if not signer: signer = CryptoFactory(context).new_signer(private_key) return CryptoFactory(context).new_signer(private_key)
async def create_account(request): """Creates a new Account and corresponding authorization token""" required_fields = ['email', 'password'] common.validate_fields(required_fields, request.json) private_key = request.app.config.CONTEXT.new_random_private_key() signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key) public_key = signer.get_public_key().as_hex() auth_entry = _create_auth_dict( request, public_key, private_key.as_hex()) await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry) account = _create_account_dict(request.json, public_key) batches, batch_id = transaction_creation.create_account( txn_key=signer, batch_key=request.app.config.SIGNER, label=account.get('label'), description=account.get('description')) await messaging.send( request.app.config.VAL_CONN, request.app.config.TIMEOUT, batches) try: await messaging.check_batch_status( request.app.config.VAL_CONN, batch_id) except (ApiBadRequest, ApiInternalError) as err: await auth_query.remove_auth_entry( request.app.config.DB_CONN, request.json.get('email')) raise err token = common.generate_auth_token( request.app.config.SECRET_KEY, account.get('email'), public_key) return response.json( { 'authorization': token, 'account': account })
def search(): keys = [] for file in glob(f'{KEY_DIR}/*.priv'): try: with open(file) as f: contents = f.read().strip() private_key = Secp256k1PrivateKey.from_hex(contents) context = create_context('secp256k1') signer = CryptoFactory(context).new_signer(private_key) keys.append({ 'name': os.path.splitext(os.path.basename(file))[0], 'pub_key': signer.get_public_key().as_hex() }) except OSError: return {'error': f'Cannot read private key file {file}'}, 400 except ParseError: return { 'error': f'Cannot parse contents of private key file {file}' }, 400 return {'keys': keys}
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])
from sawtooth_sdk.protobuf.transaction_pb2 import TransactionHeader from sawtooth_sdk.protobuf.transaction_pb2 import Transaction import sawtooth_sdk from sawtooth_signing import create_context from sawtooth_signing import CryptoFactory from sawtooth_sdk.protobuf.batch_pb2 import BatchHeader from sawtooth_sdk.protobuf.batch_pb2 import Batch from sawtooth_sdk.protobuf.batch_pb2 import BatchList #Creates a signer who will sign the tx and validate #its identity in front of the validator context = create_context('secp256k1') private_key = context.new_random_private_key() signer = CryptoFactory(context).new_signer(private_key) print("SIGNER ES: {}".format(signer.get_public_key().as_hex())) #Checks for correct amount of parameters if len(sys.argv) != 3: print("Use: ./send_tx NumOfBatches NumOfTxPerBatch") sys.exit(1) NUM_BATCHES = int(sys.argv[1]) NUM_TX_PER_BATCH = int(sys.argv[2]) #Generate the payload of the tx #Every family has a structure to follow #Uses the cbor format N = 10
def apply(self, transaction, context): header = transaction.header payload_cbor = transaction.payload payload = cbor.loads(payload_cbor) listo = payload.split(',') if listo[0] == "CREATE": amount = listo[2] code = listo[3] image = listo[1] aadhar = listo[4] account_number = listo[5] name = listo[6] message = listo[7] key = listo[8] LOGGER.info("\n the code is " + code) wallet_address = self._get_wallet_address(code) LOGGER.info("\n THe code is " + code) stop_encode = payload.encode('utf-8') current_entry = context.get_state([wallet_address]) if current_entry == []: LOGGER.info('Yes it can be done') addresses = context.set_state({wallet_address: stop_encode}) if len(addresses) < 1: raise InternalError("State Error") else: raise InternalError("Already built") elif listo[0] == "PAY": LOGGER.info("The length of the is" + str(len(listo))) amount = listo[2] image = listo[1] code = listo[3] pub_pos = listo[4] wallet_address = self._get_wallet_address(code) pub_pos = self._get_wallet_address(pub_pos) current_entry = context.get_state([wallet_address]) current_entry2 = context.get_state([pub_pos]) if current_entry == []: raise InvalidTransaction( 'No user with this key was registered') elif current_entry2 == []: raise InvalidTransaction( 'No user with this key pos was registered') else: splito = current_entry[0].data.decode('utf-8') splito2 = current_entry2[0].data.decode('utf-8') current_list = splito.split(',') current_list2 = splito2.split(',') LOGGER.info("The amount is " + amount) if int(current_list[2]) >= int(amount): image1 = base64.b64decode(current_list[1]) image2 = base64.b64decode(image) files = {'image': image1, 'image2': image2} text = requests.post("http://finger-api:5000/", files=files).text if text == "true": current_list[2] = str( int(current_list[2]) - int(amount)) temp = ','.join(current_list).encode('utf-8') current_list2[2] = str( int(current_list2[2]) + int(amount)) temp2 = ','.join(current_list2).encode('utf-8') context.set_state({wallet_address: temp}) context.set_state({pub_pos: temp2}) key1 = current_list[8] message1 = current_list[7] key2 = current_list2[8] message2 = current_list2[7] file = open("priv.txt", 'r') privkey = file.read()[0:-1] file.close() contexta = create_context('secp256k1') pvkey = Secp256k1PrivateKey.from_hex(privkey) signer = CryptoFactory(contexta).new_signer(pvkey) signer_public_key = signer.get_public_key() #LOGGER.debug("GUCHI "+key1+" "+message1+" "+signer_public_key) dtg = contexta.verify(key1, str.encode(message1), signer_public_key) btg = contexta.verify(key2, str.encode(message2), signer_public_key) if dtg: LOGGER.info("dtg") requests.get( "http://bank-api:8080/event?type=withdraw&amount={}&account_no={}" .format(amount, current_list[5])) if btg: LOGGER.info("btg") requests.get( "http://bank-api:8080/event?type=deposit&amount={}&account_no={}" .format(amount, current_list2[5])) LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS " + context.get_state([wallet_address]) [0].data.decode('utf-8').split(',')[2]) else: raise InvalidTransaction('Fingerprint Does not Match') else: raise InvalidTransaction('Less money in bankaccount') elif listo[0] == "ADD": LOGGER.info("IN the ADD") LOGGER.info("The length of the is" + str(len(listo))) code = listo[2] amount = listo[1] wallet_address = self._get_wallet_address(code) current_entry = context.get_state([wallet_address]) if current_entry == []: LOGGER.info("This was invalid") raise InvalidTransaction( 'No user with this key was registered') else: splito = current_entry[0].data.decode('utf-8') current_list = splito.split(',') current_list[2] = str(int(current_list[2]) + int(amount)) temp = ','.join(current_list).encode('utf-8') LOGGER.debug("the amount is " + amount) LOGGER.info("the amount is " + amount) context.set_state({wallet_address: temp}) LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS " + context.get_state([wallet_address])[0].data.decode( 'utf-8').split(',')[2]) elif listo[0] == "WITHD": code = listo[2] amount = listo[1] wallet_address = self._get_wallet_address(code) current_entry = context.get_state([wallet_address]) if current_entry == []: LOGGER.info("This was invalid") raise InvalidTransaction( 'No user with this key was registered') else: splito = current_entry[0].data.decode('utf-8') current_list = splito.split(',') if int(amount) <= int(current_list[2]): current_list[2] = str(int(current_list[2]) - int(amount)) temp = ','.join(current_list).encode('utf-8') LOGGER.debug("the amount is " + amount) LOGGER.info("the amount is " + amount) context.set_state({wallet_address: temp}) LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS " + context.get_state([wallet_address]) [0].data.decode('utf-8').split(',')[2]) else: raise InvalidTransaction('LOW BALANCE')
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 Transactor: def __init__(self, name, rest_endpoint): """ Args: name (str): An identifier for this Transactor rest_endpoint (str): The rest api that this Transactor will communicate with. """ self.name = name self._rest_endpoint = rest_endpoint \ if rest_endpoint.startswith("http://") \ else "http://{}".format(rest_endpoint) with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file: private_key = Secp256k1PrivateKey.from_hex( priv_file.read().strip('\n')) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self._factories = {} self._client = RestClient(url=self._rest_endpoint) self._add_transaction_family_factory(Families.INTKEY) self._add_transaction_family_factory(Families.XO) @property def public_key(self): return self._signer.get_public_key().as_hex() def _add_transaction_family_factory(self, family_name): """Add a MessageFactory for the specified family. Args: family_name (Families): One of the Enum values representing transaction families. """ family_config = FAMILY_CONFIG[family_name] self._factories[family_name] = MessageFactory( family_name=family_config['family_name'], family_version=family_config['family_version'], namespace=family_config['namespace'], signer=self._signer) def create_txn(self, family_name, batcher=None): unique_value = uuid4().hex[:20] encoder = TRANSACTION_ENCODER[family_name]['encoder'] payload = encoder( TRANSACTION_ENCODER[family_name]['payload_func'](unique_value)) address = TRANSACTION_ENCODER[family_name]['address_func']( unique_value) return self._factories[family_name].create_transaction( payload=payload, inputs=[address], outputs=[address], deps=[], batcher=batcher) def create_batch(self, family_name, count=1): transactions = [self.create_txn(family_name) for _ in range(count)] return self.batch_transactions(family_name, transactions=transactions) def batch_transactions(self, family_name, transactions): return self._factories[family_name].create_batch( transactions=transactions) def send(self, family_name, transactions=None): if not transactions: batch_list = self.create_batch(family_name) else: batch_list = self.batch_transactions(family_name=family_name, transactions=transactions) self._client.send_batches(batch_list=batch_list) def set_public_key_for_role(self, policy, role, permit_keys, deny_keys): permits = ["PERMIT_KEY {}".format(key) for key in permit_keys] denies = ["DENY_KEY {}".format(key) for key in deny_keys] self._run_identity_commands(policy, role, denies + permits) def _run_identity_commands(self, policy, role, rules): subprocess.run([ 'sawtooth', 'identity', 'policy', 'create', '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15', '--url', self._rest_endpoint, policy, *rules ], check=True) subprocess.run([ 'sawtooth', 'identity', 'role', 'create', '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15', '--url', self._rest_endpoint, role, policy ], check=True)
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()
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 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 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 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 Transactor(object): def __init__(self, name, rest_endpoint): """ Args: name (str): An identifier for this Transactor rest_endpoint (str): The rest api that this Transactor will communicate with. """ self.name = name self._rest_endpoint = rest_endpoint \ if rest_endpoint.startswith("http://") \ else "http://{}".format(rest_endpoint) with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file: private_key = Secp256k1PrivateKey.from_hex( priv_file.read().strip('\n')) self._signer = CryptoFactory(create_context('secp256k1')) \ .new_signer(private_key) self._factories = {} self._client = RestClient(url=self._rest_endpoint) self._add_transaction_family_factory(Families.INTKEY) self._add_transaction_family_factory(Families.XO) @property def public_key(self): return self._signer.get_public_key().as_hex() def _add_transaction_family_factory(self, family_name): """Add a MessageFactory for the specified family. Args: family_name (Families): One of the Enum values representing transaction families. """ family_config = FAMILY_CONFIG[family_name] self._factories[family_name] = MessageFactory( family_name=family_config['family_name'], family_version=family_config['family_version'], namespace=family_config['namespace'], signer=self._signer) def create_txn(self, family_name, batcher=None): unique_value = uuid4().hex[:20] encoder = TRANSACTION_ENCODER[family_name]['encoder'] payload = encoder( TRANSACTION_ENCODER[family_name]['payload_func'](unique_value)) address = TRANSACTION_ENCODER[family_name]['address_func']( unique_value) return self._factories[family_name].create_transaction( payload=payload, inputs=[address], outputs=[address], deps=[], batcher=batcher) def create_batch(self, family_name, count=1): transactions = [self.create_txn(family_name) for _ in range(count)] return self.batch_transactions(family_name, transactions=transactions) def batch_transactions(self, family_name, transactions): return self._factories[family_name].create_batch( transactions=transactions) def send(self, family_name, transactions=None): if not transactions: batch_list = self.create_batch(family_name) else: batch_list = self.batch_transactions( family_name=family_name, transactions=transactions) self._client.send_batches(batch_list=batch_list) def set_public_key_for_role(self, policy, role, permit_keys, deny_keys): permits = ["PERMIT_KEY {}".format(key) for key in permit_keys] denies = ["DENY_KEY {}".format(key) for key in deny_keys] self._run_identity_commands(policy, role, denies + permits) def _run_identity_commands(self, policy, role, rules): subprocess.run( ['sawtooth', 'identity', 'policy', 'create', '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15', '--url', self._rest_endpoint, policy, *rules], check=True) subprocess.run( ['sawtooth', 'identity', 'role', 'create', '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15', '--url', self._rest_endpoint, role, policy], check=True)
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 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 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 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 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 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 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 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])
def generate_ecdsa_keys(): context = create_context('secp256k1') sk = CryptoFactory(context).new_signer(context.new_random_private_key()) return sk, sk.get_public_key().as_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 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 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, 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)
private_key = context.new_random_private_key() signer = CryptoFactory(context).new_signer(private_key) #encode payload #simple payload, name and owner payload = {'action': 'create', 'asset': 'test', 'owner': 'test1'} payload_bytes = cbor.dumps(payload) #create transaction headers txn_header_bytes = TransactionHeader( family_name='code-smell', family_version='0.1', inputs=['19d832'], 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)
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 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 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])