def get_flt_account(self, public_key, index): address = addresser.float_account_address(account_id=public_key, index=index) ##entries will be a weird list of the form ##[address: "318c9fa5d39e9ccd2769115795e384b8e83b3267172ae518136ac49ddc5adf71d87814" ##data: "\nB02dbf0f4a3defef38df754122ef7c10fee6a4bb363312367524f86d230e205d459\022$b6de5d5b-7870-49df-971e-0885986bfa96\032 ##\006seller\"\021978-0-9956537-6-4*\0161-191-790-04532\r1-932866-82-5:\001\000"] entries = self._context.get_state(addresses=[address], timeout=self._timeout) try: entry = entries[0] logging.info("float_account data corresponding to \ {} is {}".format(address, entry)) except Exception as e: logging.info("float_account data corresponding to \ {} is {}".format(address, None)) return False float_account = create_empty_float_account() float_account.ParseFromString(entry.data) logging.info("This is the float_account stored on blockchain \ {}".format(float_account)) return float_account
def set_float_account(self, **input_data): """ parent_pub=header.signer_public_key, pancard=float_account.pancard, phone_number=float_account.phone_number, email=float_account.email, claimed=float_account.claimed, claimed_by=float_account.claimed_by, create_asset_index=create_asset_index.float_account, parent_idx=float_account.parent_idx, time=float_account.time, //when this float account transaction was created indian_time=float_account.indian_time, claimed_on=float_account.claimed_on, parent_role=float_account.parent_role, user_role=float_account.user_role """ logging.info("Paylaod from set_float_account {}".format(input_data)) if input_data["parent_role"] != "ADMIN": ##change idx in the account present at public key input_data["parent_zero_pub"] self.set_float_account_idxs(input_data["parent_zero_pub"], input_data["parent_idx"]) ##here the parent pub is the nth index key of the parent on thich ##this float account address is generated address = addresser.float_account_address( account_id=input_data["parent_pub"], index=input_data["parent_idx"]) float_account = create_empty_float_account() logging.info("This is the value of create_asset_idxs \ {}".format(input_data['create_asset_idxs'])) float_account.pancard = input_data["pancard"] float_account.phone_number = input_data["phone_number"] float_account.email = input_data["email"] float_account.claimed = input_data["claimed"] float_account.claimed_by = input_data["claimed_by"] ##this is not required because create_asset_idxs will wlays be empty ##when intilizing float_account #float_account.create_asset_idxs=input_data["create_asset_idxs"] float_account.parent_idx = input_data["parent_idx"] float_account.time = input_data["time"] float_account.indian_time = input_data["indian_time"] float_account.claimed_on = input_data["claimed_on"] float_account.parent_pub = input_data["parent_pub"] float_account.parent_role = input_data["parent_role"] float_account.user_role = input_data["user_role"] logging.info(float_account) logging.info("Account after serialization %s", float_account.SerializeToString()) return self._context.set_state( {address: float_account.SerializeToString()}, self._timeout)
async def float_account_addresses(self): float_account_idxs, nth_keys = await self.indexes_n_pub_priv_pairs( "float_account_idxs") address_list = [] address_list = [] nth_keys = await remote_calls.key_index_keys(self.app, self.decrypted_mnemonic, float_account_idxs) for key_index in float_account_idxs: public_key = nth_keys[str(key_index)]["public_key"] child_address = addresser.float_account_address( account_id=public_key, index=key_index) address_list.append(child_address) return address_list
def claim_float_account(self, public_key, parent_idx, claimed_by, claimed_on): """ Make claimed_on as the time sent by the transaction and claimed_by as the zeroth index key of the user. THen update the float_account address """ float_account = self.get_flt_account(public_key, parent_idx) float_account.claimed = True float_account.claimed_by = claimed_by float_account.claimed_on = claimed_on address = addresser.float_account_address(public_key, parent_idx) self._context.set_state({address: float_account.SerializeToString()}, self._timeout) return
def set_asset(self, payload, public, account, account_type): """ payload will have the CreateAsset in the payload public: hex public key with whose private key transaction was signed account: could be a float account or account account_type: could be FLOAT_ACCOUNT or CREATE_ACCOUNT """ logging.info("Account in set_asset <<{}>>".format(account)) if account_type == "FLOAT_ACCOUNT": account_address = addresser.float_account_address( account_id=payload.flt_account_parent_pub, index=payload.flt_account_parent_idx) else: account_address = addresser.create_account_address( account_id=payload.zero_pub, index=0) self.update_asset_index(account_address, account, payload.idx) address = addresser.create_asset_address(asset_id=public, index=payload.idx) asset = create_empty_asset() asset.key = payload.key asset.url = payload.url asset.time = payload.time asset.indiantime = payload.indiantime asset.file_name = payload.file_name asset.file_hash = payload.file_hash asset.idx = payload.idx asset.master_key = payload.master_key asset.master_url = payload.master_url asset.role = payload.role asset.public = public if payload.scope: asset.scope.cert_type = payload.scope.cert_type asset.scope.product_type = payload.scope.product_type asset.scope.product_name = payload.scope.product_name logging.info(asset) logging.info("Account after serialization %s", asset.SerializeToString()) return self._context.set_state({address: asset.SerializeToString()}, self._timeout)
def upload(issuer, receiver): headers = get_headers_on_email(issuer["email"], issuer["password"]) receiver = db_find_on_key_pending(receiver["email"]) address = addresser.float_account_address(receiver["parent_pub"], receiver["parent_idx"]) file_hash, base64_file_bytes, file_name = generate_file_like() data = { "file_name": file_name, "base64_file_bytes": base64_file_bytes, "file_hash": file_hash, "scope": create_scope(), "expired_on": revoke_time_stamp(days=100, hours=1, minutes=10), "address": address } r = requests.post("http://localhost:8000/assets/upload", data=json.dumps(data), headers=headers) logging.info(json.dumps(r.json(), indent=4)) if r.json()["error"]: logging.info("Since this account has already been claimed") logging.info("Trying upload with organization account") receiver = db_find_on_key(receiver["email"]) address = addresser.create_organization_account_address( receiver["acc_zero_pub"], 0) data.update({"address": address}) r = requests.post("http://localhost:8000/assets/upload", data=json.dumps(data), headers=headers) logging.info(json.dumps(r.json(), indent=4)) return r.json()["data"]["issuer_address"], r.json( )["data"]["receiver_address"]
async def send_create_asset(**in_data): """ Args key(str), hex_encoded: encrypted AES key with user publickey present at random index url(str): s3 url encrypted with user public key time(str): when this asset was created indiantime(str): time in indian format file_name(str): file_name file_hash(str): sha3_512 hash of file content child_idx(int): random index parent_zero_pub(str): Parent zero public key of the parent master_key(str): encrypted s3 url, encrypted with aes key generated with qci_public and user private key master_url(str): encrypted s3 url, encrypted with aes key generated with private key of user and public of QCI scope(Scope(defined in asset.proto)): string expired_on=13; //the date on which this certificate is intended """ ##TODO: Processor side : Float this asset and make change to create_asset_idxs ## to either float_Account_Address or create_Account_Address depending upon ##whther the user has been claimed or not inputs = [ addresser.create_asset_address( asset_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["idx"]), ] outputs = [ addresser.create_asset_address( asset_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["idx"]) ] ##ideally if account is claimed, we should have nothing to do with float account ## but we are sending both addresses to the processor and let processor handle ## the logic i.e float_account should exists and is_claimed shall be true ##to append create_asset_idxs to the account_transaction if not in_data["is_acc_claimed"]: ##implies user havent claimed his float_account_address, so the ## create_asset_idx aill be chnaged on flt_account_addresslogging.info("Float account parent pub %s"%in_data["flt_account_parent_pub"]) logging.info("Float account parent idx %s" % str(in_data["flt_account_parent_idx"])) float_account_address = addresser.float_account_address( account_id=in_data["flt_account_parent_pub"], index=in_data["flt_account_parent_idx"]) inputs.append(float_account_address) outputs.append(float_account_address) else: account_address = addresser.create_organization_account_address( account_id=in_data["zero_pub"], index=0) inputs.append(account_address) outputs.append(account_address) if in_data["child_zero_pub"]: child_address = addresser.child_account_address( account_id=in_data["child_zero_pub"], index=0) inputs.append(child_address) outputs.append(child_address) if in_data["scope"]: scope = payload_pb2.PayloadScope( group=in_data["scope"]["group"], sub_group=in_data["scope"]["sub_group"], field=in_data["scope"]["field"], nature=in_data["scope"]["nature"], operations=in_data["scope"]["operations"], description=in_data["scope"]["description"], ) else: scope = None logging.info(f"Input Address<<{inputs}>>") logging.info(f"Output Address<<{outputs}>>") asset = payload_pb2.CreateAsset( key=in_data["key"], url=in_data["url"], time=in_data["time"], indiantime=in_data["indiantime"], file_name=in_data["file_name"], file_hash=in_data["file_hash"], idx=in_data["idx"], master_key=in_data["master_key"], master_url=in_data["master_url"], role=in_data["role"], scope=scope, zero_pub=in_data["zero_pub"], flt_account_parent_pub=in_data["flt_account_parent_pub"], flt_account_parent_idx=in_data["flt_account_parent_idx"], child_zero_pub=in_data["child_zero_pub"]) logging.info(f"Create asset transaction {asset}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_ASSET, create_asset=asset) transaction_ids, batches, batch_id, batch_list_bytes = make_header_and_batch( payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"]) logging.info(f"This is the batch_id {batch_id}") rest_api_response = await messaging.send(batch_list_bytes, in_data["config"]) try: result = await messaging.wait_for_status(batch_id, in_data["config"]) except (ApiBadRequest, ApiInternalError) as err: #await auth_query.remove_auth_entry(request.app.config.DB_CONN, request.json.get('email')) logging.error(f"Transaction failed with {err}") raise ApiInternalError(err) #raise err return transaction_ids, batch_id
async def submit_organization_account(app, user): """ """ ##no9w the create account address and signer will be the user himself master_pub, master_priv, zero_pub, zero_priv = await \ remote_calls.from_mnemonic(app.config.GOAPI_URL, user["mnemonic"]) if user["acc_zero_pub"] != zero_pub: raise Exception("wrong mnemonic for user, Key mismatch error") acc_signer=encryption_utils.create_signer(zero_priv) ##hashing gst number and tan number if present ##fecth float account details from the blokchchain, because it might be a possibility ##that there are several create_asset transaction in pipeline, and the user ## now start the procedute to claim the acccount, Now if we fetch pending user ## rom db rather then blokchcain then flt_acc_idxs will differ flt_acc_address = addresser.float_account_address( user["parent_pub"], user["parent_idx"]) flt_account = await deserialize_state.deserialize_float_account( app.config.REST_API_URL, flt_acc_address) ##import from ledger.account import float_account, other then create_asset_idxs ## wil be emprty for the float_account, if we push empty list on blockchain ##it wil hsow an error, its better to not to send them at the first place transaction_data= {"config": app.config, "txn_key": acc_signer, "batch_key": app.config.SIGNER, "org_name": user["org_name"], "parent_pub": user["parent_pub"], #required to find #float_account address "user_id": user["user_id"], "pancard": hashlib.\ sha512(user["pancard"].encode())\ .hexdigest(), "gst_number": hashlib.\ sha512(user["gst_number"].encode())\ .hexdigest(), "tan_number": hashlib.\ sha512(user["tan_number"].encode())\ .hexdigest(), "phone_number": hashlib.\ sha512(user["phone_number"].encode())\ .hexdigest(), "email": user["email"], "time": int(time.time()), "indian_time": upload_utils.indian_time_stamp(), "parent_zero_pub": user["parent_zero_pub"], "parent_role": user["parent_role"], "role": user["role"], "create_asset_idxs": flt_account.get("create_asset_idxs"), "deactivate": False, "deactivate_on": None, "parent_idx": user["parent_idx"], "float_account_address": flt_acc_address, } transaction_ids, batch_id = await __send_organization_account(**transaction_data) logging.info(batch_id) if batch_id: logging.debug(user) ##if successful, insert this user in pending_users table user.update({ "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "transaction_id": transaction_ids[0], "batch_id": batch_id, "create_asset_idxs": flt_account.get("create_asset_idxs"), "type": "ORGANIZATION"}) user.pop("mnemonic") logging.debug(user) await accounts_query.insert_account(app, user) ##update user pending_user with claim, claim_by , claimed_on keys await accounts_query.claim_account(app, user["user_id"], user["email"], user["phone_number"], user["indian_time"]) ##return new user data whose float_account has just been created return user
def create_asset(**in_data): """ Inputs will have asset_address, account_address (The key index will be appended to the account address) float_accout (if the user only has a float_account till now, key_index will be appended to the float_account address) child_account_address (In case the asset being created by the child) """ ##TODO: Processor side : Float this asset and make change to create_asset_idxs ## to either float_Account_Address or create_Account_Address depending upon ##whther the user has been claimed or not inputs = [ addresser.create_asset_address( asset_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["idx"]), ] outputs = [ addresser.create_asset_address( asset_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["idx"]) ] ##ideally if account is claimed, we should have nothing to do with float account ## but we are sending both addresses to the processor and let processor handle ## the logic i.e float_account should exists and is_claimed shall be true ##to append create_asset_idxs to the account_transaction if not in_data["is_acc_claimed"]: ##implies user havent claimed his float_account_address, so the ## create_asset_idx aill be chnaged on flt_account_addresslogging.info("Float account parent pub %s"%in_data["flt_account_parent_pub"]) logging.info("Float account parent idx %s" % str(in_data["flt_account_parent_idx"])) float_account_address = addresser.float_account_address( account_id=in_data["flt_account_parent_pub"], index=in_data["flt_account_parent_idx"]) inputs.append(float_account_address) outputs.append(float_account_address) else: account_address = addresser.create_organization_account_address( account_id=in_data["zero_pub"], index=0) inputs.append(account_address) outputs.append(account_address) if in_data["child_zero_pub"]: child_address = addresser.child_account_address( account_id=in_data["child_zero_pub"], index=0) inputs.append(child_address) outputs.append(child_address) if in_data["scope"]: scope = payload_pb2.PayloadScope( group=in_data["scope"]["group"], sub_group=in_data["scope"]["sub_group"], field=in_data["scope"]["field"], nature=in_data["scope"]["nature"], operations=in_data["scope"]["operations"], description=in_data["scope"]["description"], ) else: scope = None logging.info(f"Input Address<<{inputs}>>") logging.info(f"Output Address<<{outputs}>>") asset = payload_pb2.CreateAsset( key=in_data["key"], url=in_data["url"], time=in_data["time"], indiantime=in_data["indiantime"], file_name=in_data["file_name"], file_hash=in_data["file_hash"], idx=in_data["idx"], master_key=in_data["master_key"], master_url=in_data["master_url"], role=in_data["role"], scope=scope, zero_pub=in_data["zero_pub"], flt_account_parent_pub=in_data["flt_account_parent_pub"], flt_account_parent_idx=in_data["flt_account_parent_idx"], child_zero_pub=in_data["child_zero_pub"]) logging.info(f"Create asset transaction {asset}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_ASSET, create_asset=asset) return make_header_and_batch(payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"])
def create_organization_account(**in_data): """Create a CreateAccount txn and wrap it in a batch and list. need to change two addresses create a account from user zeroth key edit float_accout address from parent nindex key and marked it claimed Args: txn_key (sawtooth_signing.Signer): The Txn signer key pair. batch_key (sawtooth_signing.Signer): The Batch signer key pair. label (str): The account's label. description (str): The description of the account. Returns: tuple: List of Batch, signature tuple """ inputs = [ addresser.create_organization_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=0), ] outputs = [ addresser.create_organization_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=0), ] if in_data["role"] != "ADMIN": inputs.append( addresser.float_account_address(account_id=in_data["parent_pub"], index=in_data["parent_idx"])) outputs.append( addresser.float_account_address(account_id=in_data["parent_pub"], index=in_data["parent_idx"])) if in_data.get("parent_pub"): logging.info(f"This is the parent pub {in_data['parent_pub']}") account = payload_pb2.CreateOrganizationAccount( role=in_data["role"], parent_role=in_data["parent_role"], phone_number=in_data["phone_number"], pancard=in_data["pancard"], user_id=in_data["user_id"], email=in_data["email"], org_name=in_data["org_name"], gst_number=in_data["gst_number"], tan_number=in_data["tan_number"], time=in_data["time"], indian_time=in_data["indian_time"], parent_zero_pub=in_data["parent_zero_pub"], deactivate=in_data["deactivate"], deactivate_on=in_data["deactivate_on"], create_asset_idxs=in_data["create_asset_idxs"], parent_pub=in_data["parent_pub"], parent_idx=in_data["parent_idx"], float_account_address=in_data["float_account_address"], ) logging.info(account) logging.info(f"THe address for the user on blockchain {inputs[0]}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload. CREATE_ORGANIZATION_ACCOUNT, create_organization_account=account) logging.info(payload) return make_header_and_batch(payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"])
def create_float_account(**in_data): """Create a CreateAccount txn and wrap it in a batch and list. Args: txn_key(sawtooth_signing.Signer): signer created from user zeroth public key parent_zero_pub(string): zeroth account key of the pub who floated this trnasaction batch_key(sawtooth_signing.Signer): signer created from QCI mnemonic zero private key, pancard(str): pancard of the user , phone_number(str): phone_number of the user, email(str): email of the user, claimed(bool): If this float account is claimed or not, claimed_by(str): Public key of the user for whom this float_acc transaction, create_asset_index(int): random key index at which the first asset was created, parent_pub(str): public key of the parent , parent_idx(str): Required to be appened to parent accoutn flt_key_inds, key_index, time=time.time(); indian_time=indian_time_stamp(), claimed_on(str): Date on which this flt account was claimed and converted to create account) parent_zero_pub: parent zero pub required for calcualting parent address parent_role=parent["role"], user_role=user_data["role"] Returns: tuple: List of Batch, signature tuple """ logging.info(f"THis is the data received in trsaction ceratrion {in_data}") inputs = [ addresser.create_organization_account_address( account_id=in_data["parent_zero_pub"], index=0), addresser.float_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["parent_idx"]) ] logging.info( f"THe account address for the parent on blockchain {inputs[0]}") logging.info(f"THe float account address for the user {inputs[1]}") outputs = [ addresser.create_organization_account_address( account_id=in_data["parent_zero_pub"], index=0), addresser.float_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["parent_idx"]) ] if in_data["child_zero_pub"]: child_address = addresser.child_account_address( account_id=in_data["child_zero_pub"], index=0) logging.info(f"CHILD address is {child_address}") inputs.append(child_address) outputs.append(child_address) logging.info(f"INPUTS ADDRESSES --<{inputs}>--") logging.info(f"OUTPUTS ADDRESSES --<{outputs}>--") float_account = payload_pb2.CreateFloatAccount( claimed_on=in_data["claimed_on"], org_name=in_data["org_name"], pancard=in_data["pancard"], gst_number=in_data["gst_number"], tan_number=in_data["tan_number"], phone_number=in_data["phone_number"], email=in_data["email"], claimed=in_data["claimed"], claimed_by=in_data["claimed_by"], create_asset_idxs=in_data["create_asset_idxs"], parent_idx=in_data["parent_idx"], time=in_data["time"], indian_time=in_data["indian_time"], parent_role=in_data["parent_role"], role=in_data["role"], parent_zero_pub=in_data["parent_zero_pub"], nonce=in_data["nonce"], nonce_hash=in_data["nonce_hash"], signed_nonce=in_data["signed_nonce"], child_zero_pub=in_data["child_zero_pub"]) logging.info(float_account) logging.info( f"THe serialized protobuf for float_account is {float_account}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_FLOAT_ACCOUNT, create_float_account=float_account) return make_header_and_batch(payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"])
def set_asset(self, public, payload): """ payload will have the CreateAsset in the payload public: hex public key with whose private key transaction was signed account: could be a float account or account account_type: could be FLOAT_ACCOUNT or CREATE_ACCOUNT """ logging.info("Payload in set_asset <<{}>>".format(payload)) if payload.flt_account_parent_pub: account_address = addresser.float_account_address( account_id=payload.flt_account_parent_pub, index=payload.flt_account_parent_idx) logging.info("Updating create_asset_idxs in float_account\ at {}".format(account_address)) float_account = self.get_flt_account( public_key=payload.flt_account_parent_pub, index=payload.flt_account_parent_idx) self.update_asset_index(account_address, float_account, payload.idx) else: account_address = addresser.create_organization_account_address( account_id=payload.zero_pub, index=0) logging.info("Updating create_asset_idxs in \ organization_account at {}".format(account_address)) organization_account = self.get_organization( public_key=payload.zero_pub) self.update_asset_index(account_address, organization_account, payload.idx) ##if this is present that means that this asset is being created by child ##of the organization, so the payload.idx needs to be appended to the ##create_asset_idxs array of the child too if payload.child_zero_pub: account_address = addresser.child_account_address( account_id=payload.child_zero_pub, index=0) child_account = self.get_child(payload.child_zero_pub, 0) self.update_asset_index(account_address, child_account, payload.idx) address = addresser.create_asset_address(asset_id=public, index=payload.idx) asset = create_empty_asset() asset.key = payload.key asset.url = payload.url asset.time = payload.time asset.indiantime = payload.indiantime asset.file_name = payload.file_name asset.file_hash = payload.file_hash asset.idx = payload.idx asset.master_key = payload.master_key asset.master_url = payload.master_url asset.expired_on = payload.expired_on asset.role = payload.role asset.public = public asset.child_zero_pub = payload.child_zero_pub if payload.scope: asset.scope.group = payload.scope.group asset.scope.sub_group = payload.scope.sub_group asset.scope.field = payload.scope.field asset.scope.nature = payload.scope.nature asset.scope.operations = payload.scope.operations asset.scope.description = payload.scope.description logging.info(asset) logging.info("Account after serialization %s", asset.SerializeToString()) return self._context.set_state({address: asset.SerializeToString()}, self._timeout)
def set_float_account(self, public_key, payload): logging.info("Paylaod from set_float_account {}".format(payload)) ##change idx in the account present at public key input_data["parent_zero_pub"] self.set_org_float_account_idxs(payload.parent_zero_pub, payload.parent_idx) ##this implies that this float account being created by the child of ##payload.parent_role if payload.child_zero_pub: self.set_child_float_account_idxs(payload.child_zero_pub, payload.parent_idx) ##here the parent pub is the nth index key of the parent on thich ##this float account address is generated address = addresser.float_account_address(account_id=public_key, index=payload.parent_idx) float_account = create_empty_float_account() logging.info("This is the value of create_asset_idxs \ {}".format(payload.create_asset_idxs)) float_account.pancard = payload.pancard float_account.phone_number = payload.phone_number float_account.email = payload.email float_account.gst_number = payload.gst_number float_account.tan_number = payload.tan_number float_account.org_name = payload.org_name ##will be changed when the person or orgnization claims this account float_account.claimed = payload.claimed float_account.claimed_by = payload.claimed_by float_account.claimed_on = payload.claimed_on ##this is not required because create_asset_idxs will wlays be empty ##when intilizing float_account #float_account.create_asset_idxs=input_data["create_asset_idxs"] float_account.time = payload.time float_account.indian_time = payload.indian_time ##parent_pub at random_idxs in float_account_idxs array with which this ##float account address was generated float_account.parent_idx = payload.parent_idx ##this was required to check the signed_nonce signed by the zeroth private ##key of the creator float_account.parent_zero_pub = payload.parent_zero_pub float_account.parent_role = payload.parent_role float_account.role = payload.role float_account.public = public_key ##so that we can track if its been made by a child of the organiation or not ##it will be an empty field if the organization themselves made the account float_account.child_zero_pub = payload.child_zero_pub float_account.parent_zero_pub = payload.parent_zero_pub ##so that we can later check who actually made this float_account and ## and was a vald account float_account.nonce = payload.nonce float_account.nonce_hash = payload.nonce_hash float_account.signed_nonce = payload.signed_nonce logging.info(float_account) logging.info("Account after serialization %s", float_account.SerializeToString()) return self._context.set_state( {address: float_account.SerializeToString()}, self._timeout)
async def send_float_account(**in_data): """ txn_key(sawtooth_signing.Signer): signer created from user zeroth public key batch_key(sawtooth_signing.Signer): signer created from QCI mnemonic zero private key, pancard(str): pancard of the user , phone_number(str): phone_number of the user, email(str): email of the user, claimed(bool): If this float account is claimed or not, claimed_by(str): Public key of the user for whom this float_acc transaction, create_asset_index(int): random key index at which the first asset was created, parent_pub(str): public key of the parent , parent_idx(str): Required to be appened to parent accoutn flt_key_inds, key_index, time=time.time(); indian_time=indian_time_stamp(), claimed_on(str): Date on which this flt account was claimed and converted to create account) """ inputs = [addresser.create_organization_account_address( account_id=in_data["parent_zero_pub"], index=0), addresser.float_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["parent_idx"] ) ] logging.info(f"THe account address for the parent on blockchain {inputs[0]}") logging.info(f"THe float account address for the user {inputs[1]}") outputs = [addresser.create_organization_account_address( account_id=in_data["parent_zero_pub"], index=0), addresser.float_account_address( account_id=in_data["txn_key"].get_public_key().as_hex(), index=in_data["parent_idx"] ) ] if in_data["child_zero_pub"]: child_address = addresser.child_account_address( account_id=in_data["child_zero_pub"], index=0 ) logging.info(f"CHILD address is {child_address}") inputs.append(child_address) outputs.append(child_address) logging.info(f"INPUTS ADDRESSES --<{inputs}>--") logging.info(f"OUTPUTS ADDRESSES --<{outputs}>--") float_account = payload_pb2.CreateFloatAccount( claimed_on=in_data["claimed_on"], org_name=in_data["org_name"], pancard=in_data["pancard"], gst_number=in_data["gst_number"], tan_number=in_data["tan_number"], phone_number=in_data["phone_number"], email=in_data["email"], claimed=in_data["claimed"], claimed_by=in_data["claimed_by"], create_asset_idxs=in_data["create_asset_idxs"], parent_idx=in_data["parent_idx"], time=in_data["time"], indian_time=in_data["indian_time"], parent_role=in_data["parent_role"], role=in_data["role"], parent_zero_pub=in_data["parent_zero_pub"], nonce=in_data["nonce"], nonce_hash=in_data["nonce_hash"], signed_nonce=in_data["signed_nonce"], child_zero_pub=in_data["child_zero_pub"] ) logging.info(float_account) logging.info(f"THe serialized protobuf for float_account is {float_account}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_FLOAT_ACCOUNT, create_float_account=float_account) transaction_ids, batches, batch_id, batch_list_bytes= make_header_and_batch( payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"]) logging.info(f"This is the batch_id {batch_id}") rest_api_response = await messaging.send( batch_list_bytes, in_data["config"]) try: result = await messaging.wait_for_status(batch_id, in_data["config"]) except (ApiBadRequest, ApiInternalError) as err: #await auth_query.remove_auth_entry(request.app.config.DB_CONN, request.json.get('email')) raise err return False, False return transaction_ids, batch_id
async def submit_float_account(app, requester, user): ##retrive float_account from parent ## handle if the parent is actually a child account, then the flt_acc_idxs ## of the parent must be used ##elseif organization is directly creating another org account then its ## own flt_account_idxs must be used ##a junk entry needs to be sent which is A once signed by the parent orgnisation of the ## child or the organization itself zeroth_private_key, which that the float_account is ## actually being sent by the concerned authority, otherwise anyone can generate any ## random keys and then make a float_transaction because we are not checking any other details ## for cros checking if requester["role"] == "CHILD": ##now find the parent pub of this child to track the parent ##organization account ##child will get the flt_acc_idxs of the parent organization org_address = addresser.create_organization_account_address( requester["parent_zero_pub"], 0) org_account = await deserialize_state.deserialize_org_account( app.config.REST_API_URL, org_address) logging.info(org_account) ##lets chaeck if the parent user_id hash matched with the child parent_id if requester["parent_idx"] not in org_account["child_account_idxs"]: raise Exception("Child parent_idx not in parent org child_account_idxs") if requester["org_name"] != org_account["org_name"]: raise Exception("Child org_name is different from parent") ##since child was created from the PUblic key present at parent_idx at the ##parent org mnemonic, We need to get that so that we can generated child ##adddress, Remember, child_account_addresses generates from parent_org ##not with the zeroth key of the child mnemonic ##TODO: you can also check whether the child address generated from #parent org public key pair at requester parent_idx is same as requester ## address ##float_account_idxs array of the child's parent organisation flt_acc_idxs = org_account.get("float_account_idxs") ##now we need to decrypt the parent mnemonic so that we can get the Public/private key ##pair corresponding to the the random index parent_id = org_account["user_id"] logging.info(f"Parent id for the child is {parent_id} and\ float_account_idxs are {flt_acc_idxs}") org_db = await accounts_query.find_on_key(app, "user_id", parent_id) logging.info(org_db) if org_db["role"] != "ADMIN": decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic( app, org_db["encrypted_admin_mnemonic"], org_db["role"]) else: decrypted_mnemonic = app.config.ADMIN_MNEMONIC logging.info(decrypted_mnemonic) nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [requester["parent_idx"]]) nth_priv, nth_pub = nth_keys[str(requester["parent_idx"])]["private_key"], \ nth_keys[str(requester["parent_idx"])]["public_key"] zero_pub = org_db["acc_zero_pub"] parent_role = org_db["role"] child_zero_pub = nth_pub else: #orgnisation itself is creating this float_account logging.info(requester) ##float_account_idxs array of the orgnization itself flt_acc_idxs = await accounts_query.get_field(app, requester["user_id"], "float_account_idxs") flt_acc_idxs = flt_acc_idxs.get("float_account_idxs") logging.info(f"Float account indxs for the orgnization {flt_acc_idxs}") decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic(app, requester["encrypted_admin_mnemonic"], requester["role"]) logging.info(decrypted_mnemonic) zero_pub = requester["acc_zero_pub"] parent_role = requester["role"] child_zero_pub = None logging.info(f"This is the decrypted mnemonic for parent {decrypted_mnemonic}") ##This will generate a new key which doesnt exists in the flt_acc_idxs array key_index = await ledger_utils.generate_key_index(flt_acc_idxs) logging.info(f"THis is the key index for parent {key_index}") nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [key_index, 0]) nth_priv, nth_pub = nth_keys[str(key_index)]["private_key"], \ nth_keys[str(key_index)]["public_key"] ##getting zeroth private key to be used later zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] flt_acc_address = addresser.float_account_address(nth_pub, key_index) logging.info(f"This is the flt acc addressfor user {flt_acc_address}") logging.info(f"Checking if valid account address has been generated\ {addresser.address_is(flt_acc_address)}") ##signer created from the parent key flt_acc_signer=upload_utils.create_signer(nth_priv) ##sending signatures, A nonce signed by zeroth_private_key nonce = random.randint(2**20, 2**31) nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest() hex_signatures = signatures.ecdsa_signature(zeroth_priv, nonce) ##hashing gst number and tan number if present if user.get("gst_number"): gst_number = hashlib.sha224(user["gst_number"].encode()).hexdigest() else: gst_number = None if user.get("tan_number"): tan_number = hashlib.sha224(user["tan_number"]\ .encode()).hexdigest() else: tan_number = None ##import from ledger.account import float_account transaction_data= {"config": app.config, "txn_key": flt_acc_signer, "batch_key": app.config.SIGNER, "org_name": user["org_name"], "pancard": hashlib.sha224(user["pancard"]\ .encode()).hexdigest(), "gst_number": gst_number, "tan_number": tan_number, "phone_number": user["phone_number"], "email": user["email"], "claimed": False, "claimed_by": None, "create_asset_idxs": [], "parent_pub": nth_pub, "parent_idx": key_index, "time": int(time.time()), "indian_time": upload_utils.indian_time_stamp(), "parent_zero_pub": zero_pub, "parent_role": parent_role, "role": user["role"], "claimed_on": None, "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": hex_signatures, "child_zero_pub": child_zero_pub } transaction_ids, batch_id = await send_float_account(**transaction_data) if batch_id: logging.debug(user) ##if successful, insert this user in pending_users table user.update({"parent_pub": nth_pub, "parent_idx": key_index, "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "parent_zero_pub": transaction_data["parent_zero_pub"], "parent_role": transaction_data["parent_role"], "transaction_id": transaction_ids[0], "batch_id": batch_id, "child_zero_pub": child_zero_pub, }) logging.debug(f"User after submitting float_Account trasaction {user}") await accounts_query.insert_pending_account(app, user) if requester["role"] == "CHILD": ##update parent create_flt_idcs array await accounts_query.update_flt_acc_idxs(app, org_db["user_id"], key_index) ##update float_account_idxs of the child also, so that we would ##know which child created which float_account_idxs await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index) else: await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index) ##return new user data whose float_account has just been created return user