Updated to work with simplewallet 0.8.8.6.

This commit is contained in:
jwinterm
2014-12-12 09:02:23 -06:00
parent 3bf712a97d
commit 1e0d8cc270
17 changed files with 802 additions and 623 deletions
+11 -6
View File
@@ -1,18 +1,23 @@
# lightWallet Kivy GUI
This is a GUI frontend that runs on top of bitmonerod and simplewallet (in RPC mode). It is designed to work with a remote bitmonerod node, so that it can function as a lightweight wallet for most users. **This program is an early beta version, and although I don't think there is really any way to screw up your wallet, please exercise some modicum of caution.**
This is a GUI frontend that runs on top of bitmonerod and simplewallet (in RPC mode). It is designed to work with a remote bitmonerod node, so that it can function as a lightweight wallet for most users. **This program is an alpha version, and although I don't think there is really any way to screw up your wallet, please exercise some modicum of caution.**
## Installation
### Windows, Linux, and Mac
The requirements for running the program are: Python 2.7, Kivy 1.8, and pygame 1.9.1. If you have these requirements, then you just need to add your binary (simplewallet.exe) and optionally wallet files to your cryptonoteRPCwalletGUI folder, or unzip the cryptonoteRPCwalletGUI contents into the folder where you currently have your binaries and wallet files. For the time being they have to be in the same local directory.
The requirements for running the program from the source files are: Python 2.7, Kivy 1.8, and pygame 1.9.1. The program is also only intended for windows at the moment; it may be semi-functional on linux or mac, but I don't think it will work properly. If you have these requirements, then you just need to add your binary, simplewallet.exe(currently designed to work only with the latest tagged release), and optionally wallet files to your cryptonoteRPCwalletGUI folder, or unzip the cryptonoteRPCwalletGUI contents into the folder where you currently have your binaries and wallet files. For the time being they have to be in the same local directory.
Currently there are no binaries available, but the plan is to compile an exe for Windows, andfrom there it should be easy to create binaries for linux.
If you're using the binary, there are no requirements other than an x64 Windows computer.
## Running
It should be OK to launch the program with an instance of bitmonerod and/or simplewallet running.
On the initial run, it will prompt you to create a new wallet or to import one by typing/copying in the path of the keys file. This will create a folder in the local directory where the new/imported wallet data is stored, and a file called CONFIG.file that let's lightWallet know which account is currently the default one being used.
On the initial run, it will prompt you to create a new wallet or to import one by typing/copying in the path of the keys file. This will create a folder in the local directory where the new/imported wallet data is stored, and a file called CONFIG.file that let's lightWallet know which account is currently the default one being used. If you would like to create/import a new wallet, you can simply delete CONFIG.file and it will run the initial config prompt again (this won't affect any wallet folders already in the lightWallet directory).
## Known issues
The transaction history and calculated balance features are not fully working yet. This is something I plan to address, but since the wallet itself works, and you can always see your balances with the total and unlocked balance readings, I decided to go ahead and release this alpha version, and will work on
## Future Work
There are several features I'd like to implement, the most important of which is probably tab or file keeping a record of all incoming and outgoing transactions. This is a really key feature that should probably be a part of any wallet, but I'm still having some trouble with the gui here, so it is delayed for the time being.
There are several features I'd like to implement, the most important of which is probably tab for an address book, where you can store addresses (and payment ids) that are each a button, and when you click the button it autofills everything on the transfer tab. Of course I'm working on the record keeping of all incoming and outgoing transactions and the calculated balance which is derived from them. This is a really key feature that should probably be a part of any wallet, but the wallet is still functional at the moment, and the transaction history is quasi-functional.
Another thing I want to change is using argparse rather than argv to parse command line arguments. This should make the program more robust (less crashy) and offer the user additional help at the command line. I probably want to clean up the interface and prettify it a bit more too. I'm open to suggestions too, so please open an issue or email me if you have any ideas, complaints, etc.
I'd like to figure out why the stdout output of simplewallet.exe lags sometimes, and it doesn't look like the wallet is quite synced up; this doesn't affect anything except making the wallet appear like it is a few blocks behind the daemon. Another thing I want to change is using argparse rather than argv to parse command line arguments.
I want to clean up the interface and prettify it a bit more too. I'm open to suggestions, so please open an issue or email me if you have any ideas, complaints, etc.
-7
View File
@@ -1,7 +0,0 @@
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
print parser.parse_args()
-49
View File
@@ -1,49 +0,0 @@
import requests
import json
import time
serverURL = 'http://localhost:19091/json_rpc'
headers = {'content-type': 'application/json'}
payload1 = json.dumps({
"jsonrpc": "2.0",
"method": "getbalance",
"params": {}
})
payload2 = json.dumps({
"jsonrpc": "2.0",
"method": "getaddress",
"params": {}
})
def balancecheck(jobqueue, resultsqueue):
"""function to make rpc call to simplewallet to get current balance"""
kivysignal = True
while kivysignal:
time.sleep(2)
walletrunning, kivysignal = jobqueue.get()
if walletrunning:
#print 'attempting rpc call'
try:
#Make rpc call
resp1 = requests.get(serverURL, headers=headers, data=payload1)
output1 = json.loads(resp1.text)
#Parse json data to get balance info
rawbalance = str(output1[u'result'][u'balance']/1e12)
rawunlockedbalance = str(output1[u'result'][u'unlocked_balance']/1e12)
#Format data for kivy
balance = '[color=00ff00]'+rawbalance+'[/color]'
unlockedbalance = '[color=00ff00]'+rawunlockedbalance+'[/color]'
resp2 = requests.get(serverURL, headers=headers, data=payload2)
output2 = json.loads(resp2.text)
address = str(output2[u'result'][u'address'])
except:
#Return out of sync if bitmonerod is not ready
balance = '[color=ff0000]out of sync[/color]'
unlockedbalance = '[color=ff0000]out of sync[/color]'
address = '[color=ff0000]out of sync[/color]'
resultsqueue.put((balance, unlockedbalance, address))
-16
View File
@@ -1,16 +0,0 @@
from subprocess import PIPE, Popen
from threading import Thread
from Queue import Queue, Empty
def bitmonerodloader():
"""Start bitmonerod and/or simplewallet and collect wallet name and address"""
p = Popen(
# ["bitmonerod.exe", "--set_log", "0"],
["bitmonerod.exe", "--set_log", "0"],
stdout=PIPE,
stdin=PIPE,
bufsize=1,
close_fds=ON_POSIX)
+11 -11
View File
@@ -1,34 +1,34 @@
import requests
import json
serverURL = 'http://localhost:8082/json_rpc'
def CheckBalanceSimplewallet():
"""function to make rpc call to simplewallet to get current balance"""
serverURL = 'http://localhost:19091/json_rpc'
headers = {'content-type': 'application/json'}
payload = json.dumps({
"jsonrpc": "2.0",
"method": "getbalance",
"params": {}
})
print 'Attempting {0} RPC call'.format(CheckBalanceSimplewallet.__name__)
def CheckBalanceSimplewallet():
"""function to make rpc call to simplewallet to get current balance"""
# print 'Attempting {0} RPC call'.format(CheckBalanceSimplewallet.__name__)
try:
#Make rpc call
headers = {'content-type': 'application/json'}
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
#Parse json data to get balance info
balance = str(output[u'result'][u'balance']/1e12)
unlockedbalance = str(output[u'result'][u'unlocked_balance']/1e12)
return output, balance, unlockedbalance
# print("got balances")
return balance, unlockedbalance
except:
# Return out of sync if bitmonerod is not ready
# print("couldn't connect")
message = "Can't connect to simplewallet"
return message, message, message
return message, message
-22
View File
@@ -1,22 +0,0 @@
import requests
import json
serverURL = 'http://localhost:8082/json_rpc'
payload = json.dumps({
"jsonrpc": "2.0",
"method": "store",
"params": {}
})
def checkwalletrpccall():
headers = {'content-type': 'application/json'}
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
print output
# return output[u'result'][u'balance'], output[u'result'][u'unlocked_balance']
if __name__ == "__main__":
checkwallet()
-16
View File
@@ -1,16 +0,0 @@
import subprocess
from sys import platform
def cpuminerloader(minerurl, user, pw, threads):
"""Start cpuminer"""
print "Start miner button pressed..."
#Start cpuminer daemon if not running
if platform == 'win32':
daemonproc = subprocess.Popen("start minerd.exe -a cryptonight -o {0} -u {1} -p {2} -t {3}".format(
minerurl, user, pw, threads), shell=True)
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
print "linux!"
daemonproc = subprocess.Popen('xterm -bg black -e "./minerd -a cryptonight -o {0} -u {1} -p {2} -t {3}"'.format(
minerurl, user, pw, threads), shell=True)
-46
View File
@@ -1,46 +0,0 @@
#!/usr/bin/python
from sys import platform
import subprocess as sub
import time
from lib.checklastblock import CheckLastBlock
def runningcheck():
"""Function to check if daemon is running"""
daemonrunning = False
if platform == 'win32':
import wmi
wmi = wmi.WMI ()
for process in wmi.Win32_Process(name='bitmonerod.exe'):
#print process.ProcessId, process.Name
if process.Name:
daemonrunning = True
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
p = sub.Popen("ps -A | grep bitmonerod", shell=True, stdout=sub.PIPE, stderr=sub.PIPE)
output, errors = p.communicate()
if output:
daemonrunning = True
return daemonrunning
def daemoncheck(queue):
"""Check if bitmonerod daemon is running and return values to kivy"""
print "Starting checkdaemon thread on: {0}".format(platform)
while True:
daemonrunning = runningcheck()
if daemonrunning:
try:
checklastblockoutput = CheckLastBlock()
except:
checklastblockoutput = 'error'
else:
checklastblockoutput = 'daemon not running'
queue.put((daemonrunning, checklastblockoutput))
time.sleep(1)
if __name__ == '__main__':
daemoncheck()
-29
View File
@@ -1,29 +0,0 @@
import requests
import json
import time
serverURL = 'http://localhost:19091/json_rpc'
headers = {'content-type': 'application/json'}
payload = json.dumps({
"jsonrpc": "2.0",
"method": "incoming_transfers",
"params": {"transfer_type": "all"}
})
def getTransfers():
resp = requests.get(serverURL, headers=headers, data=payload)
try:
output = json.loads(resp.text)
# print output
except:
# print "Waiting for bitmonerod client to sync with network..."
output = "Waiting for bitmonerod client to sync with network..."
print output
if __name__ == '__main__':
getTransfers()
-58
View File
@@ -1,58 +0,0 @@
# !/usr/bin/python
from sys import platform
import subprocess
import time
def runningcheck():
"""Function to check if daemon is running"""
daemonrunning, walletrunning, minerrunning = False, False, False
if platform == 'win32':
import wmi
wmi = wmi.WMI()
for process in wmi.Win32_Process():
# print process.ProcessId, process.Name
if process.Name == 'bitmonerod.exe':
daemonrunning = True
# print 'daemon'
if process.Name == 'simplewallet.exe':
walletrunning = True
# print 'wallet'
if process.Name == 'minerd.exe':
minerrunning = True
# print 'miner'
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
p = subprocess.Popen("ps -A", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output, errors = p.communicate()
if 'bitmonerod' in output:
daemonrunning = True
if 'simplewallet' in output:
walletrunning = True
if 'minerd' in output:
minerrunning = True
return daemonrunning, walletrunning, minerrunning
def isrunning(jobqueue, resultsqueue):
"""Check if bitmonerod daemon is running and return values to kivy"""
print "Starting checkdaemon thread on: {0}".format(platform)
kivysignal = True
while kivysignal:
try:
daemonrunning, walletrunning, minerrunning = runningcheck()
if daemonrunning:
daemoncheckerlabeltext = "[color=00ff00]It appears the bitmonerod daemon is running.[/color]"
else:
daemoncheckerlabeltext = "[color=ff0000]Click the [b]Start network daemon[/b] button to load bitmonerod.[/color]"
if walletrunning:
walletcheckerlabeltext = "[color=00ff00]It appears the simplewallet daemon is running.[/color]"
else:
walletcheckerlabeltext = "[color=00ff00]Click the [b]Initialize wallet file[/b] button to load simplewallet.[/color]"
resultsqueue.put((daemonrunning, daemoncheckerlabeltext, walletrunning,
walletcheckerlabeltext, minerrunning))
except:
pass
time.sleep(0.1)
kivysignal = jobqueue.get(kivysignal)
-22
View File
@@ -1,22 +0,0 @@
import os
import time
def namecheck(jobqueue, resultsqueue):
kivysignal = True
while kivysignal:
try:
walletname, kivysignal = jobqueue.get()
# print walletname
if walletname == "No filename":
message = "Please input a wallet file name..."
isname = None
elif os.path.isfile(walletname):
message = "Wallet file {0} exists in local directory.\nPlease press [b]Initialize wallet file[/b] to [color=00ff00]load wallet file[/color].".format(walletname)
isname = True
if not os.path.isfile(walletname):
message = "Wallet file {0} does not exist in your local directory.\nPlease press [b]Initialize wallet file[/b] to [color=00ff00]generate new wallet file[/color].".format(walletname)
isname = False
resultsqueue.put((isname, message))
except:
pass
time.sleep(0.1)
-26
View File
@@ -1,26 +0,0 @@
import requests
import json
import time
serverURL = 'http://localhost:18081/save_bc'
headers = {'content-type': 'application/json'}
# payload = json.dumps({
# "jsonrpc": "2.0",
# "id": "test",
# "method": "save_bc"
# })
def save_bc():
#resp = requests.get(serverURL, headers=headers, data=payload)
resp = requests.get(serverURL)
# try:
# output = json.loads(resp.text)
# print output
# except:
# print "Waiting for bitmonerod client to sync with network..."
# output = "Waiting for bitmonerod client to sync with network..."
print resp.text
+5 -4
View File
@@ -14,12 +14,13 @@ payload = json.dumps({
def storeWallet():
resp = requests.get(serverURL, headers=headers, data=payload)
try:
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
# print output
except:
# print "Waiting for bitmonerod client to sync with network..."
output = "Waiting for bitmonerod client to sync with network..."
print(output)
return output
# print output
if __name__ == "__main__":
storeWallet()
-62
View File
@@ -1,62 +0,0 @@
import os
import time
import subprocess
from sys import platform
def simplewalletloader(walletname, walletpw, isname):
"""Function to create and/or open wallet in simplewallet rpc mode"""
# Launch simplewallet in rpc mode if wallet file exists
if isname == True:
# os.remove(walletname)
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
if platform == 'win32':
subprocess.Popen(
"start simplewallet.exe --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0\r\nnpause".format(
walletname, walletpw), shell=True)
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
subprocess.Popen(
'xterm -bg black -hold -e "./simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091"'.format(
walletname, walletpw))
# Generate and then launch if wallet file doesn't exist
elif isname == False:
print "Generating wallet file " + walletname
if platform == 'win32':
walletgen = subprocess.Popen(
"simplewallet.exe --generate-new-wallet {0} --password {1} --set_log 0".format(
walletname, walletpw), shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
walletgen = subprocess.Popen(
"./simplewallet --generate-new-wallet {0} --password {1} --set_log 0".format(
walletname, walletpw), shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print "Wallet gen'ed"
time.sleep(5)
#print walletgen.stdout.read()
#print walletgen.communicate('exit')
walletgen.terminate()
if platform == 'win32':
os.system("taskkill /im simplewallet.exe /f")
elif platform == 'linux' or platform == 'linux2' or platform == 'darwin':
p = subprocess.Popen("pgrep simplewallet", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output, errors = p.communicate()
output = output.split('\n')
for i in output:
os.system("kill -9 {0}".format(i))
# Launch simplewallet in rpc mode now that wallet file exists
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
if platform == 'win32':
subprocess.Popen(
"start simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0\r\nnpause".format(
walletname, walletpw), shell=True)
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
subprocess.Popen(
'xterm -bg black -hold -e "./simplewallet --wallet-file {0} --password {1} --rpc-bind-port 19091 --set_log 0"'.format(
walletname, walletpw), shell=True)
elif isname == None:
pass
+5 -5
View File
@@ -7,11 +7,11 @@ serverURL = 'http://localhost:19091/json_rpc'
def transferfundsrpccall(amount, address, mixin, paymentid):
"""function to transfer funds to a single address"""
atomicamount = c_uint64(int((float(amount)*1e12)-1e6))
atomicamount = c_uint64(int((float(amount)*1e12)))
address = str(address)
mixin = int(mixin)
paymentid = str(paymentid)
mro_fee = c_uint64(int(1e11))
mro_fee = c_uint64(int(1e10))
if len(paymentid) > 1:
payload = json.dumps({
"jsonrpc":"2.0",
@@ -53,11 +53,11 @@ def transferfundsrpccall(amount, address, mixin, paymentid):
output = json.loads(resp.text)
print output
txid = output[u'result'][u'tx_hash']
return txid
return True, txid
except:
print "transfer error :0 !!!"
return "error"
error = output[u'error'][u'message']
return False, error
if __name__ == "__main__":
+203 -35
View File
@@ -3,7 +3,9 @@
<RootWidget>:
id: rootwidget
# Tx history tab id items
tx_list: tx_list
# tx_list: tx_list
# tx_scroller: tx_scroller
# scroll_box: scroll_box
# Transfer tab id items
address_input_textinput: address_input_textinput
amount_input_textinput: amount_input_textinput
@@ -16,6 +18,7 @@
unlocked_balance_label: unlocked_balance_label
total_balance_label: total_balance_label
calculated_balance_label: calculated_balance_label
wallet_savetime_label: wallet_savetime_label
# Bitmonerod daemon tab id items
daemon_server_textinput: daemon_server_textinput
blockheight_label: blockheight_label
@@ -24,58 +27,118 @@
time_since_last_label: time_since_last_label
AccordionItem:
id: tx_accordion
title: "Transaction history"
BoxLayout:
padding: 30, 30, 30, 30
orientation: "vertical"
Label:
text: "Transaction history list (scrollable)"
size_hint_y: 0.1
ScrollView:
size_hint: None, None
id: tx_scroller
size_hint: 1, 1
GridLayout:
cols: 1
spacing: 7
# size_hint_y: None
size_hint_y: None
id: tx_list
AccordionItem:
title: "Send XMR"
BoxLayout:
padding: 30, 30, 30, 30
padding: 20, 30, 20, 30
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Send to address:"
size_hint_x: 0.2
text: "Send to\naddress:"
size_hint_x: 0.15
TextInput:
id: address_input_textinput
size_hint_x: 2
font_size: 10
size_hint_x: 0.85
font_size: 9
multiline: False
Label:
text: "Amount MRO:"
size_hint_x: 0.2
size_hint_y: 0.05
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Amount XMR:"
size_hint_x: 0.4
TextInput:
id: amount_input_textinput
size_hint_x: 0.8
font_size: 10
size_hint_x: 0.6
font_size: 20
multiline: False
Label:
text: "Mixin amount:\n(Please use 0 or >= 3)"
size_hint_x: 0.2
size_hint_y: 0.05
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Mixin amount:\n(Please use 0 or >= 2)"
size_hint_x: 0.4
TextInput:
id: mixin_input_textinput
size_hint_x: 0.8
font_size: 10
size_hint_x: 0.6
font_size: 20
multiline: False
# Slider:
# min: 0
# max: 10
# value: 1
Label:
text: "Payment ID:"
size_hint_y: 0.05
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Payment ID\n(Needed to send\nto exchanges!):"
size_hint_x: 0.2
TextInput:
id: paymentid_input_textinput
size_hint_x: 1
font_size: 10
size_hint_x: 0.8
font_size: 9
text: ""
multiline: False
Label:
size_hint_y: 0.05
Button:
size_hint: 1, 0.15
halign: "center"
text: "Transfer funds"
on_press: root.transferfunds()
# on_press: root.storeformdata()
font_size: 20
Label:
size_hint_y: 0.05
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.15
MarkupLabel:
size_hint_x: 0.7
halign: "center"
text: "Please donate XMR to Cool Mining Club\nfor generously running a bitmonerod open node."
Button:
size_hint_x: 0.3
halign: "center"
text: "Click to\ndonate XMR to\nCool Mining Club"
on_press: root.donate_CMC()
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.15
MarkupLabel:
size_hint_x: 0.7
halign: "center"
text: "Please donate XMR to Monero core developers\nfor generously donating their time and effort."
Button:
size_hint_x: 0.3
halign: "center"
text: "Click to\ndonate XMR to\ncore Monero devs"
on_press: root.donate_core()
AccordionItem:
title: "Simplewallet account"
@@ -84,12 +147,14 @@
padding: 30, 30, 30, 30
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Account name: "
MarkupLabel:
id: wallet_account_label
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
size_hint_x: 0.15
text: "Address: "
@@ -100,28 +165,46 @@
on_ref_press: root.selectAddress()
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Blocks synced: "
MarkupLabel:
id: wallet_block_label
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Unlocked balance: "
MarkupLabel:
id: unlocked_balance_label
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Total balance: "
MarkupLabel:
id: total_balance_label
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
text: "Calculated balance: "
MarkupLabel:
id: calculated_balance_label
Label:
size_hint_y: 0.1
text: "*If you can see a number for the Unlocked and Total balances, then it should be OK to transfer XMR.\nSometimes the Blocks synced lags a bit, but if you see your Unlocked and Total balances, transfers should work."
font_size: 10
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.25
Button:
text: "Save wallet\n(Attempts to autosave\nafter every minute)"
halign: "center"
on_press: root.saveWallet(0.1)
MarkupLabel:
id: wallet_savetime_label
text: "Wallet last saved @"
AccordionItem:
title: "Bitmonerod daemon"
@@ -137,18 +220,23 @@
Label:
size_hint_y: 0.1
Label:
text: "Daemon ip address (default is coolmining club)"
size_hint_y: 0.05
text: "Daemon ip address (default is Coolmining Club)\nto use a local instance enter http://localhost:18081\nin CONFIG.file in local directory."
size_hint_y: 0.1
BoxLayout:
size_hint_y: 0.15
orientation: 'horizontal'
TextInput:
size_hint_x: 0.7
padding: 0, 8, 0, 0
MarkupLabel:
size_hint_x: 0.6
color: 0, 1, 0
id: daemon_server_textinput
text: "http://xmr1.coolmining.club:5012"
# text: "http://xmr1.coolmining.club:5012"
# text: "http://localhost:18081"
Button:
text: "Click to change\ndaemon address"
text: "Change daemon\naddress in\nCONFIG.file"
halign: "center"
size_hint_x: 0.4
# on_press: root.resetDaemon()
Label:
size_hint_y: 0.1
BoxLayout:
@@ -184,22 +272,27 @@
<InitialPopup>:
id: initial_popup
title: "Initial Setup Window"
size_hint: 0.75, 0.75
auto_dismiss: "False"
BoxLayout:
orientation: 'vertical'
Label:
text: "It appears that this is your first time loading CryptoNote Kivy GUI\n(or you have deleted your CONFIG.file file).\nPlease select if you would like to create a new wallet, load an existing wallet, or exit the program"
halign: "center"
text: "It appears that this is your first time loading CryptoNote Kivy GUI\n(or you have deleted your CONFIG.file file).\n\nPlease select if you would like to create a new wallet,\nload an existing wallet, or exit the program."
BoxLayout:
orientation: 'horizontal'
padding: 30, 20, 30, 20
Button:
halign: "center"
text: "Create\nNew\nWallet"
on_press: root.createWalletPopup()
Button:
halign: "center"
text: "Load\nExisting\nWallet"
on_press: root.loadWalletPopup()
Button:
text: "Exit KivyWallet"
halign: "center"
text: "Exit\nlightWallet"
on_press: root.quit()
@@ -207,6 +300,7 @@
id: create_wallet_popup
title: "Create Wallet Window"
auto_dismiss: "False"
size_hint: 0.75, 0.75
wallet_name: wallet_name
wallet_pw: wallet_pw
repeat_wallet_pw: repeat_wallet_pw
@@ -238,56 +332,74 @@
<LoadWalletPopup>:
id: load_wallet_popup
title: "Load Wallet Window"
auto_dismiss: "False"
size_hint: 0.75, 0.75
auto_dismiss: False
wallet_path: wallet_path
wallet_pw: wallet_pw
repeat_wallet_pw: repeat_wallet_pw
BoxLayout:
padding: 60, 60, 60, 60
padding: 60, 30, 60, 30
orientation: 'vertical'
MarkupLabel:
text: "Enter wallet keys path (make sure you include file extension)\nExample - [b][color=00ffff]C:\\Users\\Satoshi\\SecretStuff\\Wallets\\Monero\\wallet.bin.keys[/b][/color]:"
size_hint_y: 0.3
halign: "center"
text: "Enter wallet keys path (make sure you include file extension)\nNote: this will copy your keys file to a local subdirectory;\nit will not use your original wallet file(s).\nExample - [b][color=00ffff]C:\\Users\\Satoshi\\SecretStuff\\Wallets\\Monero\\wallet.bin.keys[/b][/color]:"
TabTextInput:
size_hint_y: 0.1
id: wallet_path
next: wallet_pw
Label:
size_hint_y: 0.1
text: "Enter wallet password:"
TabTextInput:
size_hint_y: 0.1
id: wallet_pw
password: True
next: repeat_wallet_pw
Label:
size_hint_y: 0.1
text: "Repeat wallet password:"
TabTextInput:
size_hint_y: 0.1
id: repeat_wallet_pw
password: True
next: wallet_path
Label:
size_hint_y: 0.1
text: "Note - this wallet will be set as your default wallet"
Button:
size_hint_y: 0.15
text: "Click to load wallet"
on_press: root.loadWallet()
<PasswordPopup>
title: "Password entry popup"
size_hint: 0.75, 0.75
auto_dismiss: False
walletname_label: walletname_label
wallet_pw: wallet_pw
BoxLayout:
orientation: "vertical"
padding: 20, 20, 20, 20
Label:
size_hint: 1, 0.2
id: walletname_label
TabTextInput:
size_hint: 1, 0.1
id: wallet_pw
password: True
Label:
size_hint: 1, 0.2
Button:
text: "Click to launch wallet"
on_press: root.launchWallet()
size_hint: 1, 0.5
<TransferPopup>
transfer_popup_label: transfer_popup_label
size_hint: 0.75, 0.75
size_hint: 0.9, 0.9
auto_dismiss: False
title: "Transfer Popup"
BoxLayout:
@@ -310,13 +422,29 @@
<TxIDPopup>
title: "Tx ID Popup"
address_popup_label: address_popup_label
paymentid_popup_label: paymentid_popup_label
txid_popup_label: txid_popup_label
size_hint: 0.9, 0.9
BoxLayout:
orientation: 'vertical'
Label:
font_size: 11
markup: True
id: txid_label
padding: 30, 30, 30, 30
MarkupLabel:
halign: "center"
font_size: 9
id: address_popup_label
text: ""
on_ref_press: root.selectaddress()
MarkupLabel:
halign: "center"
font_size: 9
id: paymentid_popup_label
text: ""
on_ref_press: root.selectpaymentid()
MarkupLabel:
halign: "center"
font_size: 9
id: txid_popup_label
text: ""
on_ref_press: root.selecttxid()
Button:
@@ -324,6 +452,46 @@
on_press: root.dismiss()
<DonateCMC>
title: "Donate to Cool Mining Club"
size_hint: 0.75, 0.75
donation_amount_CMC: donation_amount_CMC
BoxLayout:
padding: 30, 30, 30, 30
orientation: 'vertical'
Label:
text: "Enter amount of XMR to donate:"
TextInput:
id: donation_amount_CMC
BoxLayout:
Button:
text: "Donate!"
on_press: root.make_donation()
Button:
text: "Cancel :("
on_press: root.dismiss()
<DonateCore>
title: "Donate to Monero core devs"
size_hint: 0.75, 0.75
donation_amount_core: donation_amount_core
BoxLayout:
padding: 30, 30, 30, 30
orientation: 'vertical'
Label:
text: "Enter amount of XMR to donate:"
TextInput:
id: donation_amount_core
BoxLayout:
Button:
text: "Donate!"
on_press: root.make_donation()
Button:
text: "Cancel :("
on_press: root.dismiss()
<MarkupLabel>
markup: True
+518 -160
View File
@@ -1,9 +1,10 @@
# !/usr/bin/python
from platform import system
from kivy.app import App
from kivy.config import Config
from kivy.uix.accordion import Accordion
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.properties import ObjectProperty
from kivy.core.clipboard import Clipboard
@@ -16,19 +17,51 @@ import os
import sys
import argparse
import time
import datetime
import re
import random
import shutil
import signal
from subprocess import PIPE, Popen, STDOUT
from threading import Thread
from Queue import Queue, Empty
import shutil
from lib.checklastblock import CheckLastBlock
from lib.savewallet import storeWallet
from lib.transferfunds import transferfundsrpccall
from lib.checkbalance import CheckBalanceSimplewallet
# sys.stdout = sys.stderr
# class flushfile(object):
# def __init__(self, f):
# self.f = f
#
# def write(self, x):
# self.f.write(x)
# self.f.flush()
#
# sys.stdout = flushfile(sys.stdout)
# Set unbuffered output
# msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
# Set POSIX argument for linux for something...
ON_POSIX = 'posix' in sys.builtin_module_names
# Donation wallet addy
donate_CMC_address = "4ATxc8rJjG62ToWqCibuPv7kY9ikds3b3JmRHYqAAymEdhwBGfhtwRgMuHF9bsn18f4wXrK93cw6xdsVCJJwizkiHeUuJKB"
donate_core_address = "46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em"
# URLs for servers
cool_mining_URL = "http://xmr1.coolmining.club:5012"
localhost_URL = "http://localhost:18081"
# parser gets command line args
parser = argparse.ArgumentParser()
@@ -44,22 +77,33 @@ def enqueue_output(out, queue):
def read_output(process, stdout, queue):
while True:
last_queue_read = time.time()
# out666 = stdout.readline(1)
out = stdout.readline()
#print("Process is: "+process.poll())
if out == '' and process.poll() != None:
break
# print(out)
# if len(out) < 2:
# out = stdout.readline(1)
# print("other out "+out)
# if out == '' and process.poll() != None:
if out == '':
print("passing last loop run @ {0}".format(last_queue_read))
# print("breaking last loop run @ {0}".format(last_queue_read))
# break
pass
if out != '':
print("queueing last loop run @ {0}".format(last_queue_read))
line = out.rstrip()
queue.put_nowait(line)
sys.stdout.flush()
# sys.stdout.flush()
# Function to split tx output lines
def txSplit(line):
split_line = line.split(': ')
def tx_split(line):
split_line = line.rstrip().split(': ')
try:
amount = float(split_line[1].split(',')[0])
tx = split_line[2].strip('<>')
tx = split_line[2].strip('<').strip('>')
date = split_line[0].split('.')[0]
return amount, tx, date
except ValueError:
@@ -68,6 +112,30 @@ def txSplit(line):
return "Error", "Error", "Error"
# Check if a string is hex only
def hex_match(strg, search=re.compile(r'[^a-fA-F0-9]').search):
return not bool(search(strg))
# Generate random hex strings for payment id
def gen_paymentid():
return ''.join([random.choice('0123456789ABCDEF') for x in range(64)])
# Function to kill shit on windows
def windows_task_killer(pid):
try:
os.system("taskkill /F /T /PID {0}".format(pid))
print("Simplewallet process killed with PID {0} killed".format(pid))
except:
print("This {0} simplewallet instance isn't running".format(pid))
try:
os.system("tskill {0}".format(pid))
print("Simplewallet process killed with PID {0} killed".format(pid))
except:
print("This {0} simplewallet instance isn't running or no tskill".format(pid))
class MarkupLabel(Label):
""" Label class with markup on by default """
pass
@@ -75,7 +143,6 @@ class MarkupLabel(Label):
class TabTextInput(TextInput):
""" Tab or enter to next TextInput class """
def __init__(self, *args, **kwargs):
self.next = kwargs.pop('next', None)
super(TabTextInput, self).__init__(*args, **kwargs)
@@ -94,7 +161,6 @@ class TabTextInput(TextInput):
class InitialPopup(Popup):
""" Initial popup widget """
def loadWalletPopup(self):
self.dismiss()
lwp = LoadWalletPopup()
@@ -116,37 +182,56 @@ class CreateWalletPopup(Popup):
repeat_wallet_pw = ObjectProperty()
def createWallet(self):
electrum_coming = False
electrum_coming, electrum_1, electrum_2, electrum_3, electrum_4 = None, None, None, None, None
wallet_name = self.wallet_name.text
wallet_pw = self.wallet_pw.text
if self.wallet_pw.text == self.repeat_wallet_pw.text:
p = Popen(["simplewallet", "--generate-new-wallet",
"./" + wallet_name.replace('.', '') + "_walletData/" + wallet_name,
"--password", wallet_pw],
stdout=PIPE,
stdin=PIPE,
bufsize=1,
close_fds=ON_POSIX)
if not os.path.exists('./{0}_walletData'.format(wallet_name.replace('.', ''))):
os.mkdir('./{0}_walletData'.format(wallet_name.replace('.', '')))
else:
sys.exit(7777)
p = Popen(["simplewallet", "--generate-new-wallet",
"./" + wallet_name.replace('.', '') + "_walletData/" + wallet_name,
"--password", wallet_pw, "--set_log", "0"],
stdout=PIPE,
stdin=PIPE,
bufsize=1,
close_fds=ON_POSIX)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True # thread dies with the program
p.stdin.write("0\r\n")
p.stdin.flush()
t.start()
t_start = time.time()
while time.time() - t_start < 2:
try:
line = q.get_nowait() # or q.get(timeout=.1)
if "new wallet:" in line:
address = line.rstrip().split(': ')[1]
address = line.rstrip().split(': ')[2]
if "view key:" in line:
view_key = line.rstrip().split(': ')[1]
if electrum_3:
electrum_line_4 = line.rstrip()
electrum_3 = False
print(line.rstrip())
if electrum_2:
electrum_line_3 = line.rstrip()
electrum_3 = True
electrum_2 = False
print(line.rstrip())
if electrum_1:
electrum_line_2 = line.rstrip()
electrum_2 = True
electrum_1 = False
print(line.rstrip())
if electrum_coming:
electrum_1 = True
electrum_coming = False
print(line.rstrip())
if 130 < len(line.rstrip()) < 350:
electrum = line.rstrip()
if "PLEASE NOTE:" in line:
electrum_coming = line.rstrip()
electrum_coming = True
print(line.rstrip())
print("simplewallet output:", line.rstrip())
except Empty:
# print('no output yet')
@@ -155,23 +240,32 @@ class CreateWalletPopup(Popup):
# print(line)
pass
# time.sleep(0.1)
if sys.platform == 'win32':
try:
p.kill()
# os.system("taskkill /im simplewallet.exe /f")
# print(p.pid)
print("Simplewallet process killed")
except:
print("Wallet process not running")
windows_task_killer(p.pid)
with open('./{0}_walletData/info.txt'.format(wallet_name.replace('.', '')), 'w') as f:
f.write("Name:\n{0}\n\nAddress:\n{1}\n\nView key:\n{2}\n\nElectrum seed:\n{3}".format(
wallet_name, address, view_key, electrum))
wallet_name, address, view_key, electrum_line_2+' '+electrum_line_3+' '+electrum_line_4))
with open("./CONFIG.file", 'w') as f:
f.write(wallet_name)
f.write("Account name= " + wallet_name + "\n")
f.write("Bitmonerod daemon server= {0}".format(cool_mining_URL))
self.dismiss()
content = Button(
text="Your wallet has been created in the local directory {0}_walletData\nThe info.txt document in that folder contains your wallet recovery seed.\nPlease keep this seed safe, you can restore a corrupted/lost wallet with it.\nSomeone else can also bypass your password and steal your XMR with it.\nI suggest deleting or encrypting this file.".format(
wallet_name))
walletCreatedPopup = Popup(title="Wallet created window",
content=content)
walletCreatedPopup = Popup(title="Wallet created window", content=content, size_hint=(0.75, 0.75))
content.bind(on_press=walletCreatedPopup.dismiss)
walletCreatedPopup.open()
App.get_running_app().root.daemon_thread = Thread(target=App.get_running_app().root.checkDaemonStatus,
args=(App.get_running_app().root.daemon_queue, cool_mining_URL))
App.get_running_app().root.daemon_thread.daemon = True
App.get_running_app().root.daemon_thread.start()
App.get_running_app().root.launchWallet(wallet_name, wallet_pw)
App.get_running_app().root.daemon_server_textinput.text = cool_mining_URL
else:
content = Button(text="Check passwords!!!\nClick to dismiss")
pwErrorPopup = Popup(title="Password match error window",
@@ -191,11 +285,13 @@ class LoadWalletPopup(Popup):
wallet_name = '.'.join(tuple(split_name[0:len(split_name) - 1]))
print(split_name, wallet_name)
wallet_pw = self.wallet_pw.text
wallet_error = False
wallet_error = True
if self.wallet_pw.text == self.repeat_wallet_pw.text:
p = Popen(["simplewallet", "--wallet-file",
self.wallet_path.text,
"--password", wallet_pw],
if not os.path.exists('./{0}_walletData'.format(wallet_name.replace('.', ''))):
os.mkdir('./{0}_walletData'.format(wallet_name.replace('.', '')))
else:
sys.exit(7777)
p = Popen(["simplewallet", "--wallet-file", self.wallet_path.text, "--password", wallet_pw],
stdout=PIPE,
stdin=PIPE,
bufsize=1,
@@ -218,12 +314,20 @@ class LoadWalletPopup(Popup):
pass
else: # got line
pass
if sys.platform == 'win32':
try:
p.kill()
print("Simplewallet process killed")
except:
print("Wallet process not running")
windows_task_killer(p.pid)
wallet_error = False
if not wallet_error:
if not os.path.exists("./{0}_walletData".format(wallet_name.replace('.', ''))):
os.mkdir("./{0}_walletData".format(wallet_name.replace('.', '')))
with open("./CONFIG.file", 'w') as f:
f.write(wallet_name)
f.write("Account name= " + wallet_name + "\n")
f.write("Bitmonerod daemon server= {0}".format(cool_mining_URL))
with open("./{0}_walletData/{1}.address.txt".format(wallet_name.replace('.', ''), wallet_name), 'w') as f:
f.write(address)
shutil.copyfile(self.wallet_path.text,
@@ -232,15 +336,18 @@ class LoadWalletPopup(Popup):
content = Button(
text="Your wallet keys file has been copied to the local directory {0}_walletData\nThe original has not been disturbed.".format(
wallet_name))
walletCopiedPopup = Popup(title="Wallet keys copied window",
content=content)
walletCopiedPopup = Popup(title="Wallet keys copied window", content=content, size_hint=(0.75, 0.75))
content.bind(on_press=walletCopiedPopup.dismiss)
App.get_running_app().root.daemon_server_textinput.text = cool_mining_URL
walletCopiedPopup.open()
App.get_running_app().root.daemon_thread = Thread(target=App.get_running_app().root.checkDaemonStatus,
args=(App.get_running_app().root.daemon_queue, cool_mining_URL))
App.get_running_app().root.daemon_thread.daemon = True
App.get_running_app().root.daemon_thread.start()
App.get_running_app().root.launchWallet(wallet_name, wallet_pw)
else:
content = Button(text="Wallet import error!\nClick to start over")
pwErrorPopup = Popup(title="Wallet import error window",
content=content)
pwErrorPopup = Popup(title="Wallet import error window", content=content, size_hint=(0.75, 0.75))
content.bind(on_press=pwErrorPopup.dismiss)
ip = InitialPopup()
content.bind(on_press=ip.open)
@@ -256,10 +363,14 @@ class PasswordPopup(Popup):
super(PasswordPopup, self).__init__()
self.wallet_name = wallet_name
if not App.get_running_app().root.wallet_error:
if not App.get_running_app().root.incorrect_password:
self.walletname_label.text = "Please enter your password for {0} account:".format(self.wallet_name)
if App.get_running_app().root.wallet_error:
self.walletname_label.text = "There seems to be a problem with binary file,\nPlease enter your password to attempt rebuild of {0} account:".format(
self.wallet_name)
if App.get_running_app().root.incorrect_password:
self.walletname_label.text = "It seems you've entered an incorrect password,\nPlease re-enter your password to open {0} account:".format(
self.wallet_name)
def launchWallet(self):
wallet_pw = self.wallet_pw.text
@@ -277,30 +388,68 @@ class TransferPopup(Popup):
self.address = address
self.mixin = mixin
self.paymentid = paymentid
self.popuptext = "Are you sure you want to send {0:0.9f} XMR\n to [size=8]{1}[/size]\n with mixin count {2} and payment id [size=8]{3}[/size]".format(
self.popuptext = "Are you sure you want to send {0:0.4f} XMR\n to [size=9]{1}[/size]\n with mixin count {2} and payment id [size=9]{3}[/size]\n\nAn additional fee of 0.01-0.2 XMR will be required.".format(
float(amount), address, mixin, paymentid)
self.transfer_popup_label.text = self.popuptext
def transfer(self):
txid = transferfundsrpccall(self.amount, self.address, self.mixin, self.paymentid)
txid_popup = TxIDPopup(txid)
return_boolean, return_value = transferfundsrpccall(self.amount, self.address, self.mixin, self.paymentid)
txid_popup = TxIDPopup(return_boolean, return_value, self.amount, self.address, self.mixin, self.paymentid)
txid_popup.open()
class TxIDPopup(Popup):
txid_label = ObjectProperty()
def __init__(self, txid):
address_popup_label = ObjectProperty()
paymentid_popup_label = ObjectProperty()
txid_popup_label = ObjectProperty()
def __init__(self, return_boolean, return_value, amount, address, mixin, paymentid):
super(TxIDPopup, self).__init__()
self.txid = txid
self.txid_label.text = "TxID: [ref=txid]{0}[/ref]\n(Click TxID to copy to clipboard)".format(txid)
if return_boolean:
self.address_popup_label.text = "Successfully sent {0:.3f} XMR\nto [ref=address]{1}[/ref]\n(Click address to copy to clipboard)".format(amount, address)
self.paymentid_popup_label.text = "Using mixin count {0}\nand payment id: [ref=paymentid]{1}[/ref]\n(Click payment id to copy to clipboard)".format(mixin, paymentid)
self.txid_popup_label.text = "TxID: [ref=txid]{0}[/ref]\n(Click TxID to copy to clipboard)".format(return_value)
self.txid = return_value
self.address = address
self.paymentid = paymentid
else:
self.txid_popup_label.text = "Transaction error! Error message:\n{0}\nPlease try again by (and maybe lower mixin or amount sent).".format(return_value)
def selectaddress(self):
Clipboard.put(self.address)
def selectpaymentid(self):
Clipboard.put(self.paymentid)
def selecttxid(self):
Clipboard.put(self.txid)
class DonateCMC(Popup):
donation_amount_CMC = ObjectProperty()
def __init__(self):
super(DonateCMC, self).__init__()
def make_donation(self):
App.get_running_app().root.transferfunds(donate_CMC_address, 0., self.donation_amount_CMC.text, gen_paymentid())
self.dismiss()
class DonateCore(Popup):
donation_amount_core = ObjectProperty()
def __init__(self):
super(DonateCore, self).__init__()
def make_donation(self):
App.get_running_app().root.transferfunds(donate_core_address, 0., self.donation_amount_core.text, gen_paymentid())
self.dismiss()
class RootWidget(Accordion):
"""Root Kivy accordion widget class"""
wallet_error = None
incorrect_password = False
# Tx list items
# tx_layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
# Transfer XMR id items
address_input_textinput = ObjectProperty()
amount_input_textinput = ObjectProperty()
@@ -312,6 +461,7 @@ class RootWidget(Accordion):
unlocked_balance_label = ObjectProperty()
total_balance_label = ObjectProperty()
calculated_balance_label = ObjectProperty()
wallet_savetime_label = ObjectProperty()
# Daemon id items
daemon_server_textinput = ObjectProperty()
blockheight_label = ObjectProperty()
@@ -323,10 +473,15 @@ class RootWidget(Accordion):
# Process, queue, and thread variables
daemon_queue = Queue()
daemon_thread = None
balance_queue = Queue()
balance_thread = None
wallet_process = None
wallet_queue = Queue()
wallet_thread = None
save_thread = None
save_queue = Queue()
# Other variables
wallet_height = None
calculated_balance = 0.0
total_balance = 0.0
unlocked_balance = 0.0
@@ -334,22 +489,33 @@ class RootWidget(Accordion):
temp_tx_hash = ""
temp_tx_paymentid = ""
wallet_save_time = None
donate_CMC_input_amount = ObjectProperty()
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.daemon_server_textinput.text = cool_mining_URL
if os.path.isfile('./CONFIG.file'):
with open('./CONFIG.file', 'r') as f:
lines = f.readlines()
try:
self.wallet_name = lines[0].rstrip().split('=')[1].lstrip()
self.daemon_server_textinput.text = lines[1].rstrip().split('=')[1].lstrip()
self.daemon_thread = Thread(target=self.checkDaemonStatus,
args=(self.daemon_queue, self.daemon_server_textinput.text))
self.daemon_thread.daemon = True
self.daemon_thread.start()
if os.path.isfile('./CONFIG.file'):
with open('./CONFIG.file', 'r') as f:
self.wallet_name = f.read().rstrip()
print(self.wallet_name)
Clock.schedule_once(self.initialPassword, 0.5)
except:
Clock.schedule_once(self.initialConfig, 0.5)
else:
Clock.schedule_once(self.initialConfig, 0.5)
Clock.schedule_interval(self.checkDaemon, 5)
Clock.schedule_interval(self.checkDaemon, 2)
self.balance_thread = Thread(target=self.checkBalanceStatus, args=(self.balance_queue,))
self.balance_thread.daemon = True
self.balance_thread.start()
Clock.schedule_interval(self.checkBalance, 2)
Clock.schedule_interval(self.saveWallet, 60)
self.ids.tx_list.bind(minimum_height=self.ids.tx_list.setter('height'))
def initialConfig(self, dt):
ip = InitialPopup()
@@ -360,15 +526,17 @@ class RootWidget(Accordion):
gp.open()
def checkDaemonStatus(self, daemon_queue, server):
"""Class to be threaded for checking bitmonerod status"""
"""Method to be threaded for checking bitmonerod status"""
while True:
# print(server)
height, reward, timesince, localtime = CheckLastBlock(server + "/json_rpc")
daemon_queue.put((height, reward, timesince, localtime))
# print("sleeping")
time.sleep(1)
self.checkDaemonStatus(daemon_queue, self.daemon_server_textinput.text)
#self.checkDaemonStatus(daemon_queue, self.daemon_server_textinput.text)
def checkDaemon(self, dt):
"""RPC call to check bitmonerod for blockchain info"""
try:
height, reward, timesince, localtime = self.daemon_queue.get_nowait()
self.blockheight = int(height)
@@ -376,137 +544,231 @@ class RootWidget(Accordion):
self.last_reward_label.text = "[b][color=00ffff]{0:.2f}[/b][/color] XMR".format(reward * 1e-12)
self.last_block_time_label.text = "[b][color=00ffff]{0}[/b][/color]".format(localtime)
self.time_since_last_label.text = "[b][color=00ffff]{0:.0f}[/b][/color] seconds".format(timesince)
self.wallet_block_label.text = "[b][color=00ffff]{0}[/b][/color] of [b][color=00ffff]{1}[/b][/color]".format(
self.wallet_height, self.blockheight)
except:
pass
self.blockheight_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No daemon connection")
self.last_reward_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No daemon connection")
self.last_block_time_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No daemon connection")
self.time_since_last_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No daemon connection")
self.wallet_block_label.text = "[b][color=ff0000]{0}[/b][/color] of [b][color=ff0000]{1}[/b][/color]".format(
self.wallet_height, "No daemon connection")
def checkBalanceStatus(self, balance_queue):
"""Method to be threaded for checking balance status"""
while True:
balance, unlocked_balance = CheckBalanceSimplewallet()
# print("Putting {0} and {1} in queue". format(balance, unlocked_balance))
balance_queue.put((balance, unlocked_balance))
time.sleep(1)
#self.checkDaemonStatus(daemon_queue, self.daemon_server_textinput.text)
def checkBalance(self, dt):
"""RPC call to check bitmonerod for blockchain info"""
# print("checking queue")
try:
balance, unlocked_balance = self.balance_queue.get_nowait()
# print("Got from queue: {0} and {1}".format(balance, unlocked_balance))
try:
self.total_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(float(balance))
self.unlocked_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(float(unlocked_balance))
self.unlocked_balance, self.total_balance = float(unlocked_balance), float(balance)
# self.total_balance_label.text = "[b][color=00ffff]{0}[/b][/color]".format(balance)
# self.unlocked_balance_label.text = "[b][color=00ffff]{0}[/b][/color] XMR".format(unlocked_balance)
except ValueError:
# print("value error")
self.total_balance_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No wallet connection or syncing")
self.unlocked_balance_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No wallet connection or syncing")
except Empty:
# print("empty")
self.total_balance_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No wallet connection or syncing")
self.unlocked_balance_label.text = "[b][color=ff0000]{0}[/b][/color]".format("No wallet connection or syncing")
# def resetDaemon(self):
# print("resetting")
# save_thread = Thread(target=storeWallet)
# save_thread.daemon = True
# save_thread.start()
# save_thread.join()
# self.wallet_process.kill()
# if sys.platform == 'win32':
# try:
# os.system("taskkill /im simplewallet.exe /f")
# except:
# print("Simplewallet.exe not running")
# self.daemon_thread.join(0.5)
# self.daemon_thread = Thread(target=self.checkDaemonStatus,
# args=(self.daemon_queue, self.daemon_server_textinput.text))
# self.daemon_thread.daemon = True
# self.daemon_thread.start()
# self.wallet_process = Popen(["simplewallet", "--wallet-file", "./{0}_walletData/{1}.keys".format(
# self.wallet_name.replace('.', ''), self.wallet_name), "--password", self.wallet_pw,
# "--daemon-address", self.daemon_server_textinput.text, "--rpc-bind-port", "19091"],
# # stdin=PIPE,
# stdout=PIPE,
# stderr=STDOUT,
# bufsize=1,
# shell=True)
# self.wallet_thread = Thread(target=enqueue_output,
# args=(self.wallet_process.stdout, self.wallet_queue))
# print("finished reset")
def launchWallet(self, wallet_name, wallet_pw):
with open("./{0}_walletData/{1}.address.txt".format(wallet_name.replace('.', ''), wallet_name), 'r') as f:
self.address = f.read().rstrip()
self.wallet_account_label.text = "[b][color=00ffff]{0}[/b][/color]".format(wallet_name)
self.wallet_address_label.text = "[b][color=00ffff][ref=Address]{0}[/ref][/b][/color]".format(self.address)
self.wallet_pw = wallet_pw
print("./{0}_walletData/tx.txt".format(wallet_name.replace('.', '')))
print(os.path.isdir("./{0}_walletData".format(wallet_name.replace('.', ''))))
print(os.path.isfile("./{0}_walletData/tx.txt".format(wallet_name.replace('.', ''))))
print(os.getcwd())
print(os.path.join(os.getcwd(), "{0}_walletData".format(wallet_name.replace('.', ''))))
datadir = os.path.join(os.getcwd(), "{0}_walletData".format(wallet_name.replace('.', '')))
print(os.path.join(datadir, "tx.txt"))
tx_file = os.path.join(datadir, "tx.txt")
wallet_file = os.path.join(datadir, wallet_name)
address_file = os.path.join(datadir, wallet_name+".address.txt")
if not os.path.isfile("./{0}_walletData/{1}".format(wallet_name.replace('.', ''), wallet_name)):
self.wallet_process = Popen(["simplewallet.exe", "--wallet-file", "./{0}_walletData/{1}".format(
wallet_name.replace('.', ''), wallet_name), "--password", wallet_pw],
print("binary file not found, creating...")
p = Popen(["simplewallet.exe", "--wallet-file", wallet_file, "--password", wallet_pw],
stdin=PIPE,
stdout=PIPE,
stderr=STDOUT,
bufsize=1)
self.wallet_process.communicate(input="exit\r\n")
self.wallet_process.kill()
# try:
# system("taskkill /im simplewallet.exe /f")
# except:
# print("Simplewallet.exe not running")
if os.path.isfile("./{0}_walletData/tx.txt".format(wallet_name.replace('.', ''))):
with open("./{0}_walletData/tx.txt".format(wallet_name.replace('.', ''), 'r')) as previous_txs:
q = Queue()
t = Thread(target=enqueue_output, args=(p, q))
t.daemon = True # thread dies with the program
t.start()
t_start = time.time()
while time.time() - t_start < 2:
try:
line = q.get_nowait() # or q.get(timeout=.1)
print("simplewallet output:", line.rstrip())
if "Opened wallet: " in line.rstrip():
address = line.rstrip().split(": ")[1]
if "Error: failed" in line.rstrip():
wallet_error = True
except Empty:
# print('no output yet')
pass
else: # got line
pass
try:
p.communicate(input="exit\r\n")
except:
pass
time.sleep(2)
if sys.platform == 'win32':
try:
p.kill()
print("Simplewallet process killed")
except:
print("Wallet process not running")
windows_task_killer(p.pid)
if not os.path.isfile(address_file):
with open(address_file, 'w') as f:
f.write(address)
self.address = address
if os.path.isfile(address_file):
with open(address_file, 'r') as f:
self.address = f.read().rstrip()
# Check if tx file exists and create it if not or read txs if it does
if not os.path.isfile(tx_file):
with open(tx_file, 'w+') as previous_txs:
previous_txs.write("{0}\t{1}\t{2}\t{3}\n".format("tx type", "tx time", "XMR amount", "tx hash"))
if os.path.isfile(tx_file):
with open(tx_file, 'r') as previous_txs:
txs = previous_txs.read().split('\n')
for idx, line in enumerate(txs):
this_amount, this_tx, this_date = txSplit(line)
if idx < len(txs) - 1:
next_amount, next_tx, date = txSplit(txs[idx+1])
else:
next_amount, next_tx, date = "Done", "Done", "Done"
if this_tx != next_tx and self.temp_tx_amount == 0.0:
if "Received" in line:
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
temp_line = line.split('\t')
if idx > 0 and len(temp_line) == 4:
l = Label(text="{0} {1} XMR on {2} in tx: {3}".format(
temp_line[0], temp_line[1], temp_line[2], temp_line[3]),
size_hint_y=None, height=15, font_size=9)
self.ids.tx_list.add_widget(l)
self.calculated_balance += this_amount
elif "Spent" in line:
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
size_hint_y=None, height=15, font_size=9)
self.ids.tx_list.add_widget(l)
self.calculated_balance -= this_amount
elif this_tx == next_tx and self.temp_tx_amount == 0.0:
self.temp_tx_amount += this_amount + next_amount
elif this_tx == next_tx and self.temp_tx_amount != 0.0:
self.temp_tx_amount += next_amount
elif this_tx != next_tx and self.temp_tx_amount != 0.0:
if "Received" in line:
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
size_hint_y=None, height=15, font_size=9)
self.ids.tx_list.add_widget(l)
self.calculated_balance += self.temp_tx_amount
elif "Spent" in line:
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
size_hint_y=None, height=15, font_size=9)
self.ids.tx_list.add_widget(l)
self.calculated_balance -= self.temp_tx_amount
self.temp_tx_amount = 0.0
self.temp_tx_amount = 0.0
self.calculated_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.calculated_balance)
if temp_line[0] == "Received":
self.calculated_balance += float(temp_line[2])
elif temp_line[0] == "Spent":
self.calculated_balance -= float(temp_line[2])
print("Launching wallet process!")
time.sleep(2)
self.calculated_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(self.calculated_balance)
self.wallet_process = Popen(["simplewallet", "--wallet-file", "./{0}_walletData/{1}.keys".format(
wallet_name.replace('.', ''), wallet_name), "--password", wallet_pw,
"--daemon-address", self.daemon_server_textinput.text, "--rpc-bind-port", "19091"],
stdin=PIPE,
# "--set_log", "0"],
# stdin=PIPE,
stdout=PIPE,
stderr=STDOUT,
bufsize=1)
self.wallet_thread = Thread(target=read_output,
args=(self.wallet_process, self.wallet_process.stdout, self.wallet_queue))
# self.wallet_thread = Thread(target=enqueue_output,
# args=(self.wallet_process.stdout, self.wallet_queue))
# shell=True)
# self.wallet_thread = Thread(target=read_output,
# args=(self.wallet_process, self.wallet_process.stdout, self.wallet_queue))
print(self.wallet_process.pid)
self.wallet_thread = Thread(target=enqueue_output,
args=(self.wallet_process.stdout, self.wallet_queue))
self.wallet_thread.daemon = True # thread dies with the program
self.wallet_thread.start()
Clock.schedule_interval(self.readWalletQueue, .01)
# Clock.schedule_interval(self.saveWallet, 60)
self.wallet_account_label.text = "[b][color=00ffff]{0}[/b][/color]".format(wallet_name)
self.wallet_address_label.text = "[b][color=00ffff][ref=Address]{0}[/ref]\nClick to copy[/b][/color]".format(self.address)
Clock.schedule_interval(self.readWalletQueue, 1e-3)
def readWalletQueue(self, dt):
print(self.wallet_thread.is_alive)
try:
print("trying")
newLine = self.wallet_queue.get_nowait()
# with open("rpcwallet.log", 'a') as logfile:
# logfile.write(newLine+'\n')
print newLine
if "Wallet initialize failed: failed to read file" in newLine:
new_line = self.wallet_queue.get_nowait()
# print(new_line)
if "Wallet initialize failed: failed to read file" in new_line:
self.wallet_thread.join()
self.wallet_error = True
os.remove("./{0}_walletData/{1}".format(self.wallet_name.replace('.', ''), self.wallet_name))
Clock.schedule_once(self.initialPassword, 0.5)
if "height:" in newLine:
height = newLine.split(", ")[1].split(": ")[1]
if "Wallet initialize failed: invalid password" in new_line:
self.wallet_thread.join()
self.incorrect_password = True
Clock.schedule_once(self.initialPassword, 0.5)
if "height:" in new_line:
try:
self.wallet_height = new_line.split(", ")[1].split(": ")[1]
self.wallet_block_label.text = "[b][color=00ffff]{0}[/b][/color] of [b][color=00ffff]{1}[/b][/color]".format(
height, self.blockheight)
elif "height " in newLine:
height = newLine.split(", ")[1].split(" ")[1]
self.wallet_height, self.blockheight)
except:
print("height: read failed")
elif "height " in new_line:
try:
self.wallet_height = new_line.split(", ")[1].split(" ")[1]
self.wallet_block_label.text = "[b][color=00ffff]{0}[/b][/color] of [b][color=00ffff]{1}[/b][/color]".format(
height, self.blockheight)
elif "Refresh done," in newLine:
print("refresh done")
split_line = newLine.split(',')
self.wallet_height, self.blockheight)
except:
print("height read failed")
elif "Refresh done," in new_line:
# print("refresh done")
split_line = new_line.split(',')
self.total_balance = float(split_line[2].split(': ')[1])
self.unlocked_balance = float(split_line[3].split(': ')[1])
self.total_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.total_balance)
self.unlocked_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(self.unlocked_balance)
if not self.wallet_save_time:
print("First save launching!")
Clock.schedule_once(self.saveWallet, 0.1)
self.wallet_save_time = time.time()
print("Wallet saved at: {0}".format(self.wallet_save_time))
if self.wallet_save_time:
if time.time() - self.wallet_save_time > 1800:
Clock.schedule_once(self.saveWallet, 0.1)
print(time.time(), self.wallet_save_time, "saving")
self.wallet_save_time = time.time()
elif "Received money" in newLine and "with tx" in newLine:
with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
this_amount, this_tx, this_date = txSplit(newLine)
tx_file.write(newLine + '\n')
self.total_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(self.total_balance)
self.unlocked_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(self.unlocked_balance)
elif "Received money" in new_line and "with tx" in new_line:
this_amount, this_tx, this_date = tx_split(new_line)
self.calculated_balance += this_amount
self.calculated_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color]".format(
self.calculated_balance_label.text = "[b][color=00ffff]{0:.3f}[/b][/color] XMR".format(
self.calculated_balance)
l = Label(text="Received {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
l = Label(text="Received {0:0.4f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
size_hint_y=None, height=15, font_size=9)
# self.ids.tx_scroller.clear_widgets()
self.ids.tx_list.add_widget(l)
elif "Spent money" in newLine and "with tx" in newLine:
# self.ids.tx_scroller.add_widget(self.ids.tx_list)
with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
this_amount, this_tx, this_date = txSplit(newLine)
tx_file.write(newLine + '\n')
self.calculated_balance -= this_amount
l = Label(text="Spent {0:0.3f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
tx_file.write("{0}\t{1}\t{2:0.4f}\t{3}\n".format("Received", this_date, this_amount, this_tx))
elif "Spent money" in new_line and "with tx" in new_line:
this_amount, this_tx, this_date = tx_split(new_line)
self.calculated_balance += this_amount
self.calculated_balance_label.text = "[b][color=00ffff]{0:.4f}[/b][/color] XMR".format(
self.calculated_balance)
l = Label(text="Spent {0:0.4f} XMR on {1} in tx: {2}".format(this_amount, this_date, this_tx),
size_hint_y=None, height=15, font_size=9)
# self.ids.tx_scroller.remove_widget(self.ids.tx_list)
self.ids.tx_list.add_widget(l)
# self.ids.tx_scroller.add_widget(self.ids.tx_list)
with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
tx_file.write("{0}\t{1}\t{2:0.4f}\t{3}\n".format("Spent", this_date, this_amount, this_tx))
# elif "Payment found" in newLine:
# with open("./{0}_walletData/tx.txt".format(self.wallet_name), 'a') as tx_file:
# tx_file.write(newLine + '\n')
@@ -519,42 +781,138 @@ class RootWidget(Accordion):
def saveWallet(self, dt):
print("Launching save thread")
save_thread = Thread(target=storeWallet)
try:
save_thread = Thread(target=self.storeWallet)
save_thread.daemon = True
save_thread.start()
print("Save thread started")
save_thread.join()
except:
print("Save failed")
def storeWallet(self):
print("Save thread started")
response = storeWallet()
print(response)
try:
response = storeWallet()
print(response)
if "jsonrpc" in response:
local_save_time = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
self.wallet_savetime_label.text = "Wallet saved @\n[b][color=00ffff]{0}[/b][/color]".format(local_save_time)
print("Finished save thread")
elif "Waiting for" in response:
self.wallet_savetime_label.text = "[color=ff0000]Wallet save failed\nprobably syncing[/color]"
except:
print("Major save fail!")
def selectAddress(self):
"""copy address to clipboard when user clicks"""
"""Copy address to clipboard when user clicks"""
print('User clicked on ', self.address)
self.daemon_server_textinput.copy(self.address)
def transferfunds(self):
"""initiate transfer of funds to new address"""
def transferfunds(self, address=None, mixin=None, amount=None, paymentid=None):
if not address:
address = self.address_input_textinput.text
if not mixin:
mixin = self.mixin_input_textinput.text
if not amount:
amount = self.amount_input_textinput.text
if not paymentid:
paymentid = self.paymentid_input_textinput.text
print(address, mixin, amount, paymentid)
print(len(paymentid), hex_match(paymentid))
"""Initiate transfer of funds to new address"""
address_error_content = Button(text="Address must be 95 characters long\nand start with a '4'.\nClick to start over.",
halign="center")
address_error_popup = Popup(title="Address error", content=address_error_content, size_hint=(0.75, 0.75))
address_error_content.bind(on_press=address_error_popup.dismiss)
mixin_error_content = Button(text="Mixin must be an integer between 0 and 99.\nClick to start over.",
halign="center")
mixin_error_popup = Popup(title="Mixin error", content=mixin_error_content, size_hint=(0.75, 0.75))
mixin_error_content.bind(on_press=mixin_error_popup.dismiss)
if self.unlocked_balance > 0.01:
amount_error_content = Button(text="Amount must be a number between 0.01 and {0:.3f} XMR.\nClick to start over.".format(self.unlocked_balance),
halign="center")
else:
amount_error_content = Button(text="Amount must be a number greater than 0.01 XMR.\nClick to start over.".format(self.unlocked_balance),
halign="center")
amount_error_popup = Popup(title="Amount error", content=amount_error_content, size_hint=(0.75, 0.75))
amount_error_content.bind(on_press=amount_error_popup.dismiss)
paymentid_error_content = Button(text="Payment ID must be 0 or 64 hex characters long.\nClick to start over.",
halign="center")
paymentid_error_popup = Popup(title="Payment ID error", content=paymentid_error_content, size_hint=(0.75, 0.75))
paymentid_error_content.bind(on_press=paymentid_error_popup.dismiss)
try:
float(self.amount_input_textinput.text)
tp = TransferPopup(self.amount_input_textinput.text, self.address_input_textinput.text,
self.mixin_input_textinput.text, self.paymentid_input_textinput.text)
tp.open()
address = address
if len(address) != 95 or address[0] != '4':
address_error_popup.open()
return
except IndexError:
address_error_popup.open()
return
try:
if not mixin:
mixin = 0
mixin = int(mixin)
if mixin == 1:
mixin = 0
print(mixin)
if not 0 <= mixin < 100:
mixin_error_popup.open()
return
except ValueError:
print("no,no")
mixin_error_popup.open()
return
try:
amount = float(amount)
if not 0.01 <= amount <= self.unlocked_balance:
amount_error_popup.open()
return
except ValueError:
amount_error_popup.open()
return
try:
paymentid = paymentid
if len(paymentid) not in (0, 64) or not hex_match(paymentid):
paymentid_error_popup.open()
return
except ValueError:
paymentid_error_popup.open()
return
tp = TransferPopup(amount, address, mixin, paymentid)
tp.open()
def donate_CMC(self):
CMC_donate_popup = DonateCMC()
CMC_donate_popup.open()
def donate_core(self):
core_donate_popup = DonateCore()
core_donate_popup.open()
class lightWalletApp(App):
def build(self):
return RootWidget()
root = RootWidget()
return root
if __name__ == '__main__':
Config.set('kivy', 'exit_on_escape', 0)
Config.set('kivy', 'window_icon', "./lilicon.ico")
lightWalletApp().run()
if sys.platform == 'win32':
try:
App.get_running_app().root.wallet_process.kill()
print("Simplewallet process killed")
except:
print("Wallet process not running")
# try:
# system("taskkill /im simplewallet.exe /f")
# except:
# print("Simplewallet.exe not running")
windows_task_killer(App.get_running_app().root.wallet_process.pid)
# time.sleep(1.5)
if os.path.isfile("./simplewallet.log"):
try:
os.remove("./simplewallet.log")
except WindowsError:
print("File in use, can not be deleted!")