Skip to content

Instantly share code, notes, and snippets.

@EggPool
Last active July 4, 2018 12:53
Show Gist options
  • Save EggPool/aabcd9f59e9545ba23341db39c86ded9 to your computer and use it in GitHub Desktop.
Save EggPool/aabcd9f59e9545ba23341db39c86ded9 to your computer and use it in GitHub Desktop.
# add manual refresh, objectify
# icons created using http://www.winterdrache.de/freeware/png2ico/
# import sqlite3
import PIL.Image, PIL.ImageTk, pyqrcode, os, time, socks, ast, options, tarfile, essentials, platform
import hashlib, base64, icons, log, glob, re
# import connections
from tokensv2 import *
from decimal import *
from bisurl import *
from quantizer import quantize_eight
import csv
import glob
import recovery
from essentials import fee_calculate
import matplotlib
#from tornado.ioloop import IOLoop
# import aioprocessing
import async_client
import threading
import asyncio
matplotlib.use ('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from random import shuffle
from datetime import datetime
from Cryptodome.PublicKey import RSA
from Cryptodome.Signature import PKCS1_v1_5
from Cryptodome.Hash import SHA
from Cryptodome.Random import get_random_bytes
from Cryptodome.Cipher import AES, PKCS1_OAEP
from simplecrypt import encrypt, decrypt
from tkinter import filedialog, messagebox, ttk
from tkinter import *
import webbrowser
__version__ = "1.0.3"
def mempool_clear(s):
async_client.connection.send("mpclear")
def mempool_get(s):
# result = [['1524749959.44', '2ac10094cc1d3dd2375f8e1aa51115afd33926e3fa69472f2ea987f5', 'edf2d63cdf0b6275ead22c9e6d66aa8ea31dc0ccb367fad2e7c08a25', '11.15000000', 'rd7Op7gZlp7bBkdL5EogrhkHB3WFGNKfc2cGqzrKzwtFCJf/3nKt13y/1MggR5ioA1RAHFn/8m5q+ot7nv6bTcAOhXHgK/CcqplNBNEp3J+RFf1IbEbhbckJsdVbRvrkQoMRZmSrwCwJm+v/pB9KYqG3R5OVKmEyc5KbUZsRuTUrZjPL6lPd+VfYy6x2Wnr5JgC+q7zvQPH0+yqVqOxcbgYggbbNyHHfYIj+0k0uK+8hwmRCe+SfG+/JZwiSp8ZO4Teyd6/NDmss0AaDRYfAVmxLMEg0aOf1xPbURL3D9gyUsDWupRFVT88eS22cRTPgvS5fwpPt/rV8QUa58eRHSMJ3MDwxpkJ7KeMkN5dfiQ/NZ0HFQc3vDwnGJ1ybyVDnw/i7ioRsJtTC0hGNO33lNVqKnbQ8yQ/7yihqfUsCM1qXA/a5Q+9bRx1mr0ff+h7BYxK7qoVF/2KeiS7Ia8OiX8EPUSiwFxCnGsY+Ie+AgQlaiUIlen2LoGw41NGmZufvWXFqK9ww8e50n35OmKw0MQrJrzOr/7iBoCOXmW0/jEzbJNM7NKEni7iFNwbfk3Xzkoh8A2/m9hdDPKZASdF1hFpNVnGJnDvuINRNn3xBUqoxCQUY50b9mGO4hdkLgVOQOVvzYvdYjB0B+XJTvmfLtWQKOcAJ4/E7tr8dSrC7sPY=', 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUE0SjdSS2VPWGN2OXhaTGN6R2IvSQprV2MvanU3cktvLzIrNGJuS0NsQituT0VwNDY5Vzd5YmF3eW1mR2xVUmpvYjg3MjZ6eWFDdDVrOEJqNXU1Y25MCk1XaENueGNwdGltUytmeHA1WGx5NGs5TUNQUDlYODZFc1U0ZjBrcVBhZjhnais1MG5LdjM4a01ZMHFSR0k0U0QKNS9wVlpCY1ptRjN0eVFPYzh0SWJERk9vUHJta0FpTy9LQnAxWHA4Q0dFK24zaTdKdS9zUFlzcDZFRERobjVrVAptVDMxUGVOZ2tUOTh4OW5rSmhSTmxmQTE2Mi9ia2gva2JISE1hUE1JYUhsUDhSbGVNazlqS0hCNjVOWFVMVHNLCjZZa2FNK2F3aGVpUWIwVDE2cm5tY3N4NHZBbWViUEFBWTQ1WWNqMWx3L3lpU0ZXWWpvdkcrQjBkZ0JuTDVXbUUKb2d6bnQxN04zYzZnU1JBNEYrUUhrVlA1RjBUejdTSXFuWnZDeCtEMDhjam9hVWgxUi9SeFNlT1Mwd3pEdWdNOQpMZjhSQXZweVRxR0xmUWpYY252YnVaMGNBc1g4SzFCR3lvTDZIZ3h2U3kzeUJBMlZvSjlnM1JncVUxU3NraHgrCktsdlg0S0VWeXUxLzlMbXRpc3dKSFZGTitEdVhTV1VqMjk0RURsZktsTlRKY0h1LytQWHFyeGVzbkpjOGttYisKWVlYS0R3YnRKNDFRMnRZalBwd1BOSmpDdm1Ca2haSzR2VEFIQXNKVTVEV1pQZkRJeEN6WDVFbFFRUGNhVUV6MApvbnAzNDVpeVV0TFZZcmdIdTJCNmIvNkNqMWlCNm90SitNV1RUYXVOUHcrYXczeVRHK1NUM3dxeG5qS3I3YkoyCnJGVkFnUFBCRlI5cmVoUUpmTXBoTGtVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==', '0', '672ce4daaeb73565'], ['1524749904.95', '4edadac9093d9326ee4b17f869b14f1a2534f96f9c5d7b48dc9acaed', '4edadac9093d9326ee4b17f869b14f1a2534f96f9c5d7b48dc9acaed', '0.00000000', 'bQmnTD79aL1hjoyVF/ARfMLFfMtQiqpmvk88fPAGW1LUqLQen87+6i+2flBCuSPOWvjHQBMJ3Ctyk5MtuWj6KtoltWSKXev2tYfgNSiAOuo1YIbUhDwTBtHI5UY6X9eNmFjB5Iny0/7VB+cotV1ZBPpgCx1xQn45CtAVk4IYaXc=', 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FES3ZMVGJEeDg1YTF1Z2IvNnhNTWhWT3E2VQoyR2VZVDgrSXEyejlGd0lNUjQwbDJ0dEdxTks3dmFyTmNjRkxJdThLbjRvZ0RRczNXU1dRQ3hOa2haaC9GcXpGCllZYTMvSXRQUGZ6clhxZ2Fqd0Q4cTRadDRZbWp0OCsyQmtJbVBqakZOa3VUUUl6Mkl1M3lGcU9JeExkak13N24KVVZ1OXRGUGlVa0QwVm5EUExRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==', '0', '']]
mempool_window = Toplevel ()
mempool_window.title ("Mempool")
def update():
for child in mempool_window.winfo_children (): # prevent hangup
child.destroy ()
mp_tree = ttk.Treeview (mempool_window, selectmode="extended", columns=('sender', 'recipient', 'amount'))
# mp_tree.grid(row=0, column=0)
# table
mp_tree.heading ("#0", text='time')
mp_tree.column ("#0", anchor='center', width=100)
mp_tree.heading ("#1", text='sender')
mp_tree.column ("#1", anchor='center', width=350)
mp_tree.heading ("#2", text='recipient')
mp_tree.column ("#2", anchor='center', width=350)
mp_tree.heading ("#3", text='amount')
mp_tree.column ("#3", anchor='center', width=100)
mp_tree.grid (sticky=N + S + W + E)
# table
for tx in mempool_total:
mp_tree.insert ('', 'end', text=datetime.fromtimestamp (float (tx[0])).strftime ('%y-%m-%d %H:%M'), values=(tx[1], tx[2], tx[3]))
clear_mempool_b = Button (mempool_window, text="Clear Mempool", command=lambda: mempool_clear (s), height=1, width=20, font=("Tahoma", 8))
clear_mempool_b.grid (row=1, column=0, sticky=N + S + W + E)
close_mempool_b = Button (mempool_window, text="Close", command=lambda: mempool_window.destroy (), height=1, width=20, font=("Tahoma", 8))
close_mempool_b.grid (row=2, column=0, sticky=N + S + W + E)
def refresh_mp_auto():
try:
# global frame_chart
root.after (0, update ())
root.after (10000, refresh_mp_auto)
except Exception as e:
print ("Mempool window closed, disabling auto-refresh ({})".format (e))
refresh_mp_auto ()
def recover():
result = recovery.recover (key)
messagebox.showinfo ("Recovery Result", result)
def address_validate(address):
if re.match ('[abcdef0123456789]{56}', address):
return True
else:
return False
def create_url_clicked(app_log, command, recipient, amount, operation, openfield):
"""isolated function so no GUI leftovers are in bisurl.py"""
result = create_url (app_log, command, recipient, amount, operation, openfield)
url_r.delete (0, END)
url_r.insert (0, result)
def read_url_clicked(app_log, url):
"""isolated function so no GUI leftovers are in bisurl.py"""
result = (read_url (app_log, url))
recipient.delete (0, END)
amount.delete (0, END)
operation.delete (0, END)
openfield.delete ("1.0", END)
recipient.insert (0, result[1]) # amount
amount.insert (0, result[2]) # recipient
operation.insert (INSERT, result[3]) # operation
openfield.insert (INSERT, result[4]) # openfield
def replace_regex(string, replace):
replaced_string = re.sub (r'^{}'.format (replace), "", string)
return replaced_string
def alias_register(alias_desired):
# This will freeze, but let say it's ok, we're waiting for a feedback.
result = async_client.connection.command("aliascheck", alias_desired)
if result == "Alias free":
send ("0", myaddress, "", "alias=" + alias_desired)
pass
else:
messagebox.showinfo ("Conflict", "Name already registered")
def help():
top13 = Toplevel ()
top13.title ("Help")
aliases_box = Text (top13, width=100)
aliases_box.grid (row=0, pady=0)
aliases_box.insert (INSERT, "Encrypt with PK:\n Encrypt the data with the recipient's private key. Only they will be able to view it.")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Mark as Message:\n Mark data as message. The recipient will be able to view it in the message section.")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Base64 Encoding:\n Encode the data with base64, it is a group of binary-to-text encoding scheme that representd binary data in an ASCII string format by translating it into a radix-64 representation.")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Operation:\n A static operation for blockchain programmability.")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Data:\n A variable operation for blockchain programmability.")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Alias Recipient:\n Use an alias of the recipient in the recipient field if they have one registered")
aliases_box.insert (INSERT, "\n\n")
aliases_box.insert (INSERT, "Resolve Aliases:\n Show aliases instead of addressess where applicable in the table below.")
aliases_box.insert (INSERT, "\n\n")
close = Button (top13, text="Close", command=top13.destroy)
close.grid (row=3, column=0, sticky=W + E)
def data_insert_clear():
openfield.delete ('1.0', END) # remove previous
def all_spend_clear():
all_spend_var.set (False)
amount.delete (0, END)
amount.insert (0, 0)
def all_spend():
# all_spend_var.set(True)
all_spend_check ()
def all_spend_check():
if all_spend_var.get ():
openfield_fee_calc = openfield.get ("1.0", END).strip ()
if encode_var.get () and not msg_var.get ():
openfield_fee_calc = base64.b64encode (openfield_fee_calc.encode ("utf-8")).decode ("utf-8")
if msg_var.get () and encode_var.get ():
openfield_fee_calc = "bmsg=" + base64.b64encode (openfield_fee_calc.encode ("utf-8")).decode ("utf-8")
if msg_var.get () and not encode_var.get ():
openfield_fee_calc = "msg=" + openfield_fee_calc
if encrypt_var.get ():
openfield_fee_calc = "enc=" + str (openfield_fee_calc)
fee_from_all = fee_calculate (openfield_fee_calc)
amount.delete (0, END)
amount.insert (0, (Decimal (balance_raw.get ()) - Decimal (fee_from_all)))
def fingerprint():
root.filename = filedialog.askopenfilename (multiple=True, initialdir="", title="Select files for fingerprinting")
dict = {}
for file in root.filename:
with open (file, 'rb') as fp:
data = hashlib.blake2b (fp.read ()).hexdigest ()
dict[os.path.split (file)[-1]] = data
openfield.insert (INSERT, dict)
def keys_load_dialog():
global key
global private_key_readable
global encrypted
global unlocked
global public_key_hashed
global myaddress
global private_key_load
global public_key_load
wallet_load = filedialog.askopenfilename (multiple=False, initialdir="", title="Select private key")
key, public_key_readable, private_key_readable, encrypted, unlocked, public_key_hashed, myaddress = essentials.keys_load_new (wallet_load) # upgrade later, remove blanks
encryption_button_refresh ()
gui_address_t.delete (0, END)
gui_address_t.insert (INSERT, myaddress)
recipient_address.config (state=NORMAL)
recipient_address.delete (0, END)
recipient_address.insert (INSERT, myaddress)
recipient_address.config (state=DISABLED)
sender_address.config (state=NORMAL)
sender_address.delete (0, END)
sender_address.insert (INSERT, myaddress)
sender_address.config (state=DISABLED)
refresh (myaddress, s)
def keys_backup():
root.filename = filedialog.asksaveasfilename (initialdir="", title="Select backup file")
if not root.filename == "":
if not root.filename.endswith (".tar.gz"):
root.filename = root.filename + ".tar.gz"
der_files = glob.glob ("*.der")
tar = tarfile.open (root.filename, "w:gz")
for der_file in der_files:
tar.add (der_file, arcname=der_file)
tar.close ()
def watch():
address = gui_address_t.get ()
refresh (address, s)
def unwatch():
gui_address_t.delete (0, END)
gui_address_t.insert (INSERT, myaddress)
refresh (myaddress, s)
def aliases_list():
top12 = Toplevel ()
top12.title ("Your aliases")
aliases_box = Text (top12, width=100)
aliases_box.grid (row=0, pady=0)
# This will freeze, but let say it's ok, we're waiting for a feedback.
aliases_self = async_client.connection.command("aliasget", myaddress)
for x in aliases_self:
aliases_box.insert (INSERT, replace_regex (x[0], "alias="))
aliases_box.insert (INSERT, "\n")
close = Button (top12, text="Close", command=top12.destroy)
close.grid (row=3, column=0, sticky=W + E, padx=15, pady=(5, 5))
def recipient_insert():
recipient.delete (0, END)
recipient.insert (0, root.clipboard_get ())
def address_insert():
gui_address_t.delete (0, END)
gui_address_t.insert (0, root.clipboard_get ())
def data_insert():
openfield.delete ('1.0', END) # remove previous
openfield.insert (INSERT, root.clipboard_get ())
def data_insert_r():
openfield_r.delete ('1.0', END) # remove previous
openfield_r.insert (INSERT, root.clipboard_get ())
def url_insert():
url.delete (0, END) # remove previous
url.insert (0, root.clipboard_get ())
def address_copy():
root.clipboard_clear ()
root.clipboard_append (myaddress)
def url_copy():
root.clipboard_clear ()
root.clipboard_append (url_r.get ())
def recipient_copy():
root.clipboard_clear ()
root.clipboard_append (recipient.get ())
def percentage(percent, whole):
return (Decimal (percent) * Decimal (whole) / 100)
def alias():
alias_var = StringVar ()
# enter password
top8 = Toplevel ()
top8.title ("Enter Desired Name")
alias_label = Label (top8, text="Input name")
alias_label.grid (row=0, column=0, sticky=N + W, padx=15, pady=(5, 0))
input_alias = Entry (top8, textvariable=alias_var)
input_alias.grid (row=1, column=0, sticky=N + E, padx=15, pady=(0, 5))
dismiss = Button (top8, text="Register", command=lambda: alias_register (alias_var.get ().strip ()))
dismiss.grid (row=2, column=0, sticky=W + E, padx=15, pady=(15, 0))
dismiss = Button (top8, text="Dismiss", command=top8.destroy)
dismiss.grid (row=3, column=0, sticky=W + E, padx=15, pady=(5, 5))
def encrypt_get_password():
# enter password
top3 = Toplevel ()
top3.title ("Enter Password")
password_label = Label (top3, text="Input password")
password_label.grid (row=0, column=0, sticky=N + W, padx=15, pady=(5, 0))
input_password = Entry (top3, textvariable=password_var_enc, show='*')
input_password.grid (row=1, column=0, sticky=N + E, padx=15, pady=(0, 5))
confirm_label = Label (top3, text="Confirm password")
confirm_label.grid (row=2, column=0, sticky=N + W, padx=15, pady=(5, 0))
input_password_con = Entry (top3, textvariable=password_var_con, show='*')
input_password_con.grid (row=3, column=0, sticky=N + E, padx=15, pady=(0, 5))
enter = Button (top3, text="Encrypt", command=lambda: encrypt_fn (top3))
enter.grid (row=4, column=0, sticky=W + E, padx=15, pady=(5, 5))
cancel = Button (top3, text="Cancel", command=top3.destroy)
cancel.grid (row=5, column=0, sticky=W + E, padx=15, pady=(5, 5))
# enter password
def lock_fn(button):
key = None
decrypt_b.configure (text="Unlock", state=NORMAL)
lock_b.configure (text="Locked", state=DISABLED)
messagemenu.entryconfig ("Sign Messages", state=DISABLED) # messages
walletmenu.entryconfig ("Recovery", state=DISABLED) # recover
password_var_dec.set ("")
def encrypt_fn(destroy_this):
global key, public_key_readable, private_key_readable, encrypted, unlocked, public_key_hashed, myaddress
password = password_var_enc.get ()
password_conf = password_var_con.get ()
if password == password_conf:
ciphertext = encrypt (password, private_key_readable)
ciphertext_export = base64.b64encode (ciphertext).decode ()
essentials.keys_save (ciphertext_export, public_key_readable, myaddress)
# encrypt_b.configure(text="Encrypted", state=DISABLED)
key, public_key_readable, private_key_readable, encrypted, unlocked, public_key_hashed, myaddress = essentials.keys_load (private_key_load, public_key_load)
encryption_button_refresh ()
destroy_this.destroy ()
# lock_b.configure(text="Lock", state=NORMAL)
else:
messagebox.showwarning ("Mismatch", "Password Mismatch")
def decrypt_get_password():
# enter password
top4 = Toplevel ()
top4.title ("Enter Password")
input_password = Entry (top4, textvariable=password_var_dec, show='*')
input_password.grid (row=0, column=0, sticky=N + E, padx=15, pady=(5, 5))
enter = Button (top4, text="Unlock", command=lambda: decrypt_fn (top4))
enter.grid (row=1, column=0, sticky=W + E, padx=15, pady=(5, 5))
cancel = Button (top4, text="Cancel", command=top4.destroy)
cancel.grid (row=2, column=0, sticky=W + E, padx=15, pady=(5, 5))
# enter password
def decrypt_fn(destroy_this):
global key
try:
password = password_var_dec.get ()
decrypted_privkey = decrypt (password, base64.b64decode (private_key_readable)) # decrypt privkey
key = RSA.importKey (decrypted_privkey) # be able to sign
destroy_this.destroy ()
decrypt_b.configure (text="Unlocked", state=DISABLED)
lock_b.configure (text="Lock", state=NORMAL)
messagemenu.entryconfig ("Sign Messages", state=NORMAL) # messages
walletmenu.entryconfig ("Recovery", state=NORMAL) # recover
except:
messagebox.showwarning ("Locked", "Wrong password")
return key
def send_confirm(amount_input, recipient_input, operation_input, openfield_input):
amount_input = quantize_eight (amount_input)
# cryptopia check
if recipient_input == "edf2d63cdf0b6275ead22c9e6d66aa8ea31dc0ccb367fad2e7c08a25" and len (openfield_input) not in [16, 20]:
messagebox.showinfo ("Cannot send", "Identification message is missing for Cryptopia, please include it")
return
# cryptopia check
top10 = Toplevel ()
top10.title ("Confirm")
if alias_cb_var.get (): # alias check
"""
connections.send (s, "addfromalias", 10)
connections.send (s, recipient_input, 10)
recipient_input = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
recipient_input = async_client.connection.command("addfromalias", recipient_input)
# encr check
if encrypt_var.get ():
# get recipient's public key
"""
connections.send (s, "pubkeyget", 10)
connections.send (s, recipient_input, 10)
target_public_key_hashed = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
target_public_key_hashed = async_client.connection.command("pubkeyget", recipient_input)
recipient_key = RSA.importKey (base64.b64decode (target_public_key_hashed).decode ("utf-8"))
# openfield_input = str(target_public_key.encrypt(openfield_input.encode("utf-8"), 32))
data = openfield_input.encode ("utf-8")
# print (open("pubkey.der").read())
session_key = get_random_bytes (16)
cipher_aes = AES.new (session_key, AES.MODE_EAX)
# Encrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new (recipient_key)
# Encrypt the data with the AES session key
ciphertext, tag = cipher_aes.encrypt_and_digest (data)
enc_session_key = (cipher_rsa.encrypt (session_key))
openfield_input = str ([x for x in (cipher_aes.nonce, tag, ciphertext, enc_session_key)])
# encr check
if encode_var.get () and not msg_var.get ():
openfield_input = base64.b64encode (openfield_input.encode ("utf-8")).decode ("utf-8")
if msg_var.get () and encode_var.get ():
openfield_input = "bmsg=" + base64.b64encode (openfield_input.encode ("utf-8")).decode ("utf-8")
if msg_var.get () and not encode_var.get ():
openfield_input = "msg=" + openfield_input
if encrypt_var.get ():
openfield_input = "enc=" + str (openfield_input)
fee = fee_calculate (openfield_input)
confirmation_dialog = Text (top10, width=100)
confirmation_dialog.insert (INSERT, ("Amount: {}\nFee: {}\nTotal: {}\nTo: {}\nOperation: {}\nData: {}".format ('{:.8f}'.format (amount_input), '{:.8f}'.format (fee), '{:.8f}'.format (Decimal (amount_input) + Decimal (fee)), recipient_input, operation_input, openfield_input)))
confirmation_dialog.configure (state="disabled")
confirmation_dialog.grid (row=0, pady=0)
enter = Button (top10, text="Confirm", command=lambda: send_confirmed (amount_input, recipient_input, operation_input, openfield_input, top10))
enter.grid (row=1, column=0, sticky=W + E, padx=15, pady=(5, 5))
done = Button (top10, text="Cancel", command=top10.destroy)
done.grid (row=2, column=0, sticky=W + E, padx=15, pady=(5, 5))
def send_confirmed(amount_input, recipient_input, operation_input ,openfield_input, top10):
send (amount_input, recipient_input, operation_input, openfield_input)
top10.destroy ()
def send(amount_input, recipient_input, operation_input, openfield_input):
all_spend_check ()
if key is None:
messagebox.showerror ("Locked", "Wallet is locked")
app_log.warning ("Received tx command")
try:
Decimal (amount_input)
except:
messagebox.showerror ("Invalid Amount", "Amount must be a number")
# alias check
# alias check
if not address_validate (recipient_input):
messagebox.showerror ("Invalid Address", "Invalid address format")
else:
app_log.warning ("Amount: {}".format (amount_input))
app_log.warning ("Recipient: {}".format (recipient_input))
app_log.warning ("Data: {}".format (openfield_input))
tx_timestamp = '%.2f' % (float(stats_timestamp) - abs(float(stats_timestamp) - time.time())) #randomize timestamp for unique signatures
transaction = (str (tx_timestamp), str (myaddress), str (recipient_input), '%.8f' % float (amount_input), str (operation_input), str (openfield_input)) # this is signed, float kept for compatibility
h = SHA.new (str (transaction).encode ("utf-8"))
signer = PKCS1_v1_5.new (key)
signature = signer.sign (h)
signature_enc = base64.b64encode (signature)
app_log.warning ("Client: Encoded Signature: {}".format (signature_enc.decode ("utf-8")))
verifier = PKCS1_v1_5.new (key)
if verifier.verify (h, signature):
app_log.warning ("Client: The signature is valid, proceeding to save transaction, signature, new txhash and the public key to mempool")
# print(str(timestamp), str(address), str(recipient_input), '%.8f' % float(amount_input),str(signature_enc), str(public_key_hashed), str(keep_input), str(openfield_input))
tx_submit = str (tx_timestamp), str (myaddress), str (recipient_input), '%.8f' % float (amount_input), str (signature_enc.decode ("utf-8")), str (public_key_hashed.decode ("utf-8")), str (operation_input), str (openfield_input) # float kept for compatibility
while True:
"""
connections.send (s, "mpinsert", 10)
connections.send (s, tx_submit, 10)
reply = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
reply = async_client.connection.command("mpinsert", tx_submit)
app_log.warning ("Client: {}".format (reply))
if reply[-1] == "Success":
messagebox.showinfo("OK","Transaction accepted to mempool")
else:
messagebox.showerror("Error","There was a problem with transaction processing. Full message: {}".format(reply))
break
refresh (gui_address_t.get (), s)
else:
app_log.warning ("Client: Invalid signature")
# enter transaction end
# def app_quit():
# app_log.warning("Received quit command")
# root.destroy()
def qr(address):
address_qr = pyqrcode.create (address)
address_qr.png ('address_qr.png')
# popup
top = Toplevel ()
top.title ("Address QR Code")
im = PIL.Image.open ("address_qr.png")
photo = PIL.ImageTk.PhotoImage (im.resize ((320, 320)))
label = Label (top, image=photo)
label.image = photo # keep a reference!
label.pack ()
# msg = Message(top, text="hi")
# msg.pack()
button = Button (top, text="Dismiss", command=top.destroy)
button.pack ()
# popup
def msg_dialogue(address):
"""
connections.send (s, "addlist", 10)
connections.send (s, myaddress, 10)
addlist = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
addlist = async_client.connection.command("addlist", myaddress)
print (addlist)
def msg_received_get(addlist):
for x in addlist:
if x[11].startswith (("msg=", "bmsg=", "enc=msg=", "enc=bmsg=")) and x[3] == address:
# print(x[11])
"""
connections.send (s, "aliasget", 10)
connections.send (s, x[2], 10)
msg_address = connections.receive (s, 10)[0][0]
"""
# We could/should use the cache, but say we do a live request for now.
msg_address = async_client.connection.command("aliasget", x[2])
if x[11].startswith ("enc=msg="):
msg_received_digest = replace_regex (x[11], "enc=msg=")
try:
# msg_received_digest = key.decrypt(ast.literal_eval(msg_received_digest)).decode("utf-8")
(cipher_aes_nonce, tag, ciphertext, enc_session_key) = ast.literal_eval (msg_received_digest)
# Decrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new (key)
session_key = cipher_rsa.decrypt (enc_session_key)
# Decrypt the data with the AES session key
cipher_aes = AES.new (session_key, AES.MODE_EAX, cipher_aes_nonce)
msg_received_digest = cipher_aes.decrypt_and_verify (ciphertext, tag).decode ("utf-8")
except:
msg_received_digest = "Could not decrypt message"
elif x[11].startswith ("enc=bmsg="):
msg_received_digest = replace_regex (x[11], "enc=bmsg=")
try:
msg_received_digest = base64.b64decode (msg_received_digest).decode ("utf-8")
# msg_received_digest = key.decrypt(ast.literal_eval(msg_received_digest)).decode("utf-8")
(cipher_aes_nonce, tag, ciphertext, enc_session_key) = ast.literal_eval (msg_received_digest)
# Decrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new (key)
session_key = cipher_rsa.decrypt (enc_session_key)
# Decrypt the data with the AES session key
cipher_aes = AES.new (session_key, AES.MODE_EAX, cipher_aes_nonce)
msg_received_digest = cipher_aes.decrypt_and_verify (ciphertext, tag).decode ("utf-8")
except:
msg_received_digest = "Could not decrypt message"
elif x[11].startswith ("bmsg="):
msg_received_digest = replace_regex (x[11], "bmsg=")
try:
msg_received_digest = base64.b64decode (msg_received_digest).decode ("utf-8")
except:
msg_received_digest = "Could not decode message"
elif x[11].startswith ("msg="):
msg_received_digest = replace_regex (x[11], "msg=")
msg_received.insert (INSERT, ((time.strftime ("%Y-%m-%d %H:%M:%S", time.gmtime (Decimal (x[1])))) + " From " + replace_regex (msg_address, "alias=") + ": " + msg_received_digest) + "\n")
def msg_sent_get(addlist):
for x in addlist:
if x[11].startswith (("msg=", "bmsg=", "enc=msg=", "enc=bmsg=")) and x[2] == address:
# print(x[11])
"""
connections.send (s, "aliasget", 10)
connections.send (s, x[3], 10)
received_aliases = connections.receive (s, 10)
"""
# We could/should use the cache, but say we do a live request for now.
received_aliases = async_client.connection.command("aliasget", x[3])
msg_recipient = received_aliases[0][0]
if x[11].startswith ("enc=msg="):
msg_sent_digest = replace_regex (x[11], "enc=msg=")
try:
# msg_sent_digest = key.decrypt(ast.literal_eval(msg_sent_digest)).decode("utf-8")
(cipher_aes_nonce, tag, ciphertext, enc_session_key) = ast.literal_eval (msg_sent_digest)
# Decrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new (key)
session_key = cipher_rsa.decrypt (enc_session_key)
# Decrypt the data with the AES session key
cipher_aes = AES.new (session_key, AES.MODE_EAX, cipher_aes_nonce)
msg_sent_digest = cipher_aes.decrypt_and_verify (ciphertext, tag).decode ("utf-8")
except:
msg_sent_digest = "Could not decrypt message"
elif x[11].startswith ("enc=bmsg="):
msg_sent_digest = replace_regex (x[11], "enc=bmsg=")
try:
msg_sent_digest = base64.b64decode (msg_sent_digest).decode ("utf-8")
# msg_sent_digest = key.decrypt(ast.literal_eval(msg_sent_digest)).decode("utf-8")
(cipher_aes_nonce, tag, ciphertext, enc_session_key) = ast.literal_eval (msg_sent_digest)
# Decrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new (key)
session_key = cipher_rsa.decrypt (enc_session_key)
# Decrypt the data with the AES session key
cipher_aes = AES.new (session_key, AES.MODE_EAX, cipher_aes_nonce)
msg_sent_digest = cipher_aes.decrypt_and_verify (ciphertext, tag).decode ("utf-8")
except:
msg_sent_digest = "Could not decrypt message"
elif x[11].startswith ("bmsg="):
msg_sent_digest = replace_regex (x[11], "bmsg=")
try:
msg_sent_digest = base64.b64decode (msg_sent_digest).decode ("utf-8")
except:
msg_sent_digest = "Could not decode message"
elif x[11].startswith ("msg="):
msg_sent_digest = replace_regex (x[11], "msg=")
msg_sent.insert (INSERT, ((time.strftime ("%Y-%m-%d %H:%M:%S", time.gmtime (Decimal (x[1])))) + " To " + replace_regex (msg_recipient, "alias=") + ": " + msg_sent_digest) + "\n")
# popup
top11 = Toplevel ()
top11.title ("Messaging")
Label (top11, text="Received:", width=20).grid (row=0)
msg_received = Text (top11, width=100, height=20, font=("Tahoma", 8))
msg_received.grid (row=1, column=0, sticky=W, padx=5, pady=(5, 5))
msg_received_get (addlist)
Label (top11, text="Sent:", width=20).grid (row=2)
msg_sent = Text (top11, width=100, height=20, font=("Tahoma", 8))
msg_sent.grid (row=3, column=0, sticky=W, padx=5, pady=(5, 5))
msg_sent_get (addlist)
dismiss = Button (top11, text="Dismiss", command=top11.destroy)
dismiss.grid (row=5, column=0, sticky=W + E, padx=15, pady=(5, 5))
# popup
def refresh_auto():
root.after (0, refresh(gui_address_t.get(), s))
root.after (10000, refresh_auto)
def stats():
stats_window = Toplevel ()
stats_window.title ("Node Statistics")
stats_window.resizable (0, 0)
# canvas_stats_bg = Canvas (root, highlightthickness=0)
# canvas_stats_bg.grid (row=0, column=0, rowspan=200, columnspan=200, sticky=W + E + S + N)
# stats_window.update ()
# width_stats = stats_window.winfo_width ()
# height_stats = stats_window.winfo_height ()
# img_stats_bg = PhotoImage (file="graphics/brushed.png")
# canvas_bg.create_image (width_stats, height_stats, image=img_stats_bg)
frame_chart = Frame (stats_window, height=100, width=100)
frame_chart.grid (row=0, column=1, rowspan=999)
f = Figure (figsize=(11, 7), dpi=100)
f.set_facecolor ('silver')
f.subplots_adjust (left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.5)
canvas = FigureCanvasTkAgg (f, master=frame_chart)
canvas.get_tk_widget ().grid (row=0, column=1, sticky=W, padx=15, pady=(0, 0))
def chart_fill():
print ("Filling the chart")
f.clear ()
rows = 4
columns = 2
# f.remove(first)
first = f.add_subplot (rows, columns, 1)
first.plot ((range (len (stats_nodes_count_list))), (stats_nodes_count_list))
first.ticklabel_format (useOffset=False)
first_2 = f.add_subplot (rows, columns, 1)
first_2.plot ((range (len (stats_thread_count_list))), (stats_thread_count_list))
first_2.ticklabel_format (useOffset=False)
first.legend (('Nodes', 'Threads'), loc='best', shadow=True)
second = f.add_subplot (rows, columns, 2)
second.plot ((range (len (stats_consensus_list))), (stats_consensus_list))
second.legend (('Consensus Block',), loc='best', shadow=True)
second.ticklabel_format (useOffset=False)
third = f.add_subplot (rows, columns, 3)
third.plot ((range (len (stats_consensus_percentage_list))), (stats_consensus_percentage_list))
third.legend (('Consensus Level',), loc='best', shadow=True)
third.ticklabel_format (useOffset=False)
fourth = f.add_subplot (rows, columns, 4)
fourth.plot ((range (len (stats_diff_list_2))), (stats_diff_list_2))
fourth.legend (('Time To Generate Block',), loc='best', shadow=True)
fourth.ticklabel_format (useOffset=False)
fifth = f.add_subplot (rows, columns, 5)
fifth.plot ((range (len (stats_diff_list_0))), (stats_diff_list_0))
fifth.ticklabel_format (useOffset=False)
fifth_2 = f.add_subplot (rows, columns, 5)
fifth_2.plot ((range (len (stats_diff_list_1))), (stats_diff_list_1))
fifth_2.ticklabel_format (useOffset=False)
fifth_3 = f.add_subplot (rows, columns, 5)
fifth_3.plot ((range (len (stats_diff_list_3))), (stats_diff_list_3))
fifth_3.ticklabel_format (useOffset=False)
fifth.legend (('Diff 1', 'Diff 2', 'Diff Current',), loc='best', shadow=True)
sixth = f.add_subplot (rows, columns, 6)
sixth.plot ((range (len (stats_diff_list_4))), (stats_diff_list_4))
sixth.legend (('Block Time',), loc='best', shadow=True)
sixth.ticklabel_format (useOffset=False)
seventh = f.add_subplot (rows, columns, 7)
seventh.plot ((range (len (stats_diff_list_5))), (stats_diff_list_5))
seventh.legend (('Hashrate',), loc='best', shadow=True)
seventh.ticklabel_format (useOffset=False)
eigth = f.add_subplot (rows, columns, 8)
eigth.plot ((range (len (stats_diff_list_6))), (stats_diff_list_6))
eigth.legend (('Difficulty Adjustment',), loc='best', shadow=True)
eigth.ticklabel_format (useOffset=False)
# a tk.DrawingArea
canvas.draw ()
def update():
print ("Statistics update triggered")
stats_address = statusget[0]
stats_nodes_count = statusget[1]
stats_nodes_list = statusget[2]
stats_thread_count = statusget[3]
stats_uptime = statusget[4]
stats_consensus = statusget[5]
stats_consensus_percentage = statusget[6]
stats_version = statusget[7]
stats_diff = statusget[8]
stats_address_label_var.set ("Node Address: {}".format (stats_address))
stats_nodes_count_label_var.set ("Number of Nodes: {}".format (stats_nodes_count))
stats_nodes_list_text_var.delete (0, END)
for entry in stats_nodes_list:
stats_nodes_list_text_var.insert (END, entry)
stats_nodes_list_text_var.grid (row=2, column=0, sticky=E, padx=15, pady=(0, 0))
stats_thread_count_var.set ("Number of Threads: {}".format (stats_thread_count))
stats_uptime_var.set ("Uptime: {:.2f} hours".format (stats_uptime / 60 / 60))
stats_consensus_var.set ("Consensus Block: {}".format (stats_consensus))
stats_consensus_consensus_percentage_var.set ("Consensus Level: {:.2f}%".format (stats_consensus_percentage))
stats_version_var.set ("Version: {}".format (stats_version))
stats_diff_var_0.set ("Difficulty 1: {}".format (stats_diff[0]))
stats_diff_var_1.set ("Difficulty 2: {}".format (stats_diff[1]))
stats_diff_var_2.set ("Time to Generate Block: {}".format (stats_diff[2]))
stats_diff_var_3.set ("Current Block Difficulty: {}".format (stats_diff[3]))
stats_diff_var_4.set ("Block Time: {}".format (stats_diff[4]))
stats_diff_var_5.set ("Hashrate: {}".format (stats_diff[5]))
stats_diff_var_6.set ("Difficulty Adjustment: {}".format (stats_diff[6]))
stats_address_label_var = StringVar ()
stats_address_label = Label (stats_window, textvariable=stats_address_label_var)
stats_address_label.grid (row=0, column=0, sticky=E, padx=15, pady=(0, 0))
stats_nodes_count_label_var = StringVar ()
stats_nodes_count_label = Label (stats_window, textvariable=stats_nodes_count_label_var)
stats_nodes_count_label.grid (row=1, column=0, sticky=E, padx=15, pady=(0, 0))
scrollbar = Scrollbar (stats_window)
scrollbar.grid (row=2, column=0, sticky=N + S + E, padx=140)
stats_nodes_list_text_var = Listbox (stats_window, width=20, height=10, font=("Tahoma", 8))
scrollbar.config (command=stats_nodes_list_text_var.yview)
stats_thread_count_var = StringVar ()
stats_thread_count_label = Label (stats_window, textvariable=stats_thread_count_var)
stats_thread_count_label.grid (row=3, column=0, sticky=E, padx=15, pady=(0, 0))
stats_uptime_var = StringVar ()
stats_uptime_label = Label (stats_window, textvariable=stats_uptime_var)
stats_uptime_label.grid (row=4, column=0, sticky=E, padx=15, pady=(0, 0))
stats_consensus_var = StringVar ()
stats_consensus_label = Label (stats_window, textvariable=stats_consensus_var)
stats_consensus_label.grid (row=5, column=0, sticky=E, padx=15, pady=(0, 0))
stats_consensus_consensus_percentage_var = StringVar ()
stats_consensus_consensus_percentage_label = Label (stats_window, textvariable=stats_consensus_consensus_percentage_var)
stats_consensus_consensus_percentage_label.grid (row=6, column=0, sticky=E, padx=15, pady=(0, 0))
stats_version_var = StringVar ()
stats_version_label = Label (stats_window, textvariable=stats_version_var)
stats_version_label.grid (row=7, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_0 = StringVar ()
stats_diff_label_0 = Label (stats_window, textvariable=stats_diff_var_0)
stats_diff_label_0.grid (row=8, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_1 = StringVar ()
stats_diff_label_1 = Label (stats_window, textvariable=stats_diff_var_1)
stats_diff_label_1.grid (row=9, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_2 = StringVar ()
stats_diff_label_2 = Label (stats_window, textvariable=stats_diff_var_2)
stats_diff_label_2.grid (row=10, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_3 = StringVar ()
stats_diff_label_3 = Label (stats_window, textvariable=stats_diff_var_3)
stats_diff_label_3.grid (row=11, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_4 = StringVar ()
stats_diff_label_4 = Label (stats_window, textvariable=stats_diff_var_4)
stats_diff_label_4.grid (row=12, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_5 = StringVar ()
stats_diff_label_5 = Label (stats_window, textvariable=stats_diff_var_5)
stats_diff_label_5.grid (row=13, column=0, sticky=E, padx=15, pady=(0, 0))
stats_diff_var_6 = StringVar ()
stats_diff_label_6 = Label (stats_window, textvariable=stats_diff_var_6)
stats_diff_label_6.grid (row=14, column=0, sticky=E, padx=15, pady=(0, 0))
def refresh_stats_auto():
try:
# global frame_chart
root.after (0, update ())
root.after (10000, refresh_stats_auto)
chart_fill ()
except Exception as e:
print ("Statistics window closed, disabling auto-refresh ({})".format (e))
refresh_stats_auto ()
def csv_export(s):
"""
connections.send (s, "addlist", 10) # senders
connections.send (s, myaddress, 10)
tx_list = connections.receive (s, 10)
print (tx_list)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
tx_list = async_client.connection.command("addlist", myaddress)
root.filename = filedialog.asksaveasfilename (initialdir="", title="Select CSV file")
with open (root.filename, 'w', newline='') as csvfile:
for transaction in tx_list:
writer = csv.writer (csvfile, quoting=csv.QUOTE_MINIMAL)
writer.writerow ([transaction[0], transaction[1], transaction[3], transaction[4], transaction[5], transaction[6], transaction[7], transaction[8], transaction[9], transaction[10], transaction[11]])
return
def token_transfer(token, amount, window):
operation.delete (0, END)
operation.insert (0, "token:transfer")
openfield.delete ('1.0', END) # remove previous
openfield.insert (INSERT, "{}:{}".format (token, amount))
window.destroy ()
send_confirm (0, recipient.get (),"token:transfer", "{}:{}".format (token, amount))
def token_issue(token, amount, window):
operation.delete (0, END)
operation.insert (0, "token:issue")
openfield.delete ('1.0', END) # remove previous
openfield.insert (INSERT, "{}:{}".format (token, amount))
recipient.delete (0, END)
recipient.insert (INSERT, myaddress)
window.destroy ()
send_confirm (0, recipient.get (),"token:issue", "{}:{}".format (token, amount))
def tokens():
tokens_main = Toplevel ()
tokens_main.title ("Tokens")
token_box = Listbox (tokens_main, width=100)
token_box.grid (row=0, pady=0)
"""
connections.send (s, "tokensget", 10)
connections.send (s, gui_address_t.get (), 10)
tokens_results = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
tokens_results = async_client.connection.command("tokensget", gui_address_t.get())
print (tokens_results)
for pair in tokens_results:
token = pair[0]
balance = pair[1]
token_box.insert (END, (token, ":", balance))
# callback
def callback(event):
token_select = (token_box.get (token_box.curselection ()[0]))
token_name_var.set (token_select[0])
token_amount_var.set (token_select[2])
token_box.bind ('<Double-1>', callback)
# callback
token_name_var = StringVar ()
token_name = Entry (tokens_main, textvariable=token_name_var, width=80)
token_name.grid (row=2, column=0, sticky=E, padx=15, pady=(5, 5))
token_name_label_var = StringVar ()
token_name_label_var.set ("Token Name:")
token_name_label = Label (tokens_main, textvariable=token_name_label_var)
token_name_label.grid (row=2, column=0, sticky=W, padx=15, pady=(0, 0))
# balance_var = StringVar()
# balance_msg_label = Label(frame_buttons, textvariable=balance_var)
token_amount_var = StringVar ()
token_amount = Entry (tokens_main, textvariable=token_amount_var, width=80, )
token_amount.grid (row=3, column=0, sticky=E, padx=15, pady=(5, 5))
token_amount_label_var = StringVar ()
token_amount_label_var.set ("Token Amount:")
token_amount_label = Label (tokens_main, textvariable=token_amount_label_var)
token_amount_label.grid (row=3, column=0, sticky=W, padx=15, pady=(0, 0))
transfer = Button (tokens_main, text="Transfer", command=lambda: token_transfer (token_name_var.get (), token_amount_var.get (), tokens_main))
transfer.grid (row=4, column=0, sticky=W + E, padx=5)
issue = Button (tokens_main, text="Issue", command=lambda: token_issue (token_name_var.get (), token_amount_var.get (), tokens_main))
issue.grid (row=5, column=0, sticky=W + E, padx=5)
cancel = Button (tokens_main, text="Cancel", command=tokens_main.destroy)
cancel.grid (row=6, column=0, sticky=W + E, padx=5)
def tx_tree_define():
global tx_tree
tx_tree = ttk.Treeview (tab_transactions, selectmode="extended", columns=('sender', 'recipient', 'amount', 'type'), height=20)
tx_tree.grid (row=1, column=0)
# table
tx_tree.heading ("#0", text='time')
tx_tree.column ("#0", anchor='center', width=100)
tx_tree.heading ("#1", text='sender')
tx_tree.column ("#1", anchor='center', width=347)
tx_tree.heading ("#2", text='recipient')
tx_tree.column ("#2", anchor='center', width=347)
tx_tree.heading ("#3", text='amount')
tx_tree.column ("#3", anchor='center', width=35)
tx_tree.heading ("#4", text='type')
tx_tree.column ("#4", anchor='center', width=40)
tx_tree.grid (sticky=N + S + W + E)
def table(address, addlist_20, mempool_total):
global tx_tree
# transaction table
# data
try:
tx_tree.destroy ()
except:
pass
tx_tree_define ()
for tx in mempool_total:
tag = "mempool"
if tx[1] == address:
tx_tree.insert ('', 'end', text=datetime.fromtimestamp (float (tx[0])).strftime ('%y-%m-%d %H:%M'), values=(tx[1], tx[2], tx[3], "?"), tags=tag)
if resolve_var.get():
# aliases
#  local address
needed_aliases = [gui_address_t.get()]
for tx in addlist_20:
needed_aliases.append(tx[2]) # append address
needed_aliases.append(tx[3]) # append recipient
# no need to ask the same alias twice
needed_aliases = set(needed_aliases)
# ask for the cached version and trigger update in background
aliases = async_client.connection.aliases(needed_aliases)
for tx in addlist_20:
tx[2], tx[3] = aliases[tx[2]], aliases[tx[3]]
local_address = gui_address_t.get()
for tx in addlist_20:
if tx[3] == local_address:
tag = "received"
else:
tag = "sent"
# case for alias = this address
if resolve_var.get() and tx[3] == aliases[local_address]:
tag = "received"
# case for alias = this address
if Decimal (tx[9]) > 0:
symbol = "MIN"
elif tx[11].startswith ("bmsg"):
symbol = "B64M"
elif tx[11].startswith ("msg"):
symbol = "MSG"
else:
symbol = "TX"
tx_tree.insert ('', 'end', text=datetime.fromtimestamp (float (tx[1])).strftime ('%y-%m-%d %H:%M'), values=(tx[2], tx[3], tx[4], symbol), tags=tag)
tx_tree.tag_configure ("received", background='palegreen1')
tx_tree.tag_configure ("sent", background='chocolate1')
# table
def refresh(address, s=None):
global balance
global statusget
global block_height_old
global mempool_total
global stats_timestamp
status = async_client.connection.status(address)
if not async_client.connection.connected:
app_log.warning("Not connected yet, please wait")
ip_connected_var.set("Connecting...")
return
if not "stats_account" in status:
app_log.warning("No info yet, please wait")
ip_connected_var.set("Syncing...")
return
ip_connected_var.set(async_client.connection.ip_port)
# TEMP
# print("Status", status)
# print "refresh triggered"
try:
statusget = status['statusget']
status_version = statusget[7]
stats_timestamp = statusget[9]
server_timestamp_var.set("GMT: {}".format(time.strftime ("%H:%M:%S", time.gmtime (int(float(stats_timestamp))))))
# data for charts
block_height = statusget[8][7] # move chart only if the block height changes, returned from diff 7
try:
block_height_old
except:
block_height_old = block_height # init
if block_height_old != block_height or not stats_nodes_count_list: # or if list is empty
print ("Chart update in progress")
stats_nodes_count_list.append (statusget[1])
stats_thread_count_list.append (statusget[3])
stats_consensus_list.append (statusget[5])
stats_consensus_percentage_list.append (statusget[6])
stats_diff_list_0.append (statusget[8][0])
stats_diff_list_1.append (statusget[8][1])
stats_diff_list_2.append (statusget[8][2])
stats_diff_list_3.append (statusget[8][3])
stats_diff_list_4.append (statusget[8][4])
stats_diff_list_5.append (statusget[8][5])
stats_diff_list_6.append (statusget[8][6])
block_height_old = block_height
else:
print ("Chart update skipped, block hasn't moved")
# data for charts
stats_account = status['stats_account']
balance = stats_account[0]
credit = stats_account[1]
debit = stats_account[2]
fees = stats_account[3]
rewards = stats_account[4]
app_log.warning ("Transaction address balance: {}".format (balance))
block_get = status['block_get']
bl_height = block_get[0]
db_timestamp_last = block_get[1]
hash_last = block_get[7]
# check difficulty
diff = status['diffget']
# check difficulty
print (diff)
diff_msg = int (diff[1]) # integer is enough
# network status
time_now = str (time.time ())
last_block_ago = Decimal (time_now) - Decimal (db_timestamp_last)
if last_block_ago > 300:
sync_msg = "{}m behind".format ((int (last_block_ago / 60)))
sync_msg_label.config (fg='red')
else:
sync_msg = "Last block: {}s ago".format ((int (last_block_ago)))
sync_msg_label.config (fg='green')
# network status
mempool_total = status['mpget']
# print (mempool_total)
# fees_current_var.set("Current Fee: {}".format('%.8f' % float(fee)))
balance_var.set ("Balance: {:.8f} BIS".format (Decimal (balance)))
balance_raw.set (balance)
debit_var.set ("Sent Total: {:.8f} BIS".format (Decimal (debit)))
credit_var.set ("Received Total: {:.8f} BIS".format (Decimal (credit)))
fees_var.set ("Fees Paid: {:.8f} BIS".format (Decimal (fees)))
rewards_var.set ("Rewards: {:.8f} BIS".format (Decimal (rewards)))
bl_height_var.set ("Block: {}".format (bl_height))
diff_msg_var.set ("Difficulty: {}".format (diff_msg))
sync_msg_var.set (sync_msg)
hash_var.set ("Hash: {}...".format (hash_last[:6]))
mempool_count_var.set ("Mempool txs: {}".format (len (mempool_total)))
annverget = status['annverget']
version_var.set ("Version: {}/{}".format (status_version, annverget))
# if status_version != annverget:
# version_color = "red"
# else:
# version_color = "green"
# version_var_label.config (fg=version_color)
addlist = status['addlist']
table(address, addlist, mempool_total)
# root.after(1000, refresh)
# canvas bg
root.update()
width_root = root.winfo_width ()
height_root = root.winfo_height ()
# frame_main.update()
width_main = tab_main.winfo_width ()
height_main = tab_main.winfo_height ()
canvas_main.configure (width=width_main, height=height_main)
# photo_main.resize (width_main,height_main)
# canvas bg
annget = status['annget']
ann_var_text.config (state=NORMAL)
ann_var_text.delete ('1.0', END)
ann_var_text.insert (INSERT, annget)
ann_var_text.config (state=DISABLED)
all_spend_check ()
except Exception as e:
app_log.warning(e)
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
# node_connect()
def sign():
def verify_this():
try:
received_public_key = RSA.importKey (public_key_gui.get ("1.0", END))
verifier = PKCS1_v1_5.new (received_public_key)
hash = SHA.new (input_text.get ("1.0", END).encode ("utf-8"))
received_signature_dec = base64.b64decode (output_signature.get ("1.0", END))
if verifier.verify (hash, received_signature_dec):
messagebox.showinfo ("Validation Result", "Signature valid")
else:
raise ValueError("Invalid Signature")
except:
messagebox.showerror ("Validation Result", "Signature invalid")
def sign_this():
h = SHA.new (input_text.get ("1.0", END).encode ("utf-8"))
signer = PKCS1_v1_5.new (key)
signature = signer.sign (h)
signature_enc = base64.b64encode (signature)
output_signature.delete ('1.0', END) # remove previous
output_signature.insert (INSERT, signature_enc)
# popup
top = Toplevel ()
top.title ("Sign message")
# top.geometry("%dx%d%+d%+d" % (800, 600, 0, 0))
# top.grid_propagate(False)
Label (top, text="Message:", width=20).grid (row=0, pady=0)
input_text = Text (top, height=10)
# label.image = photo # keep a reference!
input_text.grid (row=1, column=0, sticky=N + E, padx=15, pady=(0, 0))
Label (top, text="Public Key:", width=20).grid (row=2, pady=0)
public_key_gui = Text (top, height=10)
public_key_gui.insert (INSERT, public_key_readable)
public_key_gui.grid (row=3, column=0, sticky=N + E, padx=15, pady=(0, 0))
Label (top, text="Signature:", width=20).grid (row=4, pady=0)
output_signature = Text (top, height=10)
output_signature.grid (row=5, column=0, sticky=N + E, padx=15, pady=(0, 0))
# msg = Message(top, text="hi")
# msg.pack()
sign_message = Button (top, text="Sign Message", command=sign_this)
sign_message.grid (row=6, column=0, sticky=W + E, padx=15, pady=(5, 0))
sign_message = Button (top, text="Verify Message", command=verify_this)
sign_message.grid (row=7, column=0, sticky=W + E, padx=15, pady=(15, 0))
dismiss = Button (top, text="Dismiss", command=top.destroy)
dismiss.grid (row=8, column=0, sticky=W + E, padx=15, pady=(15, 5))
# popup
def hyperlink_howto():
url = "https://github.com/EggPool/BismuthHowto"
webbrowser.open (url, new=1)
def hyperlink_BE():
url = "https://bismuth.online"
webbrowser.open (url, new=1)
def hyperlink_BISGit():
url = "https://github.com/hclivess/Bismuth/releases"
webbrowser.open (url, new=1)
def hyperlink_bct():
url = "https://bitcointalk.org/index.php?topic=1896497.0"
webbrowser.open (url, new=1)
def support_collection(sync_msg_var, version_var):
sup_col = Toplevel ()
sup_col.title ("Collection of Basic Information")
collection_box = Text (sup_col, width=100)
collection_box.grid (row=0, pady=0)
version = statusget[7]
stats_timestamp = statusget[9]
"""
connections.send (s, "blocklast", 10)
block_get = connections.receive (s, 10)
"""
# This will freeze, but let say it's ok, we're waiting for a feedback.
block_get = async_client.connection.command("blocklast")
bl_height = block_get[0]
db_timestamp_last = block_get[1]
time_now = float(time.time())
last_block_ago = int(time_now - db_timestamp_last)
collection_box.config(wrap=WORD)
collection_box.insert (INSERT, "If you have questions or want to report a problem, please copy the information below to provide it.")
collection_box.insert (INSERT, "\n\n")
collection_box.insert (INSERT, "Your OS: {} {}".format(platform.system(), platform.release()))
collection_box.insert (INSERT, "\nNode Version: {}".format(version))
collection_box.insert (INSERT, "\nConnected to: {}".format(ip))
collection_box.insert (INSERT, "\nLast Block: {}".format(bl_height))
collection_box.insert (INSERT, "\nSeconds since Last Block: {}".format(last_block_ago))
collection_box.insert (INSERT, "\nNode GMT: {}".format(time.strftime ("%H:%M:%S", time.gmtime (int(float(stats_timestamp))))))
close = Button (sup_col, text="Close", command=sup_col.destroy)
close.grid (row=3, column=0, sticky=W + E)
def themes(theme):
# global photo_bg, photo_main
global photo_main
if theme == "Barebone" or None:
# canvas_bg.delete("all")
canvas_main.delete ("all")
else:
# img_bg = PIL.Image.open ("themes/{}_bg.jpg".format(theme))
# photo_bg = PIL.ImageTk.PhotoImage (img_bg)
# canvas_bg.create_image (0, 0, image=photo_bg, anchor=NW)
width_main = tab_main.winfo_width ()
height_main = tab_main.winfo_height ()
main_bg = PIL.Image.open ("themes/{}.jpg".format (theme)).resize ((width_main, height_main), PIL.Image.ANTIALIAS)
photo_main = PIL.ImageTk.PhotoImage (main_bg)
canvas_main.create_image (0, 0, image=photo_main, anchor=NW)
with open ("theme", "w") as theme_file:
theme_file.write (theme)
def encryption_button_refresh():
if unlocked:
decrypt_b.configure (text="Unlocked", state=DISABLED)
if not unlocked:
decrypt_b.configure (text="Unlock", state=NORMAL)
messagemenu.entryconfig ("Sign Messages", state="disabled") # messages
walletmenu.entryconfig ("Recovery", state="disabled") # recover
if not encrypted:
encrypt_b.configure (text="Encrypt", state=NORMAL)
if encrypted:
encrypt_b.configure (text="Encrypted", state=DISABLED)
def connection_thread():
"""
This is running the connection client ioloop in a thread
:return:
"""
try:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
async_client.connection = async_client.AsyncClient(light_ip, app_log, loop, address=myaddress)
loop.create_task(async_client.connection.background())
try:
loop.run_forever()
except KeyboardInterrupt:
loop.stop()
app_log.info("exited from loop")
except Exception as e:
print("ect", e)
if __name__ == "__main__":
# globalize
global block_height_old
global statusget
global key
global private_key_readable
global encrypted
global unlocked
global public_key_hashed
global myaddress
global private_key_load
global public_key_load
global s
# data for charts
stats_nodes_count_list = []
stats_thread_count_list = []
stats_consensus_list = []
stats_consensus_percentage_list = []
stats_diff_list_0 = []
stats_diff_list_1 = []
stats_diff_list_2 = []
stats_diff_list_3 = []
stats_diff_list_4 = []
stats_diff_list_5 = []
stats_diff_list_6 = []
# data for charts
if os.path.exists("privkey.der"):
private_key_load = "privkey.der"
else:
private_key_load = "privkey_encrypted.der"
public_key_load = "pubkey.der"
print(getcontext())
config = options.Get()
config.read()
debug_level = config.debug_level_conf
full_ledger = config.full_ledger_conf
port = config.port
light_ip = config.light_ip
version = config.version_conf
terminal_output = config.terminal_output
gui_scaling = config.gui_scaling
# randomize light_ip-list
shuffle(light_ip)
try:
light_ip.remove('127.0.0.1')
light_ip.insert(0, '127.0.0.1')
pass
except:
pass
if "testnet" in version:
port = 2829
light_ip = ["127.0.0.1"]
# app_log = log.log("gui.log", debug_level)
app_log = log.log("wallet.log", debug_level, terminal_output)
essentials.keys_check(app_log)
essentials.db_check(app_log)
key, public_key_readable, private_key_readable, encrypted, unlocked, public_key_hashed, myaddress = essentials.keys_load(
private_key_load, public_key_load)
# Build TK INTERFACE
root = Tk()
root.wm_title("Bismuth Light Wallet")
# root.geometry("1310x700") #You want the size of the app to be 500x500
root.resizable(0, 0) # Don't allow resizing in the x or y direction / resize
# root['bg']="black"
img_icon = PIL.Image.open("graphics/icon.jpg")
photo_icon = PIL.ImageTk.PhotoImage(img_icon)
root.tk.call('wm', 'iconphoto', root._w, photo_icon, )
if gui_scaling == "adapt":
dpi_value = root.winfo_fpixels('1i')
root.tk.call('tk', 'scaling', dpi_value / 72)
elif gui_scaling != "default":
root.tk.call("tk", "scaling", gui_scaling)
password_var_enc = StringVar()
password_var_con = StringVar()
password_var_dec = StringVar()
# canvas_bg = Canvas(root,highlightthickness=0)
# canvas_bg.grid(row=0, column=0, rowspan=200,columnspan=200,sticky=W + E + S + N)
frame_bottom = Frame(root, relief='sunken', borderwidth=1)
frame_bottom.grid(row=5, column=0, sticky='NESW', pady=5, padx=5)
# notebook widget
nbtabs = ttk.Notebook(root)
nbtabs.grid(row=1, column=0, sticky='NESW', pady=5, padx=5)
# tab_main Main
tab_main = ttk.Frame(nbtabs)
nbtabs.add(tab_main, text='Overview')
canvas_main = Canvas(tab_main, highlightthickness=0)
canvas_main.grid(row=0, column=0, sticky=W + E + N + S, columnspan=99, rowspan=99)
frame_logo = Frame(tab_main, relief='ridge', borderwidth=4)
frame_logo.grid(row=1, column=0, pady=5, padx=5, sticky=W)
frame_coins = Frame(tab_main, relief='ridge', borderwidth=4)
frame_coins.grid(row=0, column=0, sticky=W + E + N, pady=5, padx=5)
frame_hyperlinks = Frame(tab_main, relief='ridge', borderwidth=4)
frame_hyperlinks.grid(row=0, column=98, pady=5, padx=5, sticky=W + N)
frame_support = Frame(tab_main, relief='ridge', borderwidth=4)
frame_support.grid(row=98, column=98, pady=5, padx=5, sticky=W + N)
# frame_mainstats = Frame(tab_main, relief = 'ridge', borderwidth = 4)
# frame_mainstats.grid(row=5, column=1, sticky=W + E + N, pady=5, padx=5)
# tab_transactions transactions
tab_transactions = ttk.Frame(nbtabs)
nbtabs.add(tab_transactions, text='History')
frame_entries_t = Frame(tab_transactions, relief='ridge', borderwidth=0)
frame_entries_t.grid(row=0, column=0, pady=5, padx=5)
# frame_labels_t = Frame(tab_transactions,relief = 'ridge', borderwidth = 0)
# frame_labels_t.grid(row=0, column=0, pady=5, padx=5, sticky=N+W+E+S)
frame_table = Frame(tab_transactions, relief='ridge', borderwidth=0)
frame_table.grid(row=1, column=0, sticky=W + E + N, pady=5, padx=5)
# refresh(myaddress, s)
# tab_send sendcoin tab
tab_send = ttk.Frame(nbtabs)
nbtabs.add(tab_send, text='Send')
frame_entries = Frame(tab_send)
frame_entries.grid(row=0, column=0, pady=5, padx=5, sticky=N + W + E + S)
frame_send = Frame(tab_send, relief='ridge', borderwidth=1)
frame_send.grid(row=0, column=2, pady=5, padx=5, sticky=N)
frame_tick = Frame(frame_send, relief='ridge', borderwidth=1)
frame_tick.grid(row=4, column=0, pady=5, padx=5, sticky=S)
# tab_receive receive
tab_receive = ttk.Frame(nbtabs)
nbtabs.add(tab_receive, text='Receive')
frame_entries_r = Frame(tab_receive, relief='ridge', borderwidth=0)
frame_entries_r.grid(row=0, column=0, pady=5, padx=5, sticky=N + W + E + S)
recipient_address = Entry(frame_entries_r, width=60, text=myaddress)
recipient_address.insert(0, myaddress)
recipient_address.grid(row=0, column=1, sticky=W, pady=5, padx=5)
recipient_address.configure(state=DISABLED)
amount_r = Entry(frame_entries_r, width=60)
amount_r.grid(row=2, column=1, sticky=W, pady=5, padx=5)
amount_r.insert(0, "0.00000000")
openfield_r = Text(frame_entries_r, width=60, height=5, font=("Tahoma", 8))
openfield_r.grid(row=3, column=1, sticky=W, pady=5, padx=5)
operation_r = Entry(frame_entries_r, width=60)
operation_r.grid(row=4, column=1, sticky=W, pady=5, padx=5)
url_r = Entry(frame_entries_r, width=60)
url_r.grid(row=5, column=1, sticky=W, pady=5, padx=5)
url_r.insert(0, "bis://")
# tab5 tokens
# tab_tokens = ttk.Frame(nbtabs)
# nbtabs.add(tab_tokens, text='Tokens')
# tab_statistics statistics
# tab_statistics = ttk.Frame(nbtabs)
# nbtabs.add(tab_statistics, text='Statistics')
# frames
# menu
# canvas
menubar = Menu(root)
walletmenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Wallet", menu=walletmenu)
walletmenu.add_command(label="Load Wallet", command=keys_load_dialog)
walletmenu.add_command(label="Backup Wallet", command=keys_backup)
walletmenu.add_command(label="Recovery", command=lambda: recover())
walletmenu.add_separator()
walletmenu.add_command(label="Spending URL QR", command=lambda: qr(url.get()))
walletmenu.add_command(label="Reception URL QR", command=lambda: qr(url_r.get()))
walletmenu.add_command(label="Alias Registration", command=alias)
walletmenu.add_command(label="Show Alias", command=aliases_list)
walletmenu.add_command(label="Fingerprint", command=fingerprint)
walletmenu.add_separator()
walletmenu.add_command(label="Exit", command=root.quit)
messagemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Message", menu=messagemenu)
messagemenu.add_command(label="Show Messages", command=lambda: msg_dialogue(gui_address_t.get()))
messagemenu.add_command(label="Sign Messages", command=sign)
if not os.path.exists("theme"):
with open("theme", "w") as theme_file:
theme_file.write("Barebone")
theme_menu = Menu(menubar, tearoff=0)
theme_list = []
for theme_picture in glob.glob('themes/*.jpg'):
theme_picture = os.path.basename(theme_picture).split('.jpg')[0]
theme_list.append(theme_picture)
theme_menu.add_command(label=theme_picture, command=lambda theme_picture=theme_picture: themes(
theme_picture)) # wow this lambda is amazing
theme_menu.add_command(label="Barebone", command=lambda: themes("Barebone"))
menubar.add_cascade(label="Themes", menu=theme_menu)
miscmenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Misc", menu=miscmenu)
miscmenu.add_command(label="Mempool", command=lambda: mempool_get(s))
miscmenu.add_command(label="CSV Export", command=lambda: csv_export(s))
miscmenu.add_command(label="Statistics", command=lambda: stats())
miscmenu.add_command(label="Tokens", command=tokens)
miscmenu.add_command(label="Help", command=help)
# labels
Label(frame_entries, text="My Address:").grid(row=0, sticky=W + N, pady=5, padx=5)
Label(frame_entries, text="Recipient:").grid(row=1, sticky=W, pady=5, padx=5)
Label(frame_entries, text="Amount:").grid(row=2, sticky=W, pady=5, padx=5)
Label(frame_entries, text="Data:", height=4).grid(row=3, sticky=W, pady=5, padx=5)
Label(frame_entries, text="Operation:", height=4).grid(row=4, sticky=W, pady=5, padx=5)
Label(frame_entries, text="URL:").grid(row=5, sticky=W + S, pady=5, padx=5)
Label(frame_entries, text="If you have a BIS URL, copy it, click paste-button\n"
"on URL field and then click 'read'."
"If you want to send Bismuth\n"
"to the shown recipient, click send and then\n"
"the confirmation dialog opens.", justify=LEFT).grid(row=6, column=1, sticky=W + S,
pady=1, padx=1, columnspan=2)
Label(frame_entries_r, text="Recipient:").grid(row=0, sticky=W, pady=5, padx=5)
Label(frame_entries_r, text="Amount:").grid(row=2, sticky=W, pady=5, padx=5)
Label(frame_entries_r, text="Data:", height=4).grid(row=3, sticky=W, pady=5, padx=5)
Label(frame_entries_r, text="Operation:", height=4).grid(row=4, sticky=W, pady=5, padx=5)
Label(frame_entries_r, text="URL:").grid(row=5, sticky=W + S, pady=5, padx=5)
Label(frame_entries_r, text="Enter amount and if wanted, a message in field Data.\n"
"Your address is automatically used. Click create and copy the url.",
justify=LEFT).grid(row=6, column=1, sticky=W + S, pady=1, padx=1, columnspan=2)
Label(frame_entries_t, text="Address:").grid(row=0, column=0, sticky=W + N, pady=5, padx=5)
resolve_var = BooleanVar()
resolve = Checkbutton(frame_entries_t, text="Aliases", variable=resolve_var,
command=lambda: refresh(gui_address_t.get(), s), width=14, anchor=W)
resolve.grid(row=0, column=5, sticky=W)
# canvas
# display the menu
root.config(menu=menubar)
# menu
# buttons
send_b = Button(frame_send, text="Send Bismuth",
command=lambda: send_confirm(str(amount.get()).strip(), recipient.get().strip(),
operation.get().strip(), (openfield.get("1.0", END)).strip()),
height=2, width=22, font=("Tahoma", 12))
send_b.grid(row=0, column=0)
frame_logo_buttons = Frame(frame_send)
frame_logo_buttons.grid(row=5, column=0, padx=5, pady=5)
encrypt_b = Button(frame_logo_buttons, text="Encrypt", command=encrypt_get_password, height=1, width=8)
encrypt_b.grid(row=0, column=0)
decrypt_b = Button(frame_logo_buttons, text="Unlock", command=decrypt_get_password, height=1, width=8)
decrypt_b.grid(row=0, column=1)
lock_b = Button(frame_logo_buttons, text="Locked", command=lambda: lock_fn(lock_b), height=1, width=8,
state=DISABLED)
lock_b.grid(row=0, column=2)
encryption_button_refresh()
# buttons
# refreshables
# update balance label
balance_raw = StringVar()
balance_var = StringVar()
balance_msg_label = Label(frame_coins, textvariable=balance_var, font=("Tahoma", 16, "bold"))
balance_msg_label.grid(row=0, column=0, sticky=S, padx=15)
balance_msg_label_sendtab = Label(frame_send, textvariable=balance_var, font=("Tahoma", 10))
balance_msg_label_sendtab.grid(row=3, column=0, sticky=N + S)
debit_var = StringVar()
spent_msg_label = Label(frame_coins, textvariable=debit_var, font=("Tahoma", 12))
spent_msg_label.grid(row=1, column=0, sticky=N + E, padx=15)
credit_var = StringVar()
received_msg_label = Label(frame_coins, textvariable=credit_var, font=("Tahoma", 12))
received_msg_label.grid(row=2, column=0, sticky=N + E, padx=15)
fees_var = StringVar()
fees_paid_msg_label = Label(frame_coins, textvariable=fees_var, font=("Tahoma", 12))
fees_paid_msg_label.grid(row=3, column=0, sticky=N + E, padx=15)
rewards_var = StringVar()
rewards_paid_msg_label = Label(frame_coins, textvariable=rewards_var, font=("Tahoma", 12))
rewards_paid_msg_label.grid(row=4, column=0, sticky=N + E, padx=15)
bl_height_var = StringVar()
block_height_label = Label(frame_bottom, textvariable=bl_height_var)
block_height_label.grid(row=0, column=7, sticky=S + E, padx=5)
ip_connected_var = StringVar()
ip_connected_label = Label(frame_bottom, textvariable=ip_connected_var)
ip_connected_label.grid(row=0, column=8, sticky=S + E, padx=5)
diff_msg_var = StringVar()
diff_msg_label = Label(frame_bottom, textvariable=diff_msg_var)
diff_msg_label.grid(row=0, column=5, sticky=S + E, padx=5)
sync_msg_var = StringVar()
sync_msg_label = Label(frame_bottom, textvariable=sync_msg_var)
sync_msg_label.grid(row=0, column=0, sticky=N + E, padx=15)
version_var = StringVar()
version_var_label = Label(frame_bottom, textvariable=version_var)
version_var_label.grid(row=0, column=2, sticky=N + E, padx=15)
hash_var = StringVar()
hash_var_label = Label(frame_bottom, textvariable=hash_var)
hash_var_label.grid(row=0, column=4, sticky=S + E, padx=5)
mempool_count_var = StringVar()
mempool_count_var_label = Label(frame_bottom, textvariable=mempool_count_var)
mempool_count_var_label.grid(row=0, column=3, sticky=S + E, padx=5)
server_timestamp_var = StringVar()
server_timestamp_label = Label(frame_bottom, textvariable=server_timestamp_var)
server_timestamp_label.grid(row=0, column=9, sticky=S + E, padx=5)
ann_var = StringVar()
ann_var_text = Text(frame_logo, width=20, height=4, font=("Tahoma", 8))
ann_var_text.grid(row=1, column=0, sticky=E + W, padx=5, pady=5)
ann_var_text.config(wrap=WORD)
ann_var_text.config(background="grey75")
encode_var = BooleanVar()
alias_cb_var = BooleanVar()
msg_var = BooleanVar()
encrypt_var = BooleanVar()
all_spend_var = BooleanVar()
# address and amount
# gui_address.configure(state="readonly")
gui_copy_address = Button(frame_entries, text="Copy", command=address_copy, font=("Tahoma", 7))
gui_copy_address.grid(row=0, column=2, sticky=W)
gui_copy_recipient = Button(frame_entries, text="Copy", command=recipient_copy, font=("Tahoma", 7))
gui_copy_recipient.grid(row=1, column=2, sticky=W)
gui_insert_recipient = Button(frame_entries, text="Paste", command=recipient_insert, font=("Tahoma", 7))
gui_insert_recipient.grid(row=1, column=3, sticky=W)
# gui_help = Button(frame_entries, text="Help", command=help, font=("Tahoma", 7))
# gui_help.grid(row=4, column=2, sticky=W + E, padx=(5, 0))
gui_all_spend = Checkbutton(frame_entries, text="All", variable=all_spend_var, command=all_spend,
font=("Tahoma", 7))
gui_all_spend.grid(row=2, column=2, sticky=W)
gui_all_spend_clear = Button(frame_entries, text="Clear", command=all_spend_clear, font=("Tahoma", 7))
gui_all_spend_clear.grid(row=2, column=3, sticky=W)
data_insert_clipboard = Button(frame_entries, text="Paste", command=data_insert, font=("Tahoma", 7))
data_insert_clipboard.grid(row=3, column=2)
data_insert_clear = Button(frame_entries, text="Clear", command=data_insert_clear, font=("Tahoma", 7))
data_insert_clear.grid(row=3, column=3, sticky=W)
url_insert_clipboard = Button(frame_entries, text="Paste", command=url_insert, font=("Tahoma", 7))
url_insert_clipboard.grid(row=5, column=2, sticky=W)
read_url_b = Button(frame_entries, text="Read", command=lambda: read_url_clicked(app_log, url.get()),
font=("Tahoma", 7))
read_url_b.grid(row=5, column=3, sticky=W)
data_insert_clipboard = Button(frame_entries_r, text="Paste", command=data_insert_r, font=("Tahoma", 7))
data_insert_clipboard.grid(row=3, column=2)
data_insert_clear = Button(frame_entries_r, text="Clear", command=data_insert_clear, font=("Tahoma", 7))
data_insert_clear.grid(row=3, column=3, sticky=W)
gui_copy_address_r = Button(frame_entries_r, text="Copy", command=address_copy, font=("Tahoma", 7))
gui_copy_address_r.grid(row=0, column=2, sticky=W)
gui_copy_url_r = Button(frame_entries_r, text="Copy", command=url_copy, font=("Tahoma", 7))
gui_copy_url_r.grid(row=5, column=3, sticky=W)
create_url_b = Button(frame_entries_r, text="Create",
command=lambda: create_url_clicked(app_log, "pay", gui_address_t.get(), amount_r.get(),
operation_r.get(), openfield_r.get("1.0", END).strip()),
font=("Tahoma", 7))
create_url_b.grid(row=5, column=2, sticky=W)
gui_paste_address = Button(frame_entries_t, text="Paste", command=address_insert, font=("Tahoma", 7))
gui_paste_address.grid(row=0, column=2, sticky=W)
gui_watch = Button(frame_entries_t, text="Watch", command=watch, font=("Tahoma", 7))
gui_watch.grid(row=0, column=3, sticky=W)
gui_unwatch = Button(frame_entries_t, text="Reset", command=unwatch, font=("Tahoma", 7))
gui_unwatch.grid(row=0, column=4, sticky=W, padx=(0, 5))
# hyperlinks
hyperlink_BISGit = Button(frame_hyperlinks, text="Bismuth@Github", command=hyperlink_BISGit, font=("Tahoma", 7))
hyperlink_BISGit.grid(row=0, column=0, sticky=N + E + S + W, padx=1, pady=1)
hyperlink_BE = Button(frame_hyperlinks, text="Official Block Explorer", command=hyperlink_BE, font=("Tahoma", 7))
hyperlink_BE.grid(row=1, column=0, sticky=N + E + S + W, padx=1, pady=1)
hyperlink_howto = Button(frame_hyperlinks, text="HowTos@Github", command=hyperlink_howto, font=("Tahoma", 7))
hyperlink_howto.grid(row=2, column=0, sticky=N + E + S + W, padx=1, pady=1)
hyperlink_bct = Button(frame_hyperlinks, text="BIS@Bitcointalk", command=hyperlink_bct, font=("Tahoma", 7))
hyperlink_bct.grid(row=3, column=0, sticky=N + E + S + W, padx=1, pady=1)
# hyperlinks
# supportbutton
dev_support = Button(frame_support, text="Collect Info for Support",
command=lambda: support_collection(str(sync_msg_var), str(version_var)), font=("Tahoma", 7))
dev_support.grid(row=98, column=98, sticky=N + E + S + W, padx=1, pady=1)
# supportbutton
gui_address_t = Entry(frame_entries_t, width=60)
gui_address_t.grid(row=0, column=1, sticky=W, pady=5, padx=5)
gui_address_t.insert(0, myaddress)
sender_address = Entry(frame_entries, width=60)
sender_address.insert(0, myaddress)
sender_address.grid(row=0, column=1, sticky=W, pady=5, padx=5)
sender_address.configure(state=DISABLED)
recipient = Entry(frame_entries, width=60)
recipient.grid(row=1, column=1, sticky=W, pady=5, padx=5)
amount = Entry(frame_entries, width=60)
amount.grid(row=2, column=1, sticky=W, pady=5, padx=5)
amount.insert(0, "0.00000000")
openfield = Text(frame_entries, width=60, height=5, font=("Tahoma", 8))
openfield.grid(row=3, column=1, sticky=W, pady=5, padx=5)
operation = Entry(frame_entries, width=60)
operation.grid(row=4, column=1, sticky=W, pady=5, padx=5)
url = Entry(frame_entries, width=60)
url.grid(row=5, column=1, sticky=W, pady=5, padx=5)
url.insert(0, "bis://")
encode = Checkbutton(frame_tick, text="Base64 Encoding", variable=encode_var, command=all_spend_check, width=14,
anchor=W)
encode.grid(row=0, column=0, sticky=W)
msg = Checkbutton(frame_tick, text="Mark as Message", variable=msg_var, command=all_spend_check, width=14, anchor=W)
msg.grid(row=1, column=0, sticky=W)
encr = Checkbutton(frame_tick, text="Encrypt with PK", variable=encrypt_var, command=all_spend_check, width=14,
anchor=W)
encr.grid(row=2, column=0, sticky=W)
alias_cb = Checkbutton(frame_tick, text="Alias Recipient", variable=alias_cb_var, command=None, width=14, anchor=W)
alias_cb.grid(row=4, column=0, sticky=W)
balance_enumerator = Entry(frame_entries, width=5)
# address and amount
# logo
# logo_hash_decoded = base64.b64decode(icons.logo_hash)
# logo = PhotoImage(data="graphics/logo.png")
logo_img = PIL.Image.open("graphics/logo.jpg")
logo = PIL.ImageTk.PhotoImage(logo_img)
Label(frame_logo, image=logo).grid(column=0, row=0)
# logo
# / Build TK INTERFACE
# Run the threaded ioloop that handles the connection and refresh in the background
loop = threading.Thread(target=connection_thread)
loop.daemon = True
loop.start()
# let the object take a coffee and wake up.
time.sleep(0.1)
s = None # Temp hack
refresh_auto()
try:
themes (open ("theme", "r").read ()) # load last selected theme
except:
with open ("theme", "w") as theme_file:
theme_file.write ("Barebone")
root.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment