async def append( self, transactions: Union[List[Transaction], List[dict]], txn_time: Union[str, int] = None) -> (int, int, List[Transaction]): transactions_to_append = [] for txn in transactions: if isinstance(txn, Transaction): transactions_to_append.append(txn) elif isinstance(txn, dict): transactions_to_append.append(Transaction.create(txn)) else: raise RuntimeError('Unexpected transaction type') transactions_with_meta = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/append_txns_metadata', params={ 'name': self.name, 'txns': transactions_to_append, 'txn_time': txn_time }) self.__state, start, end, appended_txns = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/append_txns', params={ 'name': self.name, 'txns': transactions_with_meta, }) return start, end, Transaction.from_value(appended_txns)
def __init__(self, transactions: List[Transaction] = None, state: Optional[MicroLedgerState] = None, *args, **kwargs): super().__init__(*args, **kwargs) if transactions is not None: for txn in transactions: txn = Transaction(txn) if not txn.has_metadata(): raise SiriusContextError('Transaction must have processed by Ledger engine and has metadata') self['transactions'] = transactions if state: state = MicroLedgerState(state) self['state'] = state self['hash'] = state.hash
async def get_uncommitted_transactions(self) -> List[Transaction]: txns = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/get_uncommitted_txns', params={'name': self.name}) txns = Transaction.from_value(txns) assert isinstance(txns, list) return txns
async def get_last_committed_transaction(self) -> Transaction: txn = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/get_last_committed_txn', params={'name': self.name}) txn = Transaction.from_value(txn) assert isinstance(txn, Transaction) return txn
async def commit(self, count: int) -> (int, int, List[Transaction]): self.__state, start, end, committed_txns = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/commit_txns', params={ 'name': self.name, 'count': count, }) return start, end, Transaction.from_value(committed_txns)
async def init(self, genesis: List[Transaction]) -> List[Transaction]: self.__state, txns = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/initialize', params={ 'name': self.name, 'genesis_txns': genesis }) txns = [Transaction.from_value(txn) for txn in txns] return txns
async def get_transaction(self, seq_no: int) -> Transaction: txn = await self.__api.remote_call( msg_type= 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/microledgers/1.0/get_by_seq_no', params={ 'name': self.name, 'seqNo': seq_no }) txn = Transaction.from_value(txn) assert isinstance(txn, Transaction) return txn
def __init__( self, transactions: List[Transaction] = None, states: List[Union[MicroLedgerState, dict]] = None, *args, **kwargs ): super().__init__(*args, **kwargs) if transactions is not None: for txn in transactions: txn = Transaction(txn) if not txn.has_metadata(): raise SiriusContextError('Transaction must have metadata for specific Ledger') self['transactions'] = transactions if states: # Fix states as hash states = [MicroLedgerState(state) for state in states] # sort by ledger name, assume ledger name is unique in system # to make available to calc accumulated hash predictable states = list(sorted(states, key=lambda s: s.name)) accum = hashlib.sha256() for state in states: accum.update(state.hash.encode()) self['hash'] = accum.hexdigest()
async def create( self, name: str, genesis: Union[List[Transaction], List[dict]] ) -> (AbstractMicroledger, List[Transaction]): genesis_txns = [] for txn in genesis: if isinstance(txn, Transaction): genesis_txns.append(txn) elif isinstance(txn, dict): genesis_txns.append(Transaction.create(txn)) else: raise RuntimeError('Unexpected transaction type') instance = Microledger(name, self.__api) txns = await instance.init(genesis_txns) self.instances[name] = instance return instance, txns
async def append( self, transactions: Union[List[Transaction], List[dict]], txn_time: Union[str, int] = None ) -> (int, int, List[Transaction]): txns = [] for i, txn in enumerate(Transaction.from_value(transactions)): metadata = txn.get('txnMetadata', {}) if 'seq_no' not in metadata: metadata['seq_no'] = self.seq_no + 1 + i if 'time' not in metadata: metadata['time'] = txn_time or str(datetime.datetime.utcnow()) txn['txnMetadata'] = metadata txns.append(txn) start = self.seq_no + 1 end = start + len(txns) - 1 self.__uncommitted.extend(txns) return start, end, txns
async def issue_test_results(self, cred_def: sirius_sdk.CredentialDefinition, schema: sirius_sdk.Schema, test_results: dict): async with sirius_sdk.context(**self.hub_credentials): # работаем от имени агента лабы connection_key = await sirius_sdk.Crypto.create_key() # создаем случайный уникальный ключ соединения между агентом лабы и сириус коммуникатором пользователя endpoints = await sirius_sdk.endpoints() simple_endpoint = [e for e in endpoints if e.routing_keys == []][0] # точка подключения к агенту лабы (интернет адрес) invitation = sirius_sdk.aries_rfc.Invitation( # Создаем приглашение пользователю подключиться к лабе label="Invitation to connect with medical organization", recipient_keys=[connection_key], endpoint=simple_endpoint.address ) qr_content = invitation.invitation_url qr_url = await sirius_sdk.generate_qr_code(qr_content) # агент лабы генерирует уникальный qr код для ранее созданного приглашения # пользователь сканирует qr код при помощи sirius коммуникатора. Коммуникатор отправляет агенту лабы запрос на подключение print("Scan this QR by Sirius App for receiving the Covid test result " + qr_url) listener = await sirius_sdk.subscribe() async for event in listener: if event.recipient_verkey == connection_key and isinstance(event.message, sirius_sdk.aries_rfc.ConnRequest): # агент лабы получает запрос от пользователя на подключение (запрос соответствкет ранее сгенерированному уникальному ключу соединения) request: sirius_sdk.aries_rfc.ConnRequest = event.message # агент лабы создает уникальный децентрализованный идентификатор (did) для связи с пользователем (который тоже создает уникальный did для этого соединения) my_did, my_verkey = await sirius_sdk.DID.create_and_store_my_did() sm = sirius_sdk.aries_rfc.Inviter( me=sirius_sdk.Pairwise.Me( did=my_did, verkey=my_verkey ), connection_key=connection_key, my_endpoint=simple_endpoint ) # Запускается процесс установки соединения в соответствии с открытым протоколом Aries 0160 success, p2p = await sm.create_connection(request) if success: # соединение успешно установлено, о чем сообщается пользователю путем отправки простого текстового сообщения на его сириус коммуникатор message = sirius_sdk.aries_rfc.Message( content="Welcome to the covid laboratory!", locale="en" ) print(message) await sirius_sdk.send_to(message, p2p) issuer = sirius_sdk.aries_rfc.Issuer(p2p) preview = [sirius_sdk.aries_rfc.ProposedAttrib(key, str(value)) for key, value in test_results.items()] translation = [ sirius_sdk.aries_rfc.AttribTranslation("full_name", "Patient Full Name"), sirius_sdk.aries_rfc.AttribTranslation("location", "Patient location"), sirius_sdk.aries_rfc.AttribTranslation("bio_location", "Biomaterial sampling point"), sirius_sdk.aries_rfc.AttribTranslation("timestamp", "Timestamp"), sirius_sdk.aries_rfc.AttribTranslation("approved", "Laboratory specialist"), sirius_sdk.aries_rfc.AttribTranslation("has_covid", "Covid test result") ] # лаборатория выдает результаты теста на ковид пользователю. # Результаты оформлены в соответствии с ранее зареестрированной схемой и подписаны ЦП лаборатории. # Пользователь сохраняет полученные результаты на своем сириус коммуникаторе ok = await issuer.issue( values=test_results, schema=schema, cred_def=cred_def, preview=preview, translation=translation, comment="Here is your covid test results", locale="en" ) if ok: print("Covid test confirmation was successfully issued") # если результат теста оказался положительным, он записывается в соответствующий распределенный микрореестр, # достут к которому имеет лаборатория, авиакомпания и аэропорт if test_results["has_covid"]: ledger = await sirius_sdk.Microledgers.ledger(COVID_MICROLEDGER_NAME) machine = MicroLedgerSimpleConsensus(self.me, logger=Logger()) tr = Transaction({ "test_res": test_results }) await machine.commit(ledger, self.covid_microledger_participants, [tr]) break
def transactions(self) -> Optional[List[Transaction]]: txns = self.get('transactions', None) if txns is not None: return [Transaction(txn) for txn in txns] else: return None