import json import os import time from tkinter import * import pprint import rpyc from create_keys import get_plain_key, get_private_key, make_keys from lib.block import CURRENT from lib.chain import Block, Chain from lib.transaction import Transaction from gui.encyption import decrypt_data # from gui.encyption import decrypt def new_contract(): def add(): name = str(title.get()) if not os.path.isdir('contract_keys\\' + name): make_keys(name) pubkey = get_plain_key(name) # set discriptors of contract contract = {'id':pubkey, 'type':'init', 'date of initiation':time.time(), 'data': {'client':str(sender.get()), 'contractor':str(recipient.get()), 'discription':str(description.get()), 'name':name}, 'terms' : {'deadline': int(deadline.get()), 'accepted': False, 'progress': '0%', 'price':int(price.get()), 'Sign time': 'not yet signed', 'comments':{} } } t = Transaction() t.set_contract(contract) t.hash(contract=name) temp = t.serialize(out_json=True) conn = rpyc.connect(host='localhost', port=42069, keepalive=True) conn.root.push_transaction(temp) conn.close() newWindow.destroy() else: print('Contract name already exists, choose another') newWindow.destroy() new_contract() newWindow = Tk() newWindow.title('Add contract') # create all text boxes Label(newWindow, text='Title: ').grid(row=0, column=0) title = Entry(newWindow, width=35, borderwidth=5) title.grid(row=0, column=1, columnspan=3, padx=10, pady=10) title.insert(0, 'test') Label(newWindow, text='Description: ').grid(row=1, column=0) description = Entry(newWindow, width=35, borderwidth=5) description.grid(row=1, column=1, columnspan=3, padx=10, pady=10) description.insert(0, 'test description') Label(newWindow, text='Deadline: ').grid(row=2, column=0) deadline = Entry(newWindow, width=35, borderwidth=5) deadline.grid(row=2, column=1, columnspan=3, padx=10, pady=10) deadline.insert(0, '1') Label(newWindow, text='Price: ').grid(row=3, column=0) price = Entry(newWindow, width=35, borderwidth=5) price.grid(row=3, column=1, columnspan=3, padx=10, pady=10) price.insert(0, '69420') Label(newWindow, text='Sender: ').grid(row=4, column=0) sender = Entry(newWindow, width=35, borderwidth=5) sender.grid(row=4, column=1, columnspan=3, padx=10, pady=10) sender.insert(0, 'justin') Label(newWindow, text='Recipient: ').grid(row=5, column=0) recipient = Entry(newWindow, width=35, borderwidth=5) recipient.grid(row=5, column=1, columnspan=3, padx=10, pady=10) recipient.insert(0, 'adam') # create the add contract button Button(newWindow, text = "Create contract", command=add).grid(row=6, column=1) def find_transaction(): def find(): conn = rpyc.connect(host='localhost', port=42069, keepalive=True) iden = get_plain_key(str(key.get())) transactions = conn.root.find_transactions(iden) if len(transactions) == 0: print('No contract found') else: transactions = decrypt_transactions(transactions, str(key.get())) pprint.pprint(current_contract_state(transactions, iden=iden)) conn.close() newWindow.destroy() newWindow = Tk() newWindow.title('Find contract') Label(newWindow, text='Contract key: ').grid(row=0, column=0) key = Entry(newWindow, width=35, borderwidth=5) key.grid(row=0, column=1, columnspan=3, padx=10, pady=10) key.insert(0, 'test') Button(newWindow, text='find contracts', command=find).grid(row=1, column=1) def add_term(): def add(): conn = rpyc.connect(host='localhost', port=42069, keepalive=True) iden = get_plain_key(str(contract.get())) attr = str(change.get()) value = str(values.get()) comment = str(comments.get()) transactions = conn.root.find_transactions(iden) transactions = decrypt_transactions(transactions, str(contract.get())) state = current_contract_state(transactions, iden) if value == '': t = 'remove' elif attr in state['data'] or attr in state['terms']: t = 'modify' else: t = 'update' # add new or updated info to block update = {'id':iden, 'update id':len(get_updates(transactions, iden=iden)), 'updated':attr, 'type':t, 'last update':time.time(), 'accepted': False} if t != 'remove': update['change'] = {attr:value} # check if comment is passed and add it if necassary if comment: update['comment'] = comment t = Transaction() t.set_contract(update) t.hash(contract=str(contract.get())) conn.root.push_transaction(t.serialize(out_json=True)) conn.close() newWindow.destroy() newWindow = Tk() newWindow.title('Add term') # create all text boxes Label(newWindow, text='Contract: ').grid(row=0, column=0) contract = Entry(newWindow, width=35, borderwidth=5) contract.grid(row=0, column=1, columnspan=3, padx=10, pady=10) contract.insert(0, 'test') Label(newWindow, text='What to change or add: ').grid(row=1, column=0) change = Entry(newWindow, width=35, borderwidth=5) change.grid(row=1, column=1, columnspan=3, padx=10, pady=10) change.insert(0, 'progress') Label(newWindow, text='New value (to remove, keep empty): ').grid(row=2, column=0) values = Entry(newWindow, width=35, borderwidth=5) values.grid(row=2, column=1, columnspan=3, padx=10, pady=10) values.insert(0, '50%') Label(newWindow, text='comment (optional): ').grid(row=3, column=0) comments = Entry(newWindow, width=35, borderwidth=5) comments.grid(row=3, column=1, columnspan=3, padx=10, pady=10) comments.insert(0, 'dit is een comment') Button(newWindow, text='Add term', command=add).grid(row=4, column=1) def accept_updates(): def show(): conn = rpyc.connect(host='localhost', port=42069, keepalive=True) name = str(contract.get()) transactions = conn.root.find_transactions(get_plain_key(name)) transactions = decrypt_transactions(transactions, name) updates = retrieve_updates(transactions, name, accepted=False) conn.close() if len(updates) == 0: print('No updates to accept') else: print('Updates that still need to be accepted: \n') for update in updates: pprint.pprint(update) def accept(): conn = rpyc.connect(host='localhost', port=42069, keepalive=True) name = str(contract.get()) update_id = int(change.get()) answer = accept_status.get() if answer == 'True': answer = True else: answer = False comment_text = str(comment.get()) update = { 'id':get_plain_key(name), 'update id':update_id, 'accept':answer, 'type':'accept', 'last update':time.time() } if comment_text: update['comment'] = comment_text t = Transaction() t.set_contract(update) t.hash(contract=str(contract.get())) conn.root.push_transaction(t.serialize(out_json=True)) conn.close() newWindow.destroy() newWindow = Tk() newWindow.title('Accept updates') Label(newWindow, text='Contract: ').grid(row=0, column=0) contract = Entry(newWindow, width=35, borderwidth=5) contract.grid(row=0, column=1, columnspan=3, padx=10, pady=10) contract.insert(0, 'test') Label(newWindow, text='Id of update: ').grid(row=1, column=0) change = Entry(newWindow, width=35, borderwidth=5) change.grid(row=1, column=1, columnspan=3, padx=10, pady=10) change.insert(0, '0') Label(newWindow, text='Awnser: ').grid(row=2, column=0) accept_status = StringVar(newWindow) accept_status.set('False') # default value OptionMenu(newWindow, accept_status, 'False', 'True').grid(row=2, column=1) Label(newWindow, text='Comment (optional): ').grid(row=3, column=0) comment = Entry(newWindow, width=35, borderwidth=5) comment.grid(row=3, column=1, columnspan=3, padx=10, pady=10) comment.insert(0, 'test test') Button(newWindow, text='Show updates to accept', command=show).grid(row=4, column=0, padx=10, pady=5) Button(newWindow, text='Accept', command=accept).grid(row=4, column=1, padx=10, pady=5) def current_contract_state(transactions, iden): # set up contract state state = {'id':iden, 'data':{}, 'terms':{} } # save not yet approved updates updates = {} # loop over all transaction in block for item in transactions: # save data about our project if item['id'] == iden: # set state to inital contract state if item['type'] == 'init': state = item continue # if update is not accept update, save it to updates dict if item['type'] != 'accept': # comments are always accepted if item['updated'] != 'comments': updates[item['update id']] = item continue # if accepted is true, retrieve update form dict and add to contract state elif item['accept'] == True: item = updates[item['update id']] else: continue # set attr to whatever has been updated attr = item['updated'] # check if the update was removal if item['type'] == 'remove': # delete item in the right part of the dict try: if attr in state['data']: del state['data'][attr] else: del state['terms'][attr] except: pass if item['type'] == 'update': state['terms'][attr] = item['change'][attr] # check if updated attr is data or terms elif attr in state['data']: state['data'][attr] = item['change'][attr] elif attr in state['terms']: # special case for comments if attr == 'comments' and item['type'] not in ['remove', 'init']: k = list(item['change'][attr].keys())[0] state['terms'][attr][k] = item['change'][attr][k] # case for normal updates else: state['terms'][attr] = item['change'][attr] # special cases for last update and date of initiation elif 'last update' in item: state['last update'] = item['last update'] return state def get_updates(transactions, iden=None, attr=None, accepted=None): updates = [] # get all blocks and loop over transactions for item in transactions: # if attr is '' get updates for all attributes if attr == None: # if iden is None, get updates for all contracts # updates for all contracts and attrs if iden == None: if item['type'] != 'init': updates.append(item) # updates for specific contracts from all attr else: if item['type'] != 'init' and item['id'] == iden: updates.append(item) else: # updates for specific attrs from all contract if iden == None: if item['type'] != 'init' and item['updated'] == attr: updates.append(item) # updates for specific contract and specific attr else: if item['type'] != 'init' and item['updated'] == attr and item['id'] == iden: updates.append(item) return updates def retrieve_updates(all_updates, iden, accepted=None): updates = {} for item in all_updates: if item['type'] == 'init': continue if item['type'] != 'accept' and item['updated'] != 'comments': updates[item['update id']] = item else: try: updates[item['update id']]['accepted'] = item['accept'] except: pass if accepted == None: return updates return [updates[x] for x in list(updates.keys()) if updates[x]['accepted'] == accepted] def decrypt_transactions(transactions, name): return [json.loads(decrypt_data(name, x)) for x in transactions]