def CreateWalletEndpoint(session, data): check_wallet_schema(data) pk = session.public_key invite_code = generate_random_string(48) if Wallet.select().where(Wallet.source == pk).exists(): raise APIError("Shared wallet linked with your key is already exists", 409) level = data['participants'] - data['signers'] device_uid = data.get('device_uid') wallet = Wallet.create( name=data['name'], signers=data['signers'], participants=data['participants'], invite_code=invite_code, level=level, source=pk) MultisigInfo.create( wallet=wallet.id, info=data['multisig_info'], level=0, device_uid=device_uid, source=pk) return jsonify({"invite_code": wallet.invite_code})
def ChangePublicKeyEndpoint(session, wallet, data): """Set multisig key instead of regular""" key = data['public_key'] pk = session.public_key if wallet.status == "ready": changed_key = app.redis.hget("m_sessions", session.id) if changed_key is None: app.redis.hset("m_sessions", session.id, key) return ('', 200) # wallet = Wallet.get((Wallet.source == pk) | (Wallet.multisig_source == pk)) if wallet.status not in ("changing_keys", "fulfilled"): raise APIError("Wallet is not ready for key change") # update wallet source if there is initiator key change request if wallet.source == pk: wallet.multisig_source = key wallet.save() # update multisig info source for this wallet and current session q = (MultisigInfo.update( multisig_source=key).where((MultisigInfo.source == pk) & (MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0))) q.execute() changed_keys = MultisigInfo.select().where( (MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0) & (MultisigInfo.multisig_source.is_null(False))).count() if changed_keys == wallet.participants: wallet.status = 'ready' wallet.save() app.redis.publish("stream:wallet_info:%s" % wallet.id, wallet.status) data = { 'wallet_id': wallet.id, 'public_key': pk, 'status': wallet.status, 'changed_keys': len(wallet.changed_keys), 'joined': len(wallet.multisig_infos), 'participants': wallet.participants, 'signers': wallet.signers, } print(data) app.redis.publish("stream:wallet_info", json.dumps(data)) # replace key in session app.redis.hset("m_sessions", session.id, key) return ('', 204)
def get_extra_multisig_info(wallet, level): multisigs = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == level)) data = { "extra_multisig_infos": [{ "extra_multisig_info": x.info } for x in multisigs] } return jsonify(data)
def setup_extra_multisig_info(wallet, fixed_level, extra_multisig_info, pk): level = wallet.participants - wallet.signers if not fixed_level: level_process = level + 1 for i in range(1, level + 1): print(i) is_empty = LevelEmpty(wallet, i) if is_empty: level_process = i break else: level_process = fixed_level if level_process == level+1: if not wallet.is_changing_keys: wallet.status = "changing_keys" wallet.save() app.redis.publish("stream:extra_multisig_info:%s" % wallet.id, "complete") multisig_infos = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == level_process)) data2 = { "wallet_id": wallet.id, "public_key": pk, "extra_multisig_infos": [{"extra_multisig_info": x.info} for x in multisig_infos] } app.redis.publish("stream:extra_multisig_info", json.dumps(data2)) else: (info, created) = MultisigInfo.get_or_create( wallet=wallet.id, source=pk, level=level_process, defaults={"info": extra_multisig_info}) if not created: info.info = extra_multisig_info info.save()
async def MultisigInfoStream(session, wallet, request): stream = await setup_stream(request) sub = None if wallet.is_new: sub = await wait_for_trigger('stream:multisig_info:%s' % wallet.id) multisig_infos = await objects.execute( MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0)) ) data = {"multisig_infos": [{"multisig_info": x.info} for x in multisig_infos]} await write_and_close(stream, data, 'stream:multisig_info:%s' % wallet.id, sub) return stream
async def ExtraMultisigInfoStream(session, wallet, request): stream = setup_stream(request) if wallet.is_new or wallet.is_fulfilled: sub = await aioredis.create_redis('redis://localhost') subscriber = await sub.subscribe('stream:extra_multisig_info:%s' % wallet.id) subscriber = subscriber[0] while (await subscriber.wait_message()): msg = await subscriber.get() break multisig_infos = await objects.execute( MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == 1)) ) data = {"extra_multisig_infos": [{"extra_multisig_info": x.info} for x in multisig_infos]} await write_and_close(stream, data, 'stream:multisig_info:%s' % wallet.id, sub) # using old state here if wallet.is_new or wallet.is_fulfilled: await sub.unsubscribe('stream:extra_multisig_info:%s' % wallet.id) return stream
def JoinWalletEndpoint(session, data): pk = session.public_key try: wallet = Wallet.get(invite_code=data['invite_code']) except Wallet.DoesNotExist: raise APIError("Wallet not found", status_code=404) device_uid = data.get('device_uid') if device_uid is not None: if MultisigInfo.select().where((MultisigInfo.device_uid == device_uid) & (MultisigInfo.wallet_id == wallet.id)).exists(): raise APIError("Already joined", status_code=409) if not wallet.is_new: try: multisig = MultisigInfo.get(source=pk) except MultisigInfo.DoesNotExist: raise APIError("Wallet is already fulfilled", status_code=409) return ('', 200) (info, created) = MultisigInfo.get_or_create( wallet=wallet.id, source=pk, level=0, device_uid=device_uid, defaults={"info": data['multisig_info']}) if not created: info.info = data['multisig_info'] info.save() app.redis.publish("stream:wallet_info:%s" % wallet.id, wallet.status) data2 = { 'wallet_id': wallet.id, 'public_key': pk, 'status': wallet.status, 'changed_keys': len(wallet.changed_keys), 'joined': len(wallet.multisig_infos), 'participants': wallet.participants, 'signers': wallet.signers, 'event': 'joined' } app.redis.publish("stream:wallet_info", json.dumps(data2)) if wallet.multisig_infos.count() >= wallet.participants: if wallet.level > 0: wallet.status = "fulfilled" else: wallet.status = "changing_keys" wallet.save() app.redis.publish("stream:multisig_info:%s" % wallet.id, "complete") data2 = { "wallet_id": wallet.id, "public_key": pk, "multisig_infos": [{"multisig_info": x.info} for x in wallet.multisig_infos], "event": "completed" } app.redis.publish("stream:multisig_info", json.dumps(data2)) return ('', 204)
def LevelEmpty(wallet, level): infos_count = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == level)).count() if infos_count < wallet.participants: return True else: return False
def MultisigInfoEndpoint(session, wallet): multisigs = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0)) data = {"multisig_infos": [{"multisig_info": x.info} for x in multisigs]} return jsonify(data)