From 3e7af6ee47e3efb525c39f9299a028fdcaa397e0 Mon Sep 17 00:00:00 2001 From: Oleg Silkin Date: Fri, 9 Aug 2019 00:52:34 -0400 Subject: [PATCH] Adds script to count valid signatures in the database --- scripts/valid_signatures.py | 84 +++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 scripts/valid_signatures.py diff --git a/scripts/valid_signatures.py b/scripts/valid_signatures.py new file mode 100644 index 0000000..cc206d8 --- /dev/null +++ b/scripts/valid_signatures.py @@ -0,0 +1,84 @@ +import binascii +import hashlib +import json +import sqlite3 +import asyncio + +import aiohttp + +from src.server.misc import is_signature_valid, get_encoded_signature +from src.server.database import clean + + +async def request_lbrynet(url, method, **params): + body = {'method': method, 'params': {**params}} + async with aiohttp.request('POST', url, json=body) as req: + try: + resp = await req.json() + finally: + if 'result' in resp: + return resp['result'] + + +def get_comments_with_signatures(_conn: sqlite3.Connection) -> list: + with _conn: + curs = _conn.execute("SELECT * FROM COMMENTS_ON_CLAIMS WHERE signature IS NOT NULL") + return [dict(r) for r in curs.fetchall()] + + +def is_valid_signature(pubkey, channel_id, signature, signing_ts, data: str) -> bool: + try: + if pubkey: + claim_hash = binascii.unhexlify(channel_id.encode())[::-1] + injest = b''.join((signing_ts.encode(), claim_hash, data.encode())) + return is_signature_valid( + encoded_signature=get_encoded_signature(signature), + signature_digest=hashlib.sha256(injest).digest(), + public_key_bytes=binascii.unhexlify(pubkey.encode()) + ) + else: + raise Exception("Pubkey is null") + except Exception as e: + print(e) + return False + + +async def get_channel_pubkeys(comments: list): + urls = {c['channel_url'] for c in comments} + claims = await request_lbrynet('http://localhost:5279', 'resolve', urls=list(urls)) + cids = {c['channel_id']: None for c in comments} + error_claims = [] + for url, claim in claims.items(): + if 'error' not in claim: + cids.update({ + claim['claim_id']: claim['value']['public_key'] + }) + else: + error_claims.append({url: claim}) + return cids, error_claims + + +def count_valid_signatures(cmts: list, chan_pubkeys: dict): + invalid_comments = [] + for c in cmts: + pubkey = chan_pubkeys.get(c['channel_id']) + if not is_valid_signature(pubkey, c['channel_id'], c['signature'], c['signing_ts'], c['comment']): + invalid_comments.append(c) + return len(cmts) - len(invalid_comments), invalid_comments + + +if __name__ == '__main__': + conn = sqlite3.connect('database/default.db') + conn.row_factory = sqlite3.Row + comments = get_comments_with_signatures(conn) + loop = asyncio.get_event_loop() + chan_keys, errored = loop.run_until_complete(get_channel_pubkeys(comments)) + valid_sigs, invalid_coms = count_valid_signatures(comments, chan_keys) + print(f'Total Signatures: {len(comments)}\nValid Signatures: {valid_sigs}') + print(f'Invalid Signatures: {len(comments) - valid_sigs}') + print(f'Percent Valid: {round(valid_sigs/len(comments)*100, 3)}%') + print(f'# Unresolving claims: {len(errored)}') + print(f'Num invalid comments: {len(invalid_coms)}') + print(json.dumps(errored, indent=2)) + json.dump(invalid_coms, 'invalid_coms.json', indent=2) +