From 248963ce90424c9cbec4bff155117fcbd45a74e6 Mon Sep 17 00:00:00 2001 From: Believethehype Date: Mon, 27 Nov 2023 10:35:58 +0100 Subject: [PATCH] fixing the decrypted tags thing --- bot.py | 12 ++--- dvm.py | 49 ++++++++++---------- tasks/imagegeneration_openai_dalle.py | 2 +- tasks/imagegeneration_sdxl.py | 2 +- tasks/textextractionpdf.py | 2 +- tasks/translation.py | 2 +- test_dvm_client.py | 32 ++----------- utils/backend_utils.py | 22 +++++---- utils/nostr_utils.py | 65 ++++++++++++++------------- 9 files changed, 87 insertions(+), 101 deletions(-) diff --git a/bot.py b/bot.py index 21cc454..a9b2e52 100644 --- a/bot.py +++ b/bot.py @@ -136,15 +136,16 @@ class Bot: bid_tag = Tag.parse(['bid', bid, bid]) relays_tag = Tag.parse(["relays", json.dumps(self.dvm_config.RELAY_LIST)]) alt_tag = Tag.parse(["alt", self.dvm_config.SUPPORTED_DVMS[index].TASK]) + p_tag = Tag.parse(['p', dvm_keys.public_key().to_hex()]) encrypted_params_string = json.dumps([i_tag.as_vec(), bid_tag.as_vec(), - relays_tag.as_vec(), alt_tag.as_vec()]) + relays_tag.as_vec(), alt_tag.as_vec(), p_tag.as_vec()]) print(encrypted_params_string) encrypted_params = nip04_encrypt(self.keys.secret_key(), dvm_keys.public_key(), encrypted_params_string) - p_tag = Tag.parse(['p', dvm_keys.public_key().to_hex()]) + encrypted_tag = Tag.parse(['encrypted']) nip90request = EventBuilder(self.dvm_config.SUPPORTED_DVMS[index].KIND, encrypted_params, [p_tag, encrypted_tag]).to_event(self.keys) @@ -220,14 +221,14 @@ class Bot: elif status == "payment-required" or status == "partial": amount = 0 + for tag in nostr_event.tags(): if tag.as_vec()[0] == "amount": amount_msats = int(tag.as_vec()[1]) amount = int(amount_msats / 1000) - entry = next((x for x in self.job_list if x['event_id'] == etag), None) if entry is not None and entry['is_paid'] is False and entry['dvm_key'] == ptag: - + print("PAYMENT: " + nostr_event.as_json()) #if we get a bolt11, we pay and move on if len(tag.as_vec()) > 2: bolt11 = tag.as_vec()[2] @@ -236,7 +237,8 @@ class Bot: else: user = get_or_add_user(db=self.dvm_config.DB, npub=nostr_event.pubkey().to_hex(), client=self.client, config=self.dvm_config) - bolt11 = zap(user.lud16, amount, "Zap", nostr_event, self.keys, self.dvm_config, "private") + print("PAYING: " + user.name) + bolt11 = zap(user.lud16, amount, "Zap", nostr_event, self.keys, self.dvm_config, "public") if bolt11 == None: print("Receiver has no Lightning address") return diff --git a/dvm.py b/dvm.py index 005026e..3d3af7f 100644 --- a/dvm.py +++ b/dvm.py @@ -83,24 +83,24 @@ class DVM: return def handle_nip90_job_event(nip90_event): - """ - :type nip90_event: Event - """ - tags: typing.List[Tag] - tags, p_tag_str = check_and_decrypt_tags(nip90_event, self.dvm_config) - if p_tag_str is None: + nip90_event = check_and_decrypt_tags(nip90_event, self.dvm_config) + if nip90_event is None: return - nip90_event.tags = tags - cashu = "" - for tag in tags: - if tag.as_vec()[0] == "cashu": - cashu = tag.as_vec()[0] user = get_or_add_user(self.dvm_config.DB, nip90_event.pubkey().to_hex(), client=self.client, config=self.dvm_config) - task_supported, task, duration = check_task_is_supported(nip90_event, tags, client=self.client, + + cashu = "" + p_tag_str = "" + for tag in nip90_event.tags(): + if tag.as_vec()[0] == "cashu": + cashu = tag.as_vec()[0] + elif tag.as_vec()[0] == "p": + p_tag_str = tag.as_vec()[0] + + task_supported, task, duration = check_task_is_supported(nip90_event, client=self.client, get_duration=(not user.iswhitelisted), config=self.dvm_config) @@ -134,6 +134,7 @@ class DVM: do_work(nip90_event) # if task is directed to us via p tag and user has balance, do the job and update balance + elif p_tag_str == Keys.from_sk_str( self.dvm_config.PRIVATE_KEY).public_key().to_hex() and user.balance >= amount: balance = max(user.balance - amount, 0) @@ -155,7 +156,7 @@ class DVM: # else send a payment required event to user else: bid = 0 - for tag in nip90_event.tags: + for tag in nip90_event.tags(): if tag.as_vec()[0] == 'bid': bid = int(tag.as_vec()[1]) @@ -177,14 +178,15 @@ class DVM: False, amount, client=self.client, dvm_config=self.dvm_config) else: - print("Task not supported on this DVM, skipping..") + print("[" + self.dvm_config.NIP89.name + "] Task " + task + " not supported on this DVM, skipping..") def handle_zap(zap_event): try: invoice_amount, zapped_event, sender, message, anon = parse_zap_event_tags(zap_event, - self.keys, self.dvm_config.NIP89.name, - self.client, self.dvm_config) + self.keys, + self.dvm_config.NIP89.name, + self.client, self.dvm_config) user = get_or_add_user(db=self.dvm_config.DB, npub=sender, client=self.client, config=self.dvm_config) if zapped_event is not None: @@ -198,16 +200,17 @@ class DVM: amount = int(float(tag.as_vec()[1]) / 1000) elif tag.as_vec()[0] == 'e': job_event = get_event_by_id(tag.as_vec()[1], client=self.client, config=self.dvm_config) - tags: typing.List[Tag] - tags, p_tag_str = check_and_decrypt_tags(job_event, self.dvm_config) - job_event.tags = tags + if job_event is not None: + job_event = check_and_decrypt_tags(job_event, self.dvm_config) + else: + return if p_tag_str is None: return - # if a reaction by us got zapped + # if a reaction by us got zapped - task_supported, task, duration = check_task_is_supported(job_event, tags, + task_supported, task, duration = check_task_is_supported(job_event, client=self.client, get_duration=False, config=self.dvm_config) @@ -263,7 +266,7 @@ class DVM: print("[" + self.dvm_config.NIP89.name + "] Error during content decryption: " + str(e)) def check_event_has_not_unfinished_job_input(nevent, append, client, dvmconfig): - task_supported, task, duration = check_task_is_supported(nevent, nevent.tags, client, False, + task_supported, task, duration = check_task_is_supported(nevent, client, False, config=dvmconfig) if not task_supported: return False @@ -372,7 +375,7 @@ class DVM: status_tag = Tag.parse(["status", status]) tags = [e_tag, alt_tag, status_tag] - for tag in original_event.tags: + for tag in original_event.tags(): if tag.as_vec()[0] == "p": p_tag = tag diff --git a/tasks/imagegeneration_openai_dalle.py b/tasks/imagegeneration_openai_dalle.py index f2801a5..1b1784a 100644 --- a/tasks/imagegeneration_openai_dalle.py +++ b/tasks/imagegeneration_openai_dalle.py @@ -46,7 +46,7 @@ class ImageGenerationDALLE(DVMTaskInterface): model = "dall-e-3" quality = "standard" - for tag in event.tags: + for tag in event.tags(): if tag.as_vec()[0] == 'i': input_type = tag.as_vec()[2] if input_type == "text": diff --git a/tasks/imagegeneration_sdxl.py b/tasks/imagegeneration_sdxl.py index b9e5de2..df07576 100644 --- a/tasks/imagegeneration_sdxl.py +++ b/tasks/imagegeneration_sdxl.py @@ -55,7 +55,7 @@ class ImageGenerationSDXL(DVMTaskInterface): lora_weight = "" strength = "" guidance_scale = "" - for tag in event.tags: + for tag in event.tags(): if tag.as_vec()[0] == 'i': input_type = tag.as_vec()[2] if input_type == "text": diff --git a/tasks/textextractionpdf.py b/tasks/textextractionpdf.py index 1bf9639..ba85899 100644 --- a/tasks/textextractionpdf.py +++ b/tasks/textextractionpdf.py @@ -43,7 +43,7 @@ class TextExtractionPDF(DVMTaskInterface): input_content = "" url = "" - for tag in event.tags: + for tag in event.tags(): if tag.as_vec()[0] == 'i': input_type = tag.as_vec()[2] input_content = tag.as_vec()[1] diff --git a/tasks/translation.py b/tasks/translation.py index 8ed23d0..fd97c1a 100644 --- a/tasks/translation.py +++ b/tasks/translation.py @@ -42,7 +42,7 @@ class Translation(DVMTaskInterface): text = "" translation_lang = "en" - for tag in event.tags: + for tag in event.tags(): if tag.as_vec()[0] == 'i': input_type = tag.as_vec()[2] diff --git a/test_dvm_client.py b/test_dvm_client.py index 60742e9..e8875a3 100644 --- a/test_dvm_client.py +++ b/test_dvm_client.py @@ -71,6 +71,7 @@ def nostr_client_test_image(prompt): def nostr_client_test_image_private(prompt, cashutoken): keys = Keys.from_sk_str(os.getenv("NOSTR_TEST_CLIENT_PRIVATE_KEY")) + receiver_keys = Keys.from_sk_str(os.getenv("NOSTR_PRIVATE_KEY")) # TODO more advanced logic, more parsing, params etc, just very basic test functions for now @@ -92,7 +93,7 @@ def nostr_client_test_image_private(prompt, cashutoken): relays_tag.as_vec(), alt_tag.as_vec(), cashu_tag.as_vec()]) - encrypted_params = nip04_encrypt(keys.secret_key(), keys.public_key(), + encrypted_params = nip04_encrypt(keys.secret_key(), receiver_keys.public_key(), encrypted_params_string) p_tag = Tag.parse(['p', keys.public_key().to_hex()]) @@ -107,31 +108,6 @@ def nostr_client_test_image_private(prompt, cashutoken): send_event(nip90request, client=client, dvm_config=config) return nip90request.as_json() - - - iTag = Tag.parse(["i", prompt, "text"]) - outTag = Tag.parse(["output", "image/png;format=url"]) - paramTag1 = Tag.parse(["param", "size", "1024x1024"]) - tTag = Tag.parse(["t", "bitcoin"]) - - bidTag = Tag.parse(['bid', str(1000 * 1000), str(1000 * 1000)]) - relaysTag = Tag.parse(['relays', "wss://relay.damus.io", "wss://blastr.f7z.xyz", "wss://relayable.org", - "wss://nostr-pub.wellorder.net"]) - alttag = Tag.parse(["alt", "This is a NIP90 DVM AI task to translate a given Input"]) - event = EventBuilder(EventDefinitions.KIND_NIP90_GENERATE_IMAGE, str("Generate an Image."), - [iTag, outTag, tTag, paramTag1, bidTag, relaysTag, alttag]).to_event(keys) - - relay_list = ["wss://relay.damus.io", "wss://blastr.f7z.xyz", "wss://relayable.org", - "wss://nostr-pub.wellorder.net"] - - client = Client(keys) - for relay in relay_list: - client.add_relay(relay) - client.connect() - config = DVMConfig - send_event(event, client=client, dvm_config=config) - return event.as_json() - def nostr_client(): keys = Keys.from_sk_str(os.getenv("NOSTR_TEST_CLIENT_PRIVATE_KEY")) sk = keys.secret_key() @@ -156,8 +132,8 @@ def nostr_client(): nostr_client_test_image("a beautiful purple ostrich watching the sunset") - cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6IlhXQzAvRXRhcVM4QyIsImFtb3VudCI6NCwiQyI6IjAzNzZhYTQ4YTJiMDU1NTlmYzQ4MTU2NjJjZThhMjZmZGM5OTQzYzY2Yzg0OWEzNTg3NDgwYWRmYzE0ZTEwNTRiZCIsInNlY3JldCI6IlIzTGhSZDI5UktJTzRkMHdNZ0Z0K2ZKWlVoYi90K0RmZXMxdFVrZVBVV0E9In0seyJpZCI6IlhXQzAvRXRhcVM4QyIsImFtb3VudCI6MTYsIkMiOiIwMmYyNTdhYzYzOTU4NGY1YTE5NTNkMGI0ODI3OWJkN2EyMjdmZTBkYzI0OWY0MjQwNjgzMDZlOTI0ZGE3ZGVhZDciLCJzZWNyZXQiOiJ4Tmhwdm50SkNwcXFiYmFjWDA0NzluVld4SGo5U05jaVBvdTNYQ3JWcmRjPSJ9LHsiaWQiOiJYV0MwL0V0YXFTOEMiLCJhbW91bnQiOjMyLCJDIjoiMDIyYjhiY2JkYTQ1OTNlMGZlNTY4ZWYyOTM2OWNmZjNmMzY2NzdlZDAzYTQ4ODMxNzYwNDQxN2JkNGE3MTYzZDYyIiwic2VjcmV0IjoiTEprUVlheWNyUE9yZ3hZcHhlcDZVV3U0RjZ3QUVydnZJNHZiRmN0R3h6MD0ifV0sIm1pbnQiOiJodHRwczovL2xuYml0cy5iaXRjb2luZml4ZXN0aGlzLm9yZy9jYXNodS9hcGkvdjEvOXVDcDIyUllWVXE4WjI0bzVCMlZ2VyJ9XX0" = - nostr_client_test_image_private("a beautiful ostrich watching the sunset", cashutoken ) + # cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6IlhXQzAvRXRhcVM4QyIsImFtb3VudCI6NCwiQyI6IjAzNzZhYTQ4YTJiMDU1NTlmYzQ4MTU2NjJjZThhMjZmZGM5OTQzYzY2Yzg0OWEzNTg3NDgwYWRmYzE0ZTEwNTRiZCIsInNlY3JldCI6IlIzTGhSZDI5UktJTzRkMHdNZ0Z0K2ZKWlVoYi90K0RmZXMxdFVrZVBVV0E9In0seyJpZCI6IlhXQzAvRXRhcVM4QyIsImFtb3VudCI6MTYsIkMiOiIwMmYyNTdhYzYzOTU4NGY1YTE5NTNkMGI0ODI3OWJkN2EyMjdmZTBkYzI0OWY0MjQwNjgzMDZlOTI0ZGE3ZGVhZDciLCJzZWNyZXQiOiJ4Tmhwdm50SkNwcXFiYmFjWDA0NzluVld4SGo5U05jaVBvdTNYQ3JWcmRjPSJ9LHsiaWQiOiJYV0MwL0V0YXFTOEMiLCJhbW91bnQiOjMyLCJDIjoiMDIyYjhiY2JkYTQ1OTNlMGZlNTY4ZWYyOTM2OWNmZjNmMzY2NzdlZDAzYTQ4ODMxNzYwNDQxN2JkNGE3MTYzZDYyIiwic2VjcmV0IjoiTEprUVlheWNyUE9yZ3hZcHhlcDZVV3U0RjZ3QUVydnZJNHZiRmN0R3h6MD0ifV0sIm1pbnQiOiJodHRwczovL2xuYml0cy5iaXRjb2luZml4ZXN0aGlzLm9yZy9jYXNodS9hcGkvdjEvOXVDcDIyUllWVXE4WjI0bzVCMlZ2VyJ9XX0" + #nostr_client_test_image_private("a beautiful ostrich watching the sunset", cashutoken ) class NotificationHandler(HandleNotification): def handle(self, relay_url, event): print(f"Received new event from {relay_url}: {event.as_json()}") diff --git a/utils/backend_utils.py b/utils/backend_utils.py index bedff8e..d5b7450 100644 --- a/utils/backend_utils.py +++ b/utils/backend_utils.py @@ -1,4 +1,8 @@ +import typing + import requests +from nostr_sdk import Event, Tag + from utils.definitions import EventDefinitions from utils.nostr_utils import get_event_by_id @@ -50,17 +54,16 @@ def get_task(event, client, dvmconfig): return "unknown type" -def check_task_is_supported(event, tags, client, get_duration=False, config=None): +def check_task_is_supported(event: Event, client, get_duration=False, config=None): try: dvm_config = config input_value = "" input_type = "" duration = 1 - task = get_task(event, client=client, dvmconfig=dvm_config) try: - for tag in tags: + for tag in event.tags(): if tag.as_vec()[0] == 'i': if len(tag.as_vec()) < 3: print("Job Event missing/malformed i tag, skipping..") @@ -75,7 +78,7 @@ def check_task_is_supported(event, tags, client, get_duration=False, config=None return False, "", 0 elif input_type == 'url' and check_url_is_readable(input_value) is None: print("Url not readable / supported") - return False, task, duration# + return False, task, duration # elif tag.as_vec()[0] == 'output': # TODO move this to individual modules @@ -85,13 +88,13 @@ def check_task_is_supported(event, tags, client, get_duration=False, config=None or output == "image/png" or "image/jpg" or output == "image/png;format=url" or output == "image/jpg;format=url" or output == ""): - print("Output format not supported, skipping..") - return False, "", 0 + print("Output format not supported, skipping..") + return False, "", 0 except Exception as e: print("Check task 2: " + str(e)) - for dvm in dvm_config.SUPPORTED_DVMS: + print(dvm.TASK) if dvm.TASK == task: if not dvm.is_input_supported(input_type, event.content()): return False, task, duration @@ -130,10 +133,11 @@ def check_url_is_readable(url): def get_amount_per_task(task, dvm_config, duration=1): - for dvm in dvm_config.SUPPORTED_DVMS: #this is currently just one + for dvm in dvm_config.SUPPORTED_DVMS: # this is currently just one if dvm.TASK == task: amount = dvm.COST * duration return amount else: - print("["+dvm_config.SUPPORTED_DVMS[0].NAME +"] Task " + task + " is currently not supported by this instance, skipping") + print("[" + dvm_config.SUPPORTED_DVMS[ + 0].NAME + "] Task " + task + " is currently not supported by this instance, skipping") return None diff --git a/utils/nostr_utils.py b/utils/nostr_utils.py index 4dfb394..9986630 100644 --- a/utils/nostr_utils.py +++ b/utils/nostr_utils.py @@ -1,6 +1,7 @@ import json +import typing from datetime import timedelta -from nostr_sdk import Filter, Client, Alphabet, EventId, Event, PublicKey, Tag, Keys, nip04_decrypt +from nostr_sdk import Filter, Client, Alphabet, EventId, Event, PublicKey, Tag, Keys, nip04_decrypt, EventBuilder def get_event_by_id(event_id: str, client: Client, config=None) -> Event | None: @@ -61,38 +62,38 @@ def send_event(event: Event, client: Client, dvm_config) -> EventId: def check_and_decrypt_tags(event, dvm_config): - tags = [] - is_encrypted = False - p = "" - for tag in event.tags(): - if tag.as_vec()[0] == 'encrypted': - is_encrypted = True - elif tag.as_vec()[0] == 'p': - p = tag.as_vec()[1] + try: + tags = [] + is_encrypted = False + p = "" + sender = event.pubkey() + for tag in event.tags(): + if tag.as_vec()[0] == 'encrypted': + is_encrypted = True + elif tag.as_vec()[0] == 'p': + p = tag.as_vec()[1] - if is_encrypted: - if p != Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_hex(): - print("[" + dvm_config.NIP89.name + "] Task encrypted and not addressed to this DVM, " - "skipping..") - return None, None + if is_encrypted: + if p != Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_hex(): + print("[" + dvm_config.NIP89.name + "] Task encrypted and not addressed to this DVM, " + "skipping..") + return None - elif p == Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_hex(): - encrypted_tag = Tag.parse(["encrypted"]) - p_tag = Tag.parse(["p", p]) + elif p == Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_hex(): + print("encrypted") + #encrypted_tag = Tag.parse(["encrypted"]) + #p_tag = Tag.parse(["p", p]) - tags_str = nip04_decrypt(Keys.from_sk_str(dvm_config.PRIVATE_KEY).secret_key(), - event.pubkey(), event.content()) - params = json.loads(tags_str) - - for element in params: - tags.append(Tag.parse(element)) - - # Keep the encrypted tag - tags.append(p_tag) - tags.append(encrypted_tag) - - return tags, p - - else: - return event.tags, p + tags_str = nip04_decrypt(Keys.from_sk_str(dvm_config.PRIVATE_KEY).secret_key(), + event.pubkey(), event.content()) + #TODO add outer p tag so it doesnt have to be sent twice + params = json.loads(tags_str) + eventasjson = json.loads(event.as_json()) + eventasjson['tags'] = params + eventasjson['content'] = "" + event = Event.from_json(json.dumps(eventasjson)) + print(event.as_json()) + except Exception as e: + print(e) + return event