diff --git a/mirage/_cert.py b/mirage/_cert.py index ce12aa010f40a39ffde6336f71ba114bc6b6442d..831d3b25aa5ab0893613ea72860cbb7c0f1f91a6 100644 --- a/mirage/_cert.py +++ b/mirage/_cert.py @@ -9,6 +9,3 @@ class Cert: written_on = attr.ib() block = attr.ib() mediantime = attr.ib() - - - diff --git a/mirage/_ud.py b/mirage/_ud.py index b3d470c96aab5949878d26b2c14d78db4a5d5faf..28611abcd2dcaee93ff527d427f76b965eba8133 100644 --- a/mirage/_ud.py +++ b/mirage/_ud.py @@ -7,6 +7,3 @@ class UD: base = attr.ib(repr=True) block_number = attr.ib() time = attr.ib() - - - diff --git a/mirage/_user_identity.py b/mirage/_user_identity.py index 6d8c0c2eb99e2d335692886eb6ba07134f8f2994..37b0c2bb8684804b6b1d6a6704dd73e3865f20bc 100644 --- a/mirage/_user_identity.py +++ b/mirage/_user_identity.py @@ -19,4 +19,3 @@ class UserIdentity: tx_sent = attr.ib(default=attr.Factory(list)) tx_received = attr.ib(default=attr.Factory(list)) ud_generated = attr.ib(default=attr.Factory(list)) - diff --git a/mirage/block_forge.py b/mirage/block_forge.py index c045610d1dbfcf793cccda0c89bdd617a1ce395b..da4087f870e13f5fcfd1460a80d87a0316390238 100644 --- a/mirage/block_forge.py +++ b/mirage/block_forge.py @@ -1,5 +1,13 @@ -from duniterpy.documents import Block, BlockUID, Certification, Identity, Membership, \ - Revocation, Transaction, InputSource +from duniterpy.documents import ( + Block, + BlockUID, + Certification, + Identity, + Membership, + Revocation, + Transaction, + InputSource, +) from duniterpy.key import SigningKey import time import attr @@ -16,13 +24,20 @@ class BlockForge: """ The block forge generates a blockchain with a PoW of 1 """ + currency = attr.ib(validator=attr.validators.instance_of(str)) key = attr.ib(validator=attr.validators.instance_of(SigningKey)) - pool = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list)) - blocks = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list)) - user_identities = attr.ib(default=attr.Factory(dict), validator=attr.validators.instance_of(dict)) + pool = attr.ib( + default=attr.Factory(list), validator=attr.validators.instance_of(list) + ) + blocks = attr.ib( + default=attr.Factory(list), validator=attr.validators.instance_of(list) + ) + user_identities = attr.ib( + default=attr.Factory(dict), validator=attr.validators.instance_of(dict) + ) _ud = attr.ib(default=False, validator=attr.validators.instance_of(bool)) - _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('mirage'))) + _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger("mirage"))) @classmethod def start(cls, currency, salt, password, scrypt_params): @@ -67,17 +82,39 @@ class BlockForge: return [r for r in self.pool if type(r) is Revocation] def joiners(self): - return [d for d in self.pool if type(d) is Membership and d.membership_type == 'IN' - and ((d.issuer in self.user_identities and not self.user_identities[d.issuer].member) - or d.issuer in [d.pubkey for d in self.pool if type(d) is Identity])] + return [ + d + for d in self.pool + if type(d) is Membership + and d.membership_type == "IN" + and ( + ( + d.issuer in self.user_identities + and not self.user_identities[d.issuer].member + ) + or d.issuer in [d.pubkey for d in self.pool if type(d) is Identity] + ) + ] def actives(self): - return [d for d in self.pool if type(d) is Membership and d.membership_type == 'IN' - and d.issuer in self.user_identities and self.user_identities[d.issuer].member] + return [ + d + for d in self.pool + if type(d) is Membership + and d.membership_type == "IN" + and d.issuer in self.user_identities + and self.user_identities[d.issuer].member + ] def leavers(self): - return [d for d in self.pool if type(d) is Membership and d.membership_type == 'OUT' - and d.issuer in self.user_identities and self.user_identities[d.issuer].member] + return [ + d + for d in self.pool + if type(d) is Membership + and d.membership_type == "OUT" + and d.issuer in self.user_identities + and self.user_identities[d.issuer].member + ] def excluded(self): # for pylint @@ -93,8 +130,28 @@ class BlockForge: def parameters(self): if not self.blocks: - return 0.1, 86400, 100000, 10800, 40, 2629800, 31557600, 1, 604800, 604800,\ - 0.9, 15778800, 5, 12, 300, 25, 0.66, 1488970800, 1490094000, 15778800 + return ( + 0.1, + 86400, + 100000, + 10800, + 40, + 2629800, + 31557600, + 1, + 604800, + 604800, + 0.9, + 15778800, + 5, + 12, + 300, + 25, + 0.66, + 1488970800, + 1490094000, + 15778800, + ) return None def monetary_mass(self, number=None): @@ -105,10 +162,15 @@ class BlockForge: return mass def set_member(self, pubkey, member): - self._logger.info("Set {0} ({1}) as member : {2}".format(self.user_identities[pubkey].uid, - pubkey[:5], member)) + self._logger.info( + "Set {0} ({1}) as member : {2}".format( + self.user_identities[pubkey].uid, pubkey[:5], member + ) + ) self.user_identities[pubkey].member = member - self.user_identities[pubkey].was_member = self.user_identities[pubkey].was_member or member + self.user_identities[pubkey].was_member = ( + self.user_identities[pubkey].was_member or member + ) def generate_dividend(self): self._logger.info("Generate dividend") @@ -128,13 +190,35 @@ class BlockForge: certifications = self.certifications() transactions = self.transactions() - block = Block(10, self.currency, len(self.blocks), 1, int(time.time()), - int(time.time()), self.next_dividend(), 0, - self.key.pubkey, 5, 5, 5, previous_hash, previous_issuer, - parameters, members_count, identities, - joiners, actives, leavers, - revocations, excluded, certifications, - transactions, "", 0, None) + block = Block( + 10, + self.currency, + len(self.blocks), + 1, + int(time.time()), + int(time.time()), + self.next_dividend(), + 0, + self.key.pubkey, + 5, + 5, + 5, + previous_hash, + previous_issuer, + parameters, + members_count, + identities, + joiners, + actives, + leavers, + revocations, + excluded, + certifications, + transactions, + "", + 0, + None, + ) block.inner_hash = block.computed_inner_hash() return block @@ -142,67 +226,99 @@ class BlockForge: block = self.build_data() block.sign([self.key]) - block.noonce = int(random.random()*10000000) + block.noonce = int(random.random() * 10000000) self._logger.info("New block generated : {0}".format(block.blockUID)) self.blocks.append(block) for identity in block.identities: - self.user_identities[identity.pubkey] = UserIdentity(pubkey=identity.pubkey, uid=identity.uid, - blockstamp=identity.timestamp, - signature=identity.signatures[0], - was_member=True, - member=True) - self._logger.info("New identity : {0}".format(self.user_identities[identity.pubkey])) + self.user_identities[identity.pubkey] = UserIdentity( + pubkey=identity.pubkey, + uid=identity.uid, + blockstamp=identity.timestamp, + signature=identity.signatures[0], + was_member=True, + member=True, + ) + self._logger.info( + "New identity : {0}".format(self.user_identities[identity.pubkey]) + ) if block.ud: for identity in self.user_identities.values(): if identity.member: - identity.sources.append(InputSource(block.ud, block.unit_base, 'D', identity.pubkey, block.number)) - identity.ud_generated.append(UD(amount=block.ud, - base=block.unit_base, - block_number=block.number, - time=block.mediantime)) + identity.sources.append( + InputSource( + block.ud, + block.unit_base, + "D", + identity.pubkey, + block.number, + ) + ) + identity.ud_generated.append( + UD( + amount=block.ud, + base=block.unit_base, + block_number=block.number, + time=block.mediantime, + ) + ) for certification in block.certifications: - cert = Cert(from_identity=self.user_identities[certification.pubkey_from], - to_identity=self.user_identities[certification.pubkey_to], - signature=certification.signatures[0], - written_on=block.blockUID, - block=certification.timestamp.number, - mediantime=next(b.mediantime - for b in self.blocks if b.number == certification.timestamp.number)) + cert = Cert( + from_identity=self.user_identities[certification.pubkey_from], + to_identity=self.user_identities[certification.pubkey_to], + signature=certification.signatures[0], + written_on=block.blockUID, + block=certification.timestamp.number, + mediantime=next( + b.mediantime + for b in self.blocks + if b.number == certification.timestamp.number + ), + ) self.user_identities[certification.pubkey_from].certs_sent.append(cert) self.user_identities[certification.pubkey_to].certs_received.append(cert) for membership in block.joiners + block.actives + block.leavers: - self.user_identities[membership.issuer].memberships.append(MS(pubkey=membership.issuer, - type=membership.membership_type, - written_on=block.number, - blockstamp=membership.membership_ts, - timestamp=block.mediantime)) + self.user_identities[membership.issuer].memberships.append( + MS( + pubkey=membership.issuer, + type=membership.membership_type, + written_on=block.number, + blockstamp=membership.membership_ts, + timestamp=block.mediantime, + ) + ) for tx in block.transactions: - receivers = [o.conditions.left.pubkey for o in tx.outputs - if o.conditions.left.pubkey != tx.issuers[0]] + receivers = [ + o.conditions.left.pubkey + for o in tx.outputs + if o.conditions.left.pubkey != tx.issuers[0] + ] self.user_identities[tx.issuers[0]].tx_sent.append(tx) for input_source in tx.inputs: for s in self.user_identities[tx.issuers[0]].sources: - if s.origin_id == input_source.origin_id and s.index == input_source.index: + if ( + s.origin_id == input_source.origin_id + and s.index == input_source.index + ): self.user_identities[tx.issuers[0]].sources.remove(s) for i, output in enumerate(tx.outputs): if output.conditions.left.pubkey == tx.issuers[0]: - self.user_identities[tx.issuers[0]].sources.append(InputSource(output.amount, - output.base, - 'T', tx.sha_hash, i)) + self.user_identities[tx.issuers[0]].sources.append( + InputSource(output.amount, output.base, "T", tx.sha_hash, i) + ) self.user_identities[tx.issuers[0]].tx_received.append(tx) if len(receivers) > 0: for i, output in enumerate(tx.outputs): if output.conditions.left.pubkey == receivers[0]: - self.user_identities[receivers[0]].sources.append(InputSource(output.amount, - output.base, - 'T', tx.sha_hash, i)) + self.user_identities[receivers[0]].sources.append( + InputSource(output.amount, output.base, "T", tx.sha_hash, i) + ) self.user_identities[receivers[0]].tx_received.append(tx) self.pool = [] diff --git a/mirage/http.py b/mirage/http.py index 2a72f0605596f12c4d545c18b427a450471ab67a..92960d750e7f961fb1e61c8691dd9edf3834d1e6 100644 --- a/mirage/http.py +++ b/mirage/http.py @@ -12,7 +12,7 @@ class Request: def find_unused_port(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind(('127.0.0.1', 0)) + s.bind(("127.0.0.1", 0)) port = s.getsockname()[1] s.close() return port @@ -37,10 +37,13 @@ class HTTPServer: resp = await handler(request) return resp except web.HTTPNotFound: - return web.Response(status=404, body=bytes(json.dumps({"ucode":1001, - "message": "404 error"}), - "utf-8"), - headers={'Content-Type': 'application/json'}) + return web.Response( + status=404, + body=bytes( + json.dumps({"ucode": 1001, "message": "404 error"}), "utf-8" + ), + headers={"Content-Type": "application/json"}, + ) return middleware_handler @@ -48,24 +51,26 @@ class HTTPServer: await request.read() self.requests.append(Request(request.method, request.path, request.content)) json_data, http_code = await handle(request) - return web.Response(body=bytes(json.dumps(json_data), "utf-8"), - headers={'Content-Type': 'application/json'}, - status=http_code) + return web.Response( + body=bytes(json.dumps(json_data), "utf-8"), + headers={"Content-Type": "application/json"}, + status=http_code, + ) def add_route(self, req_type, url, handle): - self.app.router.add_route(req_type, url, - lambda request: self._handler(request, handle)) + self.app.router.add_route( + req_type, url, lambda request: self._handler(request, handle) + ) async def create_server(self, ssl_ctx=None): self.handler = self.app.make_handler( - keep_alive_on=False, - access_log=log.access_logger, + keep_alive_on=False, access_log=log.access_logger, ) self.port = find_unused_port() self.runner = web.AppRunner(self.app) await self.runner.setup() - site = web.TCPSite(self.runner, '127.0.0.1', self.port) + site = web.TCPSite(self.runner, "127.0.0.1", self.port) await site.start() protocol = "https" if ssl_ctx else "http" @@ -74,4 +79,4 @@ class HTTPServer: async def close(self): await self.handler.shutdown() - await self.runner.cleanup() \ No newline at end of file + await self.runner.cleanup() diff --git a/mirage/node.py b/mirage/node.py index 9cfd8319512aa0bcf57d4d4534763b6256081a2f..203e3ba587c94c3a948c7de9458c428cda955871 100644 --- a/mirage/node.py +++ b/mirage/node.py @@ -15,7 +15,7 @@ class Node: http = attr.ib() forge = attr.ib() reject_next_post = attr.ib(default=False) - _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('mirage'))) + _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger("mirage"))) @classmethod async def start(cls, port, currency, salt, password, loop): @@ -23,25 +23,25 @@ class Node: node = cls(HTTPServer(port, loop), BlockForge(currency, key)) get_routes = { - '/network/peering': node.peering, - '/blockchain/block/{number}': node.block_by_number, - '/blockchain/current': node.current_block, - '/tx/sources/{pubkey}': node.sources, - '/wot/lookup/{search}': node.lookup, - '/wot/certifiers-of/{search}': node.certifiers_of, - '/wot/certified-by/{search}': node.certified_by, - '/wot/requirements/{pubkey}': node.requirements, - '/blockchain/parameters': node.parameters, - '/blockchain/with/ud': node.with_ud, - '/blockchain/memberships/{search}': node.memberships, - '/tx/history/{search}': node.tx_history, - '/tx/history/{search}/blocks/{from}/{to}': node.tx_history_range, - '/ud/history/{search}': node.ud_history, + "/network/peering": node.peering, + "/blockchain/block/{number}": node.block_by_number, + "/blockchain/current": node.current_block, + "/tx/sources/{pubkey}": node.sources, + "/wot/lookup/{search}": node.lookup, + "/wot/certifiers-of/{search}": node.certifiers_of, + "/wot/certified-by/{search}": node.certified_by, + "/wot/requirements/{pubkey}": node.requirements, + "/blockchain/parameters": node.parameters, + "/blockchain/with/ud": node.with_ud, + "/blockchain/memberships/{search}": node.memberships, + "/tx/history/{search}": node.tx_history, + "/tx/history/{search}/blocks/{from}/{to}": node.tx_history_range, + "/ud/history/{search}": node.ud_history, } post_routes = { - '/wot/add': node.add, - '/wot/certify': node.certify, - '/tx/process': node.process + "/wot/add": node.add, + "/wot/certify": node.certify, + "/tx/process": node.process, } for r, h in get_routes.items(): node.http.add_route("GET", r, h) @@ -55,7 +55,7 @@ class Node: data = await request.post() if self.reject_next_post: self.reject_next_post = False - return {'ucode': errors.UNHANDLED, 'message': "Rejected"}, 400 + return {"ucode": errors.UNHANDLED, "message": "Rejected"}, 400 identity = Identity.from_signed_raw(data["identity"]) self.forge.pool.append(identity) return {}, 200 @@ -64,7 +64,7 @@ class Node: data = await request.post() if self.reject_next_post: self.reject_next_post = False - return {'ucode': errors.UNHANDLED, 'message': "Rejected"}, 400 + return {"ucode": errors.UNHANDLED, "message": "Rejected"}, 400 transaction = Transaction.from_signed_raw(data["transaction"]) self.forge.pool.append(transaction) return {}, 200 @@ -73,391 +73,448 @@ class Node: data = await request.post() if self.reject_next_post: self.reject_next_post = False - return {'ucode': errors.UNHANDLED, 'message': "Rejected"}, 400 + return {"ucode": errors.UNHANDLED, "message": "Rejected"}, 400 certification = Certification.from_signed_raw(data["cert"]) self.forge.pool.append(certification) return {}, 200 async def requirements(self, request): - pubkey = request.match_info['pubkey'] + pubkey = request.match_info["pubkey"] try: user_identity = self.forge.user_identities[pubkey] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == pubkey) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == pubkey + ) except StopIteration: - return { - 'ucode': errors.NO_MEMBER_MATCHING_PUB_OR_UID, - 'message': "No member matching this pubkey or uid" - }, 404 - return { - "identities": [ + return ( + { + "ucode": errors.NO_MEMBER_MATCHING_PUB_OR_UID, + "message": "No member matching this pubkey or uid", + }, + 404, + ) + return ( + { + "identities": [ + { + "pubkey": user_identity.pubkey, + "uid": user_identity.uid, + "meta": {"timestamp": str(user_identity.blockstamp),}, + "wasMember": user_identity.was_member, + "isSentry": True, + "revoked": user_identity.revoked, + "revocation_sig": user_identity.revocation_sig, + "revoked_on": user_identity.revoked_on, + "expired": user_identity.revoked, + "outdistanced": not user_identity.member, + "certifications": [ { - "pubkey": user_identity.pubkey, - "uid": user_identity.uid, - "meta": { - "timestamp": str(user_identity.blockstamp), - }, - "wasMember": user_identity.was_member, - "isSentry": True, - "revoked": user_identity.revoked, - "revocation_sig": user_identity.revocation_sig, - "revoked_on": user_identity.revoked_on, - "expired": user_identity.revoked, - "outdistanced": not user_identity.member, - "certifications": [ - { - "from": c.from_identity.pubkey, - "to": c.to_identity.pubkey, - "expiresIn": max(self.forge.blocks[-1].mediantime - 31557600 - c.mediantime, 0) - } for c in user_identity.certs_received - ], - "membershipPendingExpiresIn": 0 if not user_identity.member else 10000000, - "membershipExpiresIn": max(self.forge.blocks[-1].mediantime - 15778800 - - user_identity.memberships[-1].timestamp, 0) - }, - ] - }, 200 + "from": c.from_identity.pubkey, + "to": c.to_identity.pubkey, + "expiresIn": max( + self.forge.blocks[-1].mediantime + - 31557600 + - c.mediantime, + 0, + ), + } + for c in user_identity.certs_received + ], + "membershipPendingExpiresIn": 0 + if not user_identity.member + else 10000000, + "membershipExpiresIn": max( + self.forge.blocks[-1].mediantime + - 15778800 + - user_identity.memberships[-1].timestamp, + 0, + ), + }, + ] + }, + 200, + ) async def block_by_number(self, request): - number = int(request.match_info['number']) + number = int(request.match_info["number"]) try: block = self.forge.blocks[number] - return { - "version": block.version, - "nonce": block.noonce, - "number": block.number, - "powMin": block.powmin, - "time": block.time, - "medianTime": block.mediantime, - "membersCount": block.members_count, - "monetaryMass": self.forge.monetary_mass(number), - "unitbase": block.unit_base, - "issuersCount": block.different_issuers_count, - "issuersFrame": block.issuers_frame, - "issuersFrameVar": block.issuers_frame_var, - "currency": block.currency, - "issuer": block.issuer, - "signature": block.signatures[0], - "hash": block.sha_hash, - "parameters": block.parameters if block.parameters else "", - "previousHash": block.prev_hash, - "previousIssuer": block.prev_issuer, - "inner_hash": block.inner_hash, - "dividend": block.ud, - "identities": [i.inline() for i in block.identities], - "joiners": [m.inline() for m in block.joiners], - "actives": [m.inline() for m in block.actives], - "leavers": [m.inline() for m in block.leavers], - "revoked": [r.inline() for r in block.revoked], - "excluded": [i.inline() for i in block.excluded], - "certifications": [c.inline() for c in block.certifications], - "transactions": [t.compact() for t in block.transactions], - "raw": block.raw() - }, 200 + return ( + { + "version": block.version, + "nonce": block.noonce, + "number": block.number, + "powMin": block.powmin, + "time": block.time, + "medianTime": block.mediantime, + "membersCount": block.members_count, + "monetaryMass": self.forge.monetary_mass(number), + "unitbase": block.unit_base, + "issuersCount": block.different_issuers_count, + "issuersFrame": block.issuers_frame, + "issuersFrameVar": block.issuers_frame_var, + "currency": block.currency, + "issuer": block.issuer, + "signature": block.signatures[0], + "hash": block.sha_hash, + "parameters": block.parameters if block.parameters else "", + "previousHash": block.prev_hash, + "previousIssuer": block.prev_issuer, + "inner_hash": block.inner_hash, + "dividend": block.ud, + "identities": [i.inline() for i in block.identities], + "joiners": [m.inline() for m in block.joiners], + "actives": [m.inline() for m in block.actives], + "leavers": [m.inline() for m in block.leavers], + "revoked": [r.inline() for r in block.revoked], + "excluded": [i.inline() for i in block.excluded], + "certifications": [c.inline() for c in block.certifications], + "transactions": [t.compact() for t in block.transactions], + "raw": block.raw(), + }, + 200, + ) except IndexError: - return { - "ucode": errors.BLOCK_NOT_FOUND, - "message": "Block not found" - }, 404 + return {"ucode": errors.BLOCK_NOT_FOUND, "message": "Block not found"}, 404 async def current_block(self, request): try: block = self.forge.blocks[-1] - return { - "version": block.version, - "nonce": block.noonce, - "number": block.number, - "powMin": block.powmin, - "time": block.time, - "medianTime": block.mediantime, - "membersCount": block.members_count, - "monetaryMass": self.forge.monetary_mass(), - "unitbase": block.unit_base, - "issuersCount": block.different_issuers_count, - "issuersFrame": block.issuers_frame, - "issuersFrameVar": block.issuers_frame_var, - "currency": block.currency, - "issuer": block.issuer, - "signature": block.signatures[0], - "hash": block.computed_inner_hash(), - "parameters": block.parameters if block.parameters else "", - "previousHash": block.prev_hash, - "previousIssuer": block.prev_issuer, - "inner_hash": block.inner_hash, - "dividend": block.ud, - "identities": [ i.inline() for i in block.identities], - "joiners": [m.inline() for m in block.joiners], - "actives": [m.inline() for m in block.actives], - "leavers": [m.inline() for m in block.leavers], - "revoked": [r.inline() for r in block.revoked], - "excluded": [i.inline() for i in block.excluded], - "certifications": [c.inline() for c in block.certifications], - "transactions": [t.inline() for t in block.transactions], - "raw": block.raw() - }, 200 + return ( + { + "version": block.version, + "nonce": block.noonce, + "number": block.number, + "powMin": block.powmin, + "time": block.time, + "medianTime": block.mediantime, + "membersCount": block.members_count, + "monetaryMass": self.forge.monetary_mass(), + "unitbase": block.unit_base, + "issuersCount": block.different_issuers_count, + "issuersFrame": block.issuers_frame, + "issuersFrameVar": block.issuers_frame_var, + "currency": block.currency, + "issuer": block.issuer, + "signature": block.signatures[0], + "hash": block.computed_inner_hash(), + "parameters": block.parameters if block.parameters else "", + "previousHash": block.prev_hash, + "previousIssuer": block.prev_issuer, + "inner_hash": block.inner_hash, + "dividend": block.ud, + "identities": [i.inline() for i in block.identities], + "joiners": [m.inline() for m in block.joiners], + "actives": [m.inline() for m in block.actives], + "leavers": [m.inline() for m in block.leavers], + "revoked": [r.inline() for r in block.revoked], + "excluded": [i.inline() for i in block.excluded], + "certifications": [c.inline() for c in block.certifications], + "transactions": [t.inline() for t in block.transactions], + "raw": block.raw(), + }, + 200, + ) except IndexError: - return { - "ucode": errors.NO_CURRENT_BLOCK, - "message": "No current block" - }, 404 + return ( + {"ucode": errors.NO_CURRENT_BLOCK, "message": "No current block"}, + 404, + ) async def sources(self, request): - pubkey = str(request.match_info['pubkey']) + pubkey = str(request.match_info["pubkey"]) try: sources = self.forge.user_identities[pubkey].sources - return { - "currency": self.forge.currency, - "pubkey": pubkey, - "sources": [{ - 'type': s.source, - 'noffset': s.index, - 'identifier': s.origin_id, - 'amount': s.amount, - 'base': s.base, - 'conditions': "SIG({0})".format(pubkey) - } for s in sources] - }, 200 + return ( + { + "currency": self.forge.currency, + "pubkey": pubkey, + "sources": [ + { + "type": s.source, + "noffset": s.index, + "identifier": s.origin_id, + "amount": s.amount, + "base": s.base, + "conditions": "SIG({0})".format(pubkey), + } + for s in sources + ], + }, + 200, + ) except KeyError: - return { - "currency": self.forge.currency, - "pubkey": pubkey, - "sources": [] - }, 200 + return ( + {"currency": self.forge.currency, "pubkey": pubkey, "sources": []}, + 200, + ) async def peering(self, request): - return { - "version": 2, - "currency": self.peer_doc().currency, - "endpoints": [ - str(self.peer_doc().endpoints[0]) - ], - "status": "UP", - "block": str(self.peer_doc().blockUID), - "signature": self.peer_doc().signatures[0], - "raw": self.peer_doc().raw(), - "pubkey": self.peer_doc().pubkey - }, 200 + return ( + { + "version": 2, + "currency": self.peer_doc().currency, + "endpoints": [str(self.peer_doc().endpoints[0])], + "status": "UP", + "block": str(self.peer_doc().blockUID), + "signature": self.peer_doc().signatures[0], + "raw": self.peer_doc().raw(), + "pubkey": self.peer_doc().pubkey, + }, + 200, + ) async def parameters(self, request): - return { - "currency": self.forge.currency, - "c": 0.0025, - "dt": 86400, - "ud0": 100000, - "sigPeriod": 10800, - "sigStock": 40, - "sigWindow": 2629800, - "sigValidity": 31557600, - "sigQty": 1, - "idtyWindow": 604800, - "msWindow": 604800, - "xpercent": 0.9, - "msValidity": 15778800, - "stepMax": 5, - "medianTimeBlocks": 12, - "avgGenTime": 300, - "dtDiffEval": 25, - "blocksRot": 40, - "percentRot": 0.66, - "udTime0": 1488970800, - "udReevalTime0": 1490094000, - "dtReeval": 15778800 - - }, 200 + return ( + { + "currency": self.forge.currency, + "c": 0.0025, + "dt": 86400, + "ud0": 100000, + "sigPeriod": 10800, + "sigStock": 40, + "sigWindow": 2629800, + "sigValidity": 31557600, + "sigQty": 1, + "idtyWindow": 604800, + "msWindow": 604800, + "xpercent": 0.9, + "msValidity": 15778800, + "stepMax": 5, + "medianTimeBlocks": 12, + "avgGenTime": 300, + "dtDiffEval": 25, + "blocksRot": 40, + "percentRot": 0.66, + "udTime0": 1488970800, + "udReevalTime0": 1490094000, + "dtReeval": 15778800, + }, + 200, + ) async def with_ud(self, request): - return { - "result": { - "blocks": [b.number for b in self.forge.blocks if b.ud] - } - }, 200 + return ( + {"result": {"blocks": [b.number for b in self.forge.blocks if b.ud]}}, + 200, + ) async def memberships(self, request): - search = str(request.match_info['search']) + search = str(request.match_info["search"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == search + ) except StopIteration: - return { - 'ucode': errors.NO_MEMBER_MATCHING_PUB_OR_UID, - 'message': "No member matching this pubkey or uid" - }, 404 + return ( + { + "ucode": errors.NO_MEMBER_MATCHING_PUB_OR_UID, + "message": "No member matching this pubkey or uid", + }, + 404, + ) - return { - "pubkey": user_identity.pubkey, - "uid": user_identity.uid, - "sigDate": str(user_identity.blockstamp), - "memberships": [ - { - "version": 2, - "currency": self.forge.currency, - "membership": m.type, - "blockNumber": m.blockstamp.number, - "blockHash": m.blockstamp.sha_hash, - "written": m.written_on - } - for m in user_identity.memberships - ] - }, 200 + return ( + { + "pubkey": user_identity.pubkey, + "uid": user_identity.uid, + "sigDate": str(user_identity.blockstamp), + "memberships": [ + { + "version": 2, + "currency": self.forge.currency, + "membership": m.type, + "blockNumber": m.blockstamp.number, + "blockHash": m.blockstamp.sha_hash, + "written": m.written_on, + } + for m in user_identity.memberships + ], + }, + 200, + ) async def certifiers_of(self, request): - search = str(request.match_info['search']) + search = str(request.match_info["search"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == search + ) except StopIteration: - return { - 'ucode': errors.NO_MEMBER_MATCHING_PUB_OR_UID, - 'message': "No member matching this pubkey or uid" - }, 404 - - return { - "pubkey": user_identity.pubkey, - "uid": user_identity.uid, - "sigDate": str(user_identity.blockstamp), - "isMember": user_identity.member, - "certifications": [ - { - "pubkey": c.from_identity.pubkey, - "uid": c.from_identity.uid, - "isMember": c.from_identity.member, - "wasMember": c.from_identity.was_member, - "cert_time": { - "block": c.block, - "medianTime": c.mediantime - }, - "sigDate": str(c.from_identity.blockstamp), - "written": { - "number": c.written_on.number, - "hash": c.written_on.sha_hash + return ( + { + "ucode": errors.NO_MEMBER_MATCHING_PUB_OR_UID, + "message": "No member matching this pubkey or uid", }, - "signature": c.signature - } - for c in user_identity.certs_received - ] - }, 200 + 404, + ) + + return ( + { + "pubkey": user_identity.pubkey, + "uid": user_identity.uid, + "sigDate": str(user_identity.blockstamp), + "isMember": user_identity.member, + "certifications": [ + { + "pubkey": c.from_identity.pubkey, + "uid": c.from_identity.uid, + "isMember": c.from_identity.member, + "wasMember": c.from_identity.was_member, + "cert_time": {"block": c.block, "medianTime": c.mediantime}, + "sigDate": str(c.from_identity.blockstamp), + "written": { + "number": c.written_on.number, + "hash": c.written_on.sha_hash, + }, + "signature": c.signature, + } + for c in user_identity.certs_received + ], + }, + 200, + ) async def certified_by(self, request): - search = str(request.match_info['search']) + search = str(request.match_info["search"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == search + ) except StopIteration: - return { - 'ucode': errors.NO_MEMBER_MATCHING_PUB_OR_UID, - 'message': "No member matching this pubkey or uid" - }, 404 - - return { - "pubkey": user_identity.pubkey, - "uid": user_identity.uid, - "sigDate": str(user_identity.blockstamp), - "isMember": user_identity.member, - "certifications": [ - { - "pubkey": c.from_identity.pubkey, - "uid": c.from_identity.uid, - "isMember": c.from_identity.member, - "wasMember": c.from_identity.was_member, - "cert_time": { - "block": c.block, - "medianTime": c.mediantime + return ( + { + "ucode": errors.NO_MEMBER_MATCHING_PUB_OR_UID, + "message": "No member matching this pubkey or uid", }, - "sigDate": str(c.from_identity.blockstamp), - "written": { - "number": c.written_on.number, - "hash": c.written_on.sha_hash - }, - "signature": c.signature - } - for c in user_identity.certs_sent - ] - }, 200 + 404, + ) + + return ( + { + "pubkey": user_identity.pubkey, + "uid": user_identity.uid, + "sigDate": str(user_identity.blockstamp), + "isMember": user_identity.member, + "certifications": [ + { + "pubkey": c.from_identity.pubkey, + "uid": c.from_identity.uid, + "isMember": c.from_identity.member, + "wasMember": c.from_identity.was_member, + "cert_time": {"block": c.block, "medianTime": c.mediantime}, + "sigDate": str(c.from_identity.blockstamp), + "written": { + "number": c.written_on.number, + "hash": c.written_on.sha_hash, + }, + "signature": c.signature, + } + for c in user_identity.certs_sent + ], + }, + 200, + ) async def lookup(self, request): - search = str(request.match_info['search']) - matched = [i for i in self.forge.user_identities.values() if search in i.pubkey or search in i.uid] + search = str(request.match_info["search"]) + matched = [ + i + for i in self.forge.user_identities.values() + if search in i.pubkey or search in i.uid + ] - return { - "partial": False, - "results": [ - { - "pubkey": m.pubkey, - "uids": [ - { - "uid": m.uid, - "meta": { - "timestamp": str(m.blockstamp), - }, - "revoked": m.revoked, - "revoked_on": m.revoked_on, - "revocation_sig": m.revocation_sig, - "self": m.signature, - "others": [ - { - "pubkey": c.to_identity.pubkey, - "meta": { - "block_number": c.block, - }, - "uids": [c.to_identity.uid], - "isMember": c.to_identity.member, - "wasMember": c.to_identity.was_member, - "signature": c.signature - } for c in m.certs_received - ], - } - ], - "signed": [ - { - "pubkey": c.to_identity.pubkey, - "meta": { - "timestamp": str(c.to_identity.blockstamp), - }, - "cert_time": { - "block": c.block, - "block_hash": str(self.forge.blocks[c.block].blockUID) - }, - "uid": c.to_identity.uid, - "isMember": c.to_identity.member, - "wasMember": c.to_identity.was_member, - "revoked": c.to_identity.revoked, - "revoked_on": c.to_identity.revoked_on, - "revocation_sig": c.to_identity.revocation_sig, - "signature": c.signature - } for c in m.certs_sent - ] - } - for m in matched - ] - }, 200 + return ( + { + "partial": False, + "results": [ + { + "pubkey": m.pubkey, + "uids": [ + { + "uid": m.uid, + "meta": {"timestamp": str(m.blockstamp),}, + "revoked": m.revoked, + "revoked_on": m.revoked_on, + "revocation_sig": m.revocation_sig, + "self": m.signature, + "others": [ + { + "pubkey": c.to_identity.pubkey, + "meta": {"block_number": c.block,}, + "uids": [c.to_identity.uid], + "isMember": c.to_identity.member, + "wasMember": c.to_identity.was_member, + "signature": c.signature, + } + for c in m.certs_received + ], + } + ], + "signed": [ + { + "pubkey": c.to_identity.pubkey, + "meta": {"timestamp": str(c.to_identity.blockstamp),}, + "cert_time": { + "block": c.block, + "block_hash": str( + self.forge.blocks[c.block].blockUID + ), + }, + "uid": c.to_identity.uid, + "isMember": c.to_identity.member, + "wasMember": c.to_identity.was_member, + "revoked": c.to_identity.revoked, + "revoked_on": c.to_identity.revoked_on, + "revocation_sig": c.to_identity.revocation_sig, + "signature": c.signature, + } + for c in m.certs_sent + ], + } + for m in matched + ], + }, + 200, + ) async def tx_history(self, request): - search = str(request.match_info['search']) + search = str(request.match_info["search"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == search + ) except StopIteration: - return { - "currency": self.forge.currency, - "pubkey": search, - "history": { - "sent": [], - "received": [], - "sending": [], - "receiving": [], - "pending": [] - } - }, 200 - return { + return ( + { + "currency": self.forge.currency, + "pubkey": search, + "history": { + "sent": [], + "received": [], + "sending": [], + "receiving": [], + "pending": [], + }, + }, + 200, + ) + return ( + { "currency": self.forge.currency, "pubkey": user_identity.pubkey, "history": { @@ -471,14 +528,31 @@ class Node: "comment": tx.comment, "locktime": tx.locktime, "blockstamp": str(tx.blockstamp), - "blockstampTime": next([b.mediantime for b in self.forge.blocks - if b.number == tx.blockstamp.number]), + "blockstampTime": next( + [ + b.mediantime + for b in self.forge.blocks + if b.number == tx.blockstamp.number + ] + ), "signatures": tx.signatures, "hash": tx.sha_hash, - "block_number": next((b.number for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])), - "time": next((b.mediantime for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])) + "block_number": next( + ( + b.number + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), + "time": next( + ( + b.mediantime + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), } for tx in user_identity.tx_sent ], @@ -492,46 +566,73 @@ class Node: "comment": tx.comment, "locktime": tx.locktime, "blockstamp": str(tx.blockstamp), - "blockstampTime": next([b.mediantime for b in self.forge.blocks - if b.number == tx.blockstamp.number]), + "blockstampTime": next( + [ + b.mediantime + for b in self.forge.blocks + if b.number == tx.blockstamp.number + ] + ), "signatures": tx.signatures, "hash": tx.sha_hash, - "block_number": next((b.number for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])), - "time": next((b.mediantime for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])) + "block_number": next( + ( + b.number + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), + "time": next( + ( + b.mediantime + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), } for tx in user_identity.tx_received ], "sending": [], "receiving": [], - "pending": [] - } - }, 200 + "pending": [], + }, + }, + 200, + ) async def tx_history_range(self, request): try: - search = str(request.match_info['search']) - start = int(request.match_info['from']) + search = str(request.match_info["search"]) + start = int(request.match_info["from"]) end = int(request.match_info["to"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i + for i in self.forge.user_identities.values() + if i.uid == search + ) except StopIteration: - return { - "currency": self.forge.currency, - "pubkey": search, - "history": { - "sent": [], - "received": [], - "sending": [], - "receiving": [], - "pending": [] - } - }, 200 - return { + return ( + { + "currency": self.forge.currency, + "pubkey": search, + "history": { + "sent": [], + "received": [], + "sending": [], + "receiving": [], + "pending": [], + }, + }, + 200, + ) + return ( + { "currency": self.forge.currency, "pubkey": user_identity.pubkey, "history": { @@ -545,16 +646,34 @@ class Node: "comment": tx.comment, "locktime": tx.locktime, "blockstamp": str(tx.blockstamp), - "blockstampTime": next((b.mediantime for b in self.forge.blocks - if b.number == tx.blockstamp.number)), + "blockstampTime": next( + ( + b.mediantime + for b in self.forge.blocks + if b.number == tx.blockstamp.number + ) + ), "signatures": tx.signatures, "hash": tx.sha_hash, - "block_number": next((b.number for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])), - "time": next((b.mediantime for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])) + "block_number": next( + ( + b.number + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), + "time": next( + ( + b.mediantime + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), } - for tx in user_identity.tx_sent if start <= tx.blockstamp.number <= end + for tx in user_identity.tx_sent + if start <= tx.blockstamp.number <= end ], "received": [ { @@ -566,56 +685,85 @@ class Node: "comment": tx.comment, "locktime": tx.locktime, "blockstamp": str(tx.blockstamp), - "blockstampTime": next((b.mediantime for b in self.forge.blocks - if b.number == tx.blockstamp.number)), + "blockstampTime": next( + ( + b.mediantime + for b in self.forge.blocks + if b.number == tx.blockstamp.number + ) + ), "signatures": tx.signatures, "hash": tx.sha_hash, - "block_number": next((b.number for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])), - "time": next((b.mediantime for b in self.forge.blocks - if tx.sha_hash in [tx.sha_hash for tx in b.transactions])) + "block_number": next( + ( + b.number + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), + "time": next( + ( + b.mediantime + for b in self.forge.blocks + if tx.sha_hash + in [tx.sha_hash for tx in b.transactions] + ) + ), } - for tx in user_identity.tx_received if start <= tx.blockstamp.number <= end + for tx in user_identity.tx_received + if start <= tx.blockstamp.number <= end ], "sending": [], "receiving": [], - "pending": [] - } - }, 200 + "pending": [], + }, + }, + 200, + ) except Exception as e: print(str(e)) async def ud_history(self, request): - search = str(request.match_info['search']) + search = str(request.match_info["search"]) try: user_identity = self.forge.user_identities[search] except KeyError: try: - user_identity = next(i for i in self.forge.user_identities.values() if i.uid == search) + user_identity = next( + i for i in self.forge.user_identities.values() if i.uid == search + ) except StopIteration: - return { - "currency": self.forge.currency, - "pubkey": search, - "history": { - "history": [], - } - }, 200 - return { + return ( + { + "currency": self.forge.currency, + "pubkey": search, + "history": {"history": [],}, + }, + 200, + ) + return ( + { "currency": self.forge.currency, "pubkey": user_identity.pubkey, "history": { - "history": [ - attr.asdict(ud) - for ud in user_identity.ud_generated - ] - } - }, 200 + "history": [attr.asdict(ud) for ud in user_identity.ud_generated] + }, + }, + 200, + ) def peer_doc(self): - peer = Peer(2, self.forge.currency, self.forge.key.pubkey, BlockUID.empty(), - [BMAEndpoint(None, "127.0.0.1", None, self.http.port)], None) + peer = Peer( + 2, + self.forge.currency, + self.forge.key.pubkey, + BlockUID.empty(), + [BMAEndpoint(None, "127.0.0.1", None, self.http.port)], + None, + ) peer.sign([self.forge.key]) return peer async def close(self): - await self.http.close() \ No newline at end of file + await self.http.close() diff --git a/mirage/user.py b/mirage/user.py index ffcaff6abd4c652bd953dbcdebe220667d78955f..d22ec69910940ff4732b8d242f116b235c17444a 100644 --- a/mirage/user.py +++ b/mirage/user.py @@ -1,7 +1,15 @@ import attr import logging -from duniterpy.documents import Identity, Membership, BlockUID, Certification, \ - OutputSource, Transaction, Unlock, SIGParameter +from duniterpy.documents import ( + Identity, + Membership, + BlockUID, + Certification, + OutputSource, + Transaction, + Unlock, + SIGParameter, +) from duniterpy.documents.transaction import reduce_base from duniterpy.grammars import output from duniterpy.key import SigningKey @@ -30,12 +38,17 @@ def outputs_from_sources(amount, sources): test_sources = result_sources + [s] # if we have to compute an overhead if current_value(test_sources, overheads) > amount * (10 ** amount_base): - overhead = current_value(test_sources, overheads) - int(amount) * (10 ** amount_base) + overhead = current_value(test_sources, overheads) - int(amount) * ( + 10 ** amount_base + ) # we round the overhead in the current base # exemple : 12 in base 1 -> 1*10^1 overhead = int(round(float(overhead) / (10 ** current_base))) source_value = s.amount * (10 ** s.base) - out = int((source_value - (overhead * (10 ** current_base))) / (10 ** current_base)) + out = int( + (source_value - (overhead * (10 ** current_base))) + / (10 ** current_base) + ) if out * (10 ** current_base) <= amount * (10 ** amount_base): result_sources.append(s) buf_sources.remove(s) @@ -58,6 +71,7 @@ class User: """ The user generates identities documents and sign them """ + SCRYPT_PARAMS = ScryptParams(2 ** 12, 16, 1) currency = attr.ib(validator=attr.validators.instance_of(str)) @@ -66,33 +80,59 @@ class User: salt = attr.ib(validator=attr.validators.instance_of(str)) password = attr.ib(validator=attr.validators.instance_of(str)) blockstamp = attr.ib(validator=attr.validators.instance_of(BlockUID)) - _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger('mirage'))) + _logger = attr.ib(default=attr.Factory(lambda: logging.getLogger("mirage"))) @classmethod def create(cls, currency, uid, salt, password, blockstamp): - return cls(currency, uid, SigningKey.from_credentials(salt, password, User.SCRYPT_PARAMS), salt, password, - blockstamp) + return cls( + currency, + uid, + SigningKey.from_credentials(salt, password, User.SCRYPT_PARAMS), + salt, + password, + blockstamp, + ) def identity(self): - identity = Identity(10, self.currency, self.key.pubkey, self.uid, self.blockstamp, None) + identity = Identity( + 10, self.currency, self.key.pubkey, self.uid, self.blockstamp, None + ) identity.sign([self.key]) return identity def join(self, blockstamp): - ms_doc = Membership(10, self.currency, self.key.pubkey, blockstamp, - 'IN', self.uid, self.blockstamp, None) + ms_doc = Membership( + 10, + self.currency, + self.key.pubkey, + blockstamp, + "IN", + self.uid, + self.blockstamp, + None, + ) ms_doc.sign([self.key]) return ms_doc def leave(self, blockstamp): - ms_doc = Membership(10, self.currency, self.key.pubkey, blockstamp, - 'OUT', self.uid, self.blockstamp, None) + ms_doc = Membership( + 10, + self.currency, + self.key.pubkey, + blockstamp, + "OUT", + self.uid, + self.blockstamp, + None, + ) ms_doc.sign([self.key]) return ms_doc def certify(self, other, blockstamp): - cert = Certification(10, self.currency, self.key.pubkey, other.identity(), blockstamp, None) + cert = Certification( + 10, self.currency, self.key.pubkey, other.identity(), blockstamp, None + ) cert.sign([self.key]) return cert @@ -104,8 +144,15 @@ class User: for o in outputs: if o[1] == base: output_sum += o[0] - total.append(OutputSource(output_sum, base, output.Condition.token(output.SIG.token(receiver.key.pubkey)) - .compose(output.Condition()))) + total.append( + OutputSource( + output_sum, + base, + output.Condition.token( + output.SIG.token(receiver.key.pubkey) + ).compose(output.Condition()), + ) + ) overheads_bases = set(o[1] for o in overheads) for base in overheads_bases: @@ -113,8 +160,15 @@ class User: for o in overheads: if o[1] == base: overheads_sum += o[0] - total.append(OutputSource(overheads_sum, base, output.Condition.token(output.SIG.token(self.key.pubkey)) - .compose(output.Condition()))) + total.append( + OutputSource( + overheads_sum, + base, + output.Condition.token(output.SIG.token(self.key.pubkey)).compose( + output.Condition() + ), + ) + ) return total @@ -130,8 +184,17 @@ class User: unlocks.append(Unlock(i, [SIGParameter(0)])) outputs = self.tx_outputs(receiver, computed_outputs, overheads) - tx = Transaction(3, self.currency, blockstamp, 0, - [self.key.pubkey], inputs, unlocks, - outputs, message, []) + tx = Transaction( + 3, + self.currency, + blockstamp, + 0, + [self.key.pubkey], + inputs, + unlocks, + outputs, + message, + [], + ) tx.sign([self.key]) return tx