data.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. import json
  2. import os
  3. import pprint
  4. import time
  5. from tkinter import *
  6. import rpyc
  7. from create_keys import get_plain_key, get_private_key, make_keys
  8. from lib.block import CURRENT
  9. from lib.chain import Block, Chain
  10. from lib.transaction import Transaction
  11. from gui.encyption import decrypt_data
  12. # from gui.encyption import decrypt
  13. def new_contract():
  14. def add():
  15. name = str(title.get())
  16. if not os.path.isdir('contract_keys\\' + name):
  17. # get data form gui
  18. make_keys(name)
  19. pubkey = get_plain_key(name)
  20. # set discriptors of contract
  21. contract = {'id':pubkey,
  22. 'type':'init',
  23. 'date of initiation':time.time(),
  24. 'data': {'client':str(sender.get()),
  25. 'contractor':str(recipient.get()),
  26. 'discription':str(description.get()),
  27. 'name':name},
  28. 'terms' : {'deadline': int(deadline.get()),
  29. 'accepted': False,
  30. 'progress': '0%',
  31. 'price':int(price.get()),
  32. 'Sign time': 'not yet signed',
  33. 'comments':{}
  34. }
  35. }
  36. # create transaction and set contract to contents
  37. t = Transaction()
  38. t.set_contract(contract)
  39. # encrypt data
  40. t.hash(contract=name)
  41. # push transaction to blockchain
  42. temp = t.serialize(out_json=True)
  43. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  44. conn.root.push_transaction(temp)
  45. conn.close()
  46. newWindow.destroy()
  47. # if contract name already exists, print message and try again
  48. else:
  49. print('Contract name already exists, choose another')
  50. newWindow.destroy()
  51. new_contract()
  52. newWindow = Tk()
  53. newWindow.title('Add contract')
  54. # create all text boxes
  55. Label(newWindow, text='Title: ').grid(row=0, column=0)
  56. title = Entry(newWindow, width=35, borderwidth=5)
  57. title.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
  58. title.insert(0, 'test')
  59. Label(newWindow, text='Description: ').grid(row=1, column=0)
  60. description = Entry(newWindow, width=35, borderwidth=5)
  61. description.grid(row=1, column=1, columnspan=3, padx=10, pady=10)
  62. description.insert(0, 'test description')
  63. Label(newWindow, text='Deadline: ').grid(row=2, column=0)
  64. deadline = Entry(newWindow, width=35, borderwidth=5)
  65. deadline.grid(row=2, column=1, columnspan=3, padx=10, pady=10)
  66. deadline.insert(0, '1')
  67. Label(newWindow, text='Price: ').grid(row=3, column=0)
  68. price = Entry(newWindow, width=35, borderwidth=5)
  69. price.grid(row=3, column=1, columnspan=3, padx=10, pady=10)
  70. price.insert(0, '69420')
  71. Label(newWindow, text='Sender: ').grid(row=4, column=0)
  72. sender = Entry(newWindow, width=35, borderwidth=5)
  73. sender.grid(row=4, column=1, columnspan=3, padx=10, pady=10)
  74. sender.insert(0, 'justin')
  75. Label(newWindow, text='Recipient: ').grid(row=5, column=0)
  76. recipient = Entry(newWindow, width=35, borderwidth=5)
  77. recipient.grid(row=5, column=1, columnspan=3, padx=10, pady=10)
  78. recipient.insert(0, 'adam')
  79. # create the add contract button
  80. Button(newWindow, text = "Create contract", command=add).grid(row=6, column=1, padx=10, pady=5)
  81. def find_transaction():
  82. # get current state of contract
  83. def find():
  84. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  85. # find all transactions of a contract
  86. iden = get_plain_key(str(key.get()))
  87. transactions = conn.root.find_transactions(iden)
  88. # check if contract exists
  89. if len(transactions) == 0:
  90. print('No contract found')
  91. # build current state of contract and print to console
  92. else:
  93. transactions = decrypt_transactions(transactions, str(key.get()))
  94. print('Current contract state')
  95. pprint.pprint(current_contract_state(transactions, iden=iden))
  96. conn.close()
  97. newWindow.destroy()
  98. # get current state and all transactions
  99. def findall():
  100. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  101. # find all transactions of a contract
  102. iden = get_plain_key(str(key.get()))
  103. transactions = conn.root.find_transactions(iden)
  104. # check if contract exists
  105. if len(transactions) == 0:
  106. print('No contract found')
  107. # build current state of contract and print to console
  108. else:
  109. transactions = decrypt_transactions(transactions, str(key.get()))
  110. print('All updates')
  111. # show all updates of contract
  112. for item in transactions:
  113. if item['type'] != 'init':
  114. pprint.pprint(item)
  115. print('\n')
  116. # show contract
  117. print('Current contract state')
  118. pprint.pprint(current_contract_state(transactions, iden=iden))
  119. conn.close()
  120. newWindow.destroy()
  121. # gui setup
  122. newWindow = Tk()
  123. newWindow.title('Find contract')
  124. Label(newWindow, text='Contract key: ').grid(row=0, column=0)
  125. key = Entry(newWindow, width=35, borderwidth=5)
  126. key.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
  127. key.insert(0, 'test')
  128. Button(newWindow, text='find contracts', command=find).grid(row=2, column=0, padx=10, pady=5)
  129. Button(newWindow, text='find contracts and updates', command=findall).grid(row=2, column=1, padx=10, pady=5)
  130. def add_term():
  131. def add():
  132. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  133. # retrieve data from gui
  134. iden = get_plain_key(str(contract.get()))
  135. attr = str(change.get())
  136. value = str(values.get())
  137. comment = str(comments.get())
  138. transactions = conn.root.find_transactions(iden)
  139. transactions = decrypt_transactions(transactions, str(contract.get()))
  140. state = current_contract_state(transactions, iden)
  141. # check type of transaction
  142. if value == '':
  143. t = 'remove'
  144. elif attr in state['data'] or attr in state['terms']:
  145. t = 'modify'
  146. else: t = 'update'
  147. # add new or updated info to block
  148. update = {'id':iden,
  149. 'update id':len(get_updates(transactions, iden=iden)),
  150. 'updated':attr,
  151. 'type':t,
  152. 'last update':time.time(),
  153. 'accepted': False}
  154. if t != 'remove':
  155. update['change'] = {attr:value}
  156. # check if comment is passed and add it if necassary
  157. if comment:
  158. update['comment'] = comment
  159. # create transacion, hash it and push to blockchain
  160. t = Transaction()
  161. t.set_contract(update)
  162. t.hash(contract=str(contract.get()))
  163. conn.root.push_transaction(t.serialize(out_json=True))
  164. conn.close()
  165. newWindow.destroy()
  166. newWindow = Tk()
  167. newWindow.title('Add term')
  168. # create all text boxes
  169. Label(newWindow, text='Contract: ').grid(row=0, column=0)
  170. contract = Entry(newWindow, width=35, borderwidth=5)
  171. contract.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
  172. contract.insert(0, 'test')
  173. Label(newWindow, text='What to change or add: ').grid(row=1, column=0)
  174. change = Entry(newWindow, width=35, borderwidth=5)
  175. change.grid(row=1, column=1, columnspan=3, padx=10, pady=10)
  176. change.insert(0, 'progress')
  177. Label(newWindow, text='New value (to remove, keep empty): ').grid(row=2, column=0)
  178. values = Entry(newWindow, width=35, borderwidth=5)
  179. values.grid(row=2, column=1, columnspan=3, padx=10, pady=10)
  180. values.insert(0, '50%')
  181. Label(newWindow, text='comment (optional): ').grid(row=3, column=0)
  182. comments = Entry(newWindow, width=35, borderwidth=5)
  183. comments.grid(row=3, column=1, columnspan=3, padx=10, pady=10)
  184. comments.insert(0, 'dit is een comment')
  185. Button(newWindow, text='Add term', command=add).grid(row=4, column=1, padx=10, pady=5)
  186. def accept_updates():
  187. def show():
  188. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  189. # find all transactions based on given contract
  190. name = str(contract.get())
  191. transactions = conn.root.find_transactions(get_plain_key(name))
  192. transactions = decrypt_transactions(transactions, name)
  193. updates = retrieve_updates(transactions, name, accepted=False)
  194. conn.close()
  195. # show updates to accept
  196. if len(updates) == 0:
  197. print('No updates to accept')
  198. else:
  199. print('Updates that still need to be accepted: \n')
  200. for update in updates:
  201. pprint.pprint(update)
  202. def accept():
  203. conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
  204. # get data from gui
  205. name = str(contract.get())
  206. update_id = int(change.get())
  207. answer = accept_status.get()
  208. if answer == 'True':
  209. answer = True
  210. else: answer = False
  211. comment_text = str(comment.get())
  212. # set transaction data
  213. update = {
  214. 'id':get_plain_key(name),
  215. 'update id':update_id,
  216. 'accept':answer,
  217. 'type':'accept',
  218. 'last update':time.time()
  219. }
  220. if comment_text:
  221. update['comment'] = comment_text
  222. # create transacion, hash it and push to blockchain
  223. t = Transaction()
  224. t.set_contract(update)
  225. t.hash(contract=str(contract.get()))
  226. conn.root.push_transaction(t.serialize(out_json=True))
  227. conn.close()
  228. newWindow.destroy()
  229. newWindow = Tk()
  230. newWindow.title('Accept updates')
  231. Label(newWindow, text='Contract: ').grid(row=0, column=0)
  232. contract = Entry(newWindow, width=35, borderwidth=5)
  233. contract.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
  234. contract.insert(0, 'test')
  235. Label(newWindow, text='Id of update: ').grid(row=1, column=0)
  236. change = Entry(newWindow, width=35, borderwidth=5)
  237. change.grid(row=1, column=1, columnspan=3, padx=10, pady=10)
  238. change.insert(0, '0')
  239. Label(newWindow, text='Awnser: ').grid(row=2, column=0)
  240. accept_status = StringVar(newWindow)
  241. accept_status.set('False') # default value
  242. OptionMenu(newWindow, accept_status, 'False', 'True').grid(row=2, column=1)
  243. Label(newWindow, text='Comment (optional): ').grid(row=3, column=0)
  244. comment = Entry(newWindow, width=35, borderwidth=5)
  245. comment.grid(row=3, column=1, columnspan=3, padx=10, pady=10)
  246. comment.insert(0, 'test test')
  247. Button(newWindow, text='Show updates to accept', command=show).grid(row=4, column=0, padx=10, pady=5)
  248. Button(newWindow, text='Accept', command=accept).grid(row=4, column=1, padx=10, pady=5)
  249. def current_contract_state(transactions, iden):
  250. # set up contract state
  251. state = {'id':iden,
  252. 'data':{},
  253. 'terms':{}
  254. }
  255. # save not yet approved updates
  256. updates = {}
  257. # loop over all transaction in block
  258. for item in transactions:
  259. # save data about our project
  260. if item['id'] == iden:
  261. # set state to inital contract state
  262. if item['type'] == 'init':
  263. state = item
  264. continue
  265. # if update is not accept update, save it to updates dict
  266. if item['type'] != 'accept':
  267. # comments are always accepted
  268. if item['updated'] != 'comments':
  269. updates[item['update id']] = item
  270. continue
  271. # if accepted is true, retrieve update form dict and add to contract state
  272. elif item['accept'] == True:
  273. item = updates[item['update id']]
  274. else: continue
  275. # set attr to whatever has been updated
  276. attr = item['updated']
  277. # check if the update was removal
  278. if item['type'] == 'remove':
  279. # delete item in the right part of the dict
  280. try:
  281. if attr in state['data']:
  282. del state['data'][attr]
  283. else:
  284. del state['terms'][attr]
  285. except:
  286. pass
  287. if item['type'] == 'update':
  288. state['terms'][attr] = item['change'][attr]
  289. # check if updated attr is data or terms
  290. elif attr in state['data']:
  291. state['data'][attr] = item['change'][attr]
  292. elif attr in state['terms']:
  293. # special case for comments
  294. if attr == 'comments' and item['type'] not in ['remove', 'init']:
  295. k = list(item['change'][attr].keys())[0]
  296. state['terms'][attr][k] = item['change'][attr][k]
  297. # case for normal updates
  298. else:
  299. state['terms'][attr] = item['change'][attr]
  300. # special cases for last update and date of initiation
  301. elif 'last update' in item:
  302. state['last update'] = item['last update']
  303. return state
  304. def get_updates(transactions, iden=None, attr=None, accepted=None):
  305. updates = []
  306. # get all blocks and loop over transactions
  307. for item in transactions:
  308. # if attr is '' get updates for all attributes
  309. if attr == None:
  310. # if iden is None, get updates for all contracts
  311. # updates for all contracts and attrs
  312. if iden == None:
  313. if item['type'] != 'init':
  314. updates.append(item)
  315. # updates for specific contracts from all attr
  316. else:
  317. if item['type'] != 'init' and item['id'] == iden:
  318. updates.append(item)
  319. else:
  320. # updates for specific attrs from all contract
  321. if iden == None:
  322. if item['type'] != 'init' and item['updated'] == attr:
  323. updates.append(item)
  324. # updates for specific contract and specific attr
  325. else:
  326. if item['type'] != 'init' and item['updated'] == attr and item['id'] == iden:
  327. updates.append(item)
  328. return updates
  329. def retrieve_updates(all_updates, iden, accepted=None):
  330. updates = {}
  331. # for all updates, only find modify and remove updates
  332. for item in all_updates:
  333. if item['type'] == 'init':
  334. continue
  335. if item['type'] != 'accept' and item['updated'] != 'comments':
  336. updates[item['update id']] = item
  337. else:
  338. try:
  339. updates[item['update id']]['accepted'] = item['accept']
  340. except:
  341. pass
  342. if accepted == None:
  343. return updates
  344. # only return updates based on accepted argument
  345. return [updates[x] for x in list(updates.keys()) if updates[x]['accepted'] == accepted]
  346. # creates list of all decrypted transactions
  347. def decrypt_transactions(transactions, name):
  348. return [json.loads(decrypt_data(name, x)) for x in transactions]