Major update to cryptonoteRPCwalletGUI

This commit is contained in:
jwinterm
2014-06-16 19:08:40 -05:00
parent 7f4a09dbc0
commit 6e80f4a560
21 changed files with 954 additions and 336 deletions
+18
View File
@@ -0,0 +1,18 @@
# Cryptonote RPC wallet Kivy GUI
This is a GUI frontend that runs on top of bitmonerod, simplewallet (in RPC mode), and optionally LucasJones or Wolf's cryptonight cpuminer. **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.**
## Installation
### Windows, Linux, and Mac
The requirements for running the program are: Python 2.7 (or 2.6 may work), Kivy 1.8 (at least 1.4), and pygame 1.9.1 (others may work). If you have these requirements, then you just need to either add your binaries (bitmonerod(.exe), simplewallet(.exe), and optionally minerd(.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.
Currently there are no binaries available. I'm in the process of trying to compile an exe for Windows, and I think it should be easier to create binaries for linux. I've tested the program on Windows 7 & 8.1 and Debian Wheezy, and it seems to work OK on both. I think it should also work on Mac, but I haven't been able to test that yet.
## Running
It should be OK to launch the program with an instance of bitmonerod, simplewallet, or minerd running, but the program won't allow you to launch another instance of these programs if it detects their already running. So, unless you know that you are running bitmonerod and simplewallet in RPC mode, it's probably best to just launch them from within the GUI program. If you close just the GUI though, it should be fine to relaunch when one or all of the binaries are already running.
You can pass your wallet filename and password as arguments on the commandline, if you're launching from the command line, however this is currently not done in the most robust way possible, so make sure you just pass two arguments, the first being wallet name and second password, or the program will probably fail to start. I'm looking to make this more robust using argparse rather than argv.
## 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 incoming transactions, so it is delayed for the time being.
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.
-15
View File
@@ -1,15 +0,0 @@
import os
import subprocess
def bitmonerodloader():
"""Start bitmonerod and/or simplewallet and collect wallet name and address"""
#Start bitmonerod daemon if not running
if os.name == 'nt':
daemonproc = subprocess.Popen("start bitmonerod --rpc-bind-port 18081",
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
elif os.name == 'posix':
daemonproc = subprocess.Popen(['./bitmonerod --rpc-bind-port 18081'],
creationflags=subprocess.CREATE_NEW_CONSOLE,
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
-42
View File
@@ -1,42 +0,0 @@
import requests
import json
import time
serverURL = 'http://localhost:8081/json_rpc'
headers = {'content-type': 'application/json'}
payload = json.dumps({
"jsonrpc": "2.0",
"id": "test",
"method": "getlastblockheader"
})
def checklastblockrpccall():
synced = False
while synced == False:
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
try:
output[u'result'][u'status'] == 'OK'
synced = True
except:
time.sleep(2)
print "Waiting for bitmonerod client to sync with network..."
try:
if output[u'error'][u'message'] == 'Core is busy':
time.sleep(3)
except:
print '2nd'
print "Client is synced with the network."
print output
time.sleep(4)
return output
if __name__ == "__main__":
checklastblockrpccall()
-43
View File
@@ -1,43 +0,0 @@
import os
import time
import subprocess
import checklastblock
def simplewalletloader(walletname, walletpw, queue):
"""Function to create and/or open wallet in simplewallet rpc mode"""
#Generate wallet if file doesn't exist in local directory
if not os.path.isfile('./'+walletname):
print "Generating wallet file " + walletname
if os.name == 'nt':
walletgen = subprocess.Popen(
"simplewallet --generate-new-wallet " + walletname + " --password " + walletpw,
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
elif os.name == 'posix':
walletgen = subprocess.Popen(
"./simplewallet --generate-new-wallet " + walletname + " --password " + walletpw,
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
creationflags=subprocess.CREATE_NEW_CONSOLE)
time.sleep(7)
walletgen.terminate()
#Launch simplewallet in rpc mode
print "***Opening ___" + walletname + "___ wallet file rpc interface***"
if os.name == 'nt':
walletproc = subprocess.Popen("start simplewallet --wallet {0} --password {1} --rpc-bind-port 8082".format(walletname, walletpw),
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
elif os.name == 'posix':
walletproc = subprocess.Popen(["./simplewallet --wallet {0} --password {1} --rpc-bind-port 8082".format(
walletname, walletpw)], creationflags=subprocess.CREATE_NEW_CONSOLE)
#Read address file to get address
with open(walletname + ".address.txt", "r") as addressfile:
rawaddress = addressfile.read().replace('\n', '')
#Format data for display in kivy
walletname = walletname + ' wallet file has been opened'
address = '[color=00ffff][ref=addressselection]' + rawaddress + '[/ref][/color]'
queue.put((walletname, address, rawaddress))
-42
View File
@@ -1,42 +0,0 @@
import requests
import json
from ctypes import c_uint64
serverURL = 'http://localhost:8082/json_rpc'
def transferfundsrpccall(amount, address, mixin):
"""function to transfer funds to a single address"""
atomicamount = c_uint64(int((float(amount)*1e12)-1e6))
address = str(address)
mixin = int(mixin)
mro_fee = c_uint64(int(1e6))
payload = json.dumps({
"jsonrpc":"2.0",
"method":"transfer",
"params":{
"destinations":[
{
"amount":atomicamount.value,
"address":address
}
],
"fee":mro_fee.value,
"mixin":mixin,
"unlock_time":0
}
})
print payload
try:
headers = {'content-type': 'application/json'}
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
print output
except:
print "transfer error :0 !!!"
if __name__ == "__main__":
checkbalance()
+244 -162
View File
@@ -1,7 +1,11 @@
#:kivy 1.8.0
<RootWidget>:
cols: 1
id: rootwidget
daemonchecker_label: daemonchecker_label
daemoninfo_label: daemoninfo_label
namechecker_label: namechecker_label
walletchecker_label: walletchecker_label
input_name: name_input
input_pw: pw_input
label_myaddress: myaddress_label
@@ -11,179 +15,257 @@
input_amount: amount_input
input_mixin: mixin_input
input_paymentid: paymentid_input
minerurl_input: minerurl_input
mineruser_input: mineruser_input
minerpw_input: minerpw_input
minerthreads_input: minerthreads_input
BoxLayout:
size_hint_y: 0.4
Label:
text: "[b]Kivy Monero/Cryptonote GUI RPC Wallet[/b]"
markup: True
font_size: 20
AccordionItem:
title: "Start mining"
BoxLayout:
padding: 50,50,50,50
orientation: 'vertical'
Label:
text: "You must have cpuminer-multi binary in the local directory to use this panel."
Label:
text: "Mining pool address and port\n(e.g. stratum+tcp://pool.moonero.com:1234)"
TextInput:
id: minerurl_input
size_hint_x: 0.7
Label:
text: "Username/address\n(typically your XMR address)"
TextInput:
id: mineruser_input
font_size: 8
size_hint_x: 1.7
Label:
text: "Password\n(typically 'x' or blank)"
TextInput:
id: minerpw_input
size_hint_x: 0.7
Label:
text: "Number of threads\n(leave blank for max)"
TextInput:
id: minerthreads_input
size_hint_x: 0.4
Button:
text: "Launch cpuminer"
on_press: root.launchminer()
font_size: 20
BoxLayout:
size_hint_y: 0.1
AccordionItem:
title: "Transfer funds"
BoxLayout:
padding: 50,50,50,50
orientation: 'vertical'
Label:
text: "Send to address:"
size_hint_x: 0.2
TextInput:
id: address_input
size_hint_x: 2
font_size: 10
multiline: False
Label:
text: "Amount MRO:"
size_hint_x: 0.2
TextInput:
id: amount_input
size_hint_x: 0.8
font_size: 10
multiline: False
Label:
text: "Mixin amount:"
size_hint_x: 0.2
TextInput:
id: mixin_input
size_hint_x: 0.8
font_size: 10
multiline: False
Label:
text: "Payment ID:"
size_hint_x: 0.2
TextInput:
id: paymentid_input
size_hint_x: 1
font_size: 10
text: ""
multiline: False
Button:
text: "Transfer funds"
on_press: root.transferfunds()
on_press: root.storeformdata()
font_size: 20
AccordionItem:
title: "Initialize wallet file in simplewallet"
BoxLayout:
padding: 50,50,50,50
orientation: 'vertical'
Label:
id: walletchecker_label
size_hint_y: 0.5
text: ""
markup: True
font_size: 16
Button:
text: "Initialize wallet file"
on_press: root.launchwallet()
on_press: root.storeformdata()
font_size: 20
Label:
id: namechecker_label
text: ""
markup: True
font_size: 16
BoxLayout:
orientation: 'horizontal'
Label:
text: "Wallet name: "
size_hint_x: 0.3
font_size: 16
TextInput:
id: name_input
size_hint_x: 0.7
font_size: 12
text: root.walletname
BoxLayout:
orientation: 'horizontal'
Label:
text: "Wallet password: "
size_hint_x: 0.3
font_size: 16
TextInput:
id: pw_input
size_hint_x: 0.7
font_size: 12
text: root.walletpw
password: True
Label:
text: "Wallet address: \n [size=10](click address to copy)[/size]"
markup: True
font_size: 16
halign: 'center'
Label:
id: myaddress_label
text: "[ref=addressselection]uninitialized[/ref]"
markup: True
font_size: 10
on_ref_press: root.selectaddress()
BoxLayout:
orientation: 'horizontal'
Label:
text: "Balance: "
size_hint_x: 0.3
font_size: 16
Label:
id: balance_label
text: root.balance
size_hint_x: 0.7
markup: True
font_size: 16
BoxLayout:
orientation: 'horizontal'
Label:
text: "Unlocked balance: "
size_hint_x: 0.3
font_size: 16
Label:
id: unlockedbalance_label
text: root.unlockedbalance
size_hint_x: 0.7
markup: True
font_size: 16
Button:
text: "Save wallet data\n(for faster loading next time)."
on_press: root.savewallet()
font_size: 16
AccordionItem:
title: "Launch bitmonerod daemon"
BoxLayout:
padding: 50,50,50,50
orientation: 'vertical'
Image:
source: 'logo.png'
Label:
markup: True
font_size: 24
text: "[b]Kivy[/b] Wallet GUI"
Label:
id: daemonchecker_label
text: ""
markup: True
font_size: 18
Button:
size_hint_y: 1.2
text: "Start network daemon"
font_size: 20
on_press: root.launchdaemon()
Label:
size_hint_y: 2.5
id: daemoninfo_label
markup: True
font_size: 16
text: "Daemon block goes here..."
halign: 'left'
Button:
text: "Save blockchain info\n(for faster syncing next time)."
on_press: root.save_bc()
font_size: 16
Button:
text: "Store form data/user input\n(for lesser typing next time)."
on_press: root.storeformdata()
font_size: 16
<SaveBCPopup>
size_hint: 0.75, 0.75
auto_dismiss: False
title: "Save Blockchain Popup"
BoxLayout:
size_hint_y: 0.35
Label:
orientation: 'horizontal'
Button:
size_hint_x: 1.7
text: "Launch bitmonerod daemon"
on_press: root.launchdaemon()
Label:
text: "This may take a minute or three.\nPlease be patient...\nclick to close and save blockchain!"
on_press: root.really_save_bc()
on_press: root.dismiss()
Button:
size_hint_x: 1.7
text: "Launch simplewallet daemon"
on_press: root.launchwallet()
Label:
text: "Click to close without saving and cancel."
on_press: root.dismiss()
<TransferPopup>
popup_label: popup_label
size_hint: 0.75, 0.75
auto_dismiss: False
title: "Transfer Popup"
BoxLayout:
size_hint_y: 0.2
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
orientation: 'vertical'
Label:
text: "Wallet name: "
size_hint_x: 0.2
font_size: 16
TextInput:
id: name_input
size_hint_x: 0.8
font_size: 12
text: root.walletname
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
Label:
text: "Wallet password: "
size_hint_x: 0.2
font_size: 16
TextInput:
id: pw_input
size_hint_x: 0.8
font_size: 12
text: root.walletpw
password: True
BoxLayout:
size_hint_y: 0.5
padding: 10,0,80,0
Label:
text: "Wallet address: \n [size=10](click address to copy)[/size]"
# text: "are you sure?"
id: popup_label
text: ""
markup: True
size_hint_x: 0.3
font_size: 16
halign: 'center'
Label:
id: myaddress_label
text: "[ref=addressselection]uninitialized[/ref]"
markup: True
size_hint_x: 0.7
font_size: 10
on_ref_press: root.selectaddress()
BoxLayout:
orientation: 'horizontal'
Button:
text: "Yes, transfer XMR."
on_press: root.transfer()
on_press: root.dismiss()
Button:
text: "No, cancel transaction."
on_press: root.dismiss()
<TxIDPopup>
title: "Tx ID Popup"
txid_label: txid_label
BoxLayout:
size_hint_y: 0.3
orientation: 'vertical'
Label:
text: "Balance: "
size_hint_x: 0.3
font_size: 16
Label:
id: balance_label
text: root.balance
size_hint_x: 0.7
font_size: 11
markup: True
font_size: 16
BoxLayout:
size_hint_y: 0.3
Label:
text: "Unlocked balance: "
size_hint_x: 0.3
font_size: 16
Label:
id: unlockedbalance_label
text: root.unlockedbalance
size_hint_x: 0.7
markup: True
font_size: 16
BoxLayout:
size_hint_y: 0.35
Label:
id: txid_label
text: ""
on_ref_press: root.selecttxid()
Button:
text: "Refresh balance"
on_press: root.checkbalance()
font_size: 20
Label:
BoxLayout:
size_hint_y: 0.2
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
Label:
text: "Send to address:"
size_hint_x: 0.2
TextInput:
id: address_input
size_hint_x: 0.8
font_size: 10
multiline: False
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
Label:
text: "Amount MRO:"
size_hint_x: 0.2
TextInput:
id: amount_input
size_hint_x: 0.8
font_size: 10
multiline: False
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
Label:
text: "Mixin amount:"
size_hint_x: 0.2
TextInput:
id: mixin_input
size_hint_x: 0.8
font_size: 10
multiline: False
BoxLayout:
padding: 10,0,40,0
size_hint_y: 0.3
Label:
text: "Payment ID:"
size_hint_x: 0.2
TextInput:
id: paymentid_input
size_hint_x: 0.8
font_size: 10
text: "DISABLED!!! Do not send funds to exchanges. Disabled payment id field is required for depositing on exchanges!"
multiline: False
BoxLayout:
padding: 200,0,200,0
size_hint_y: 0.35
Button:
text: "Transfer funds"
on_press: root.transferfunds()
font_size: 20
BoxLayout:
size_hint_y: 0.1
text: "OK, dismiss."
on_press: root.dismiss()
+253 -32
View File
@@ -1,74 +1,289 @@
# !/usr/bin/python
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.accordion import Accordion
from kivy.properties import ObjectProperty
from kivy.core.clipboard import Clipboard
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.storage.jsonstore import JsonStore
from functions.bitmonerodloader import bitmonerodloader
from functions.checkbalance import checkbalancerpccall
from functions.transferfunds import transferfundsrpccall
from functions.simplewalletloader import simplewalletloader
from lib.isrunning import isrunning
from lib.checklastblock import checklastblock
from lib.bitmonerodloader import bitmonerodloader
from lib.balancecheck import balancecheck
from lib.namecheck import namecheck
from lib.transferfunds import transferfundsrpccall
from lib.simplewalletloader import simplewalletloader
from lib.save_bc import save_bc
from lib.savewallet import storewallet
from lib.cpuminerloader import cpuminerloader
from sys import argv
from sys import argv, platform
from os.path import isfile
import argparse
from multiprocessing import Process, Queue
class RootWidget(GridLayout):
# Signal that will switch to False on shutdown to kill children
kivysignal = True
class SaveBCPopup(Popup):
def really_save_bc(self):
self.storebcthread = Process(target=save_bc)
self.storebcthread.start()
self.storebcthread.join()
self.storebcthread.terminate()
self.storebcthread.join(timeout=3)
class TransferPopup(Popup):
popup_label = ObjectProperty()
def __init__(self, amount, address, mixin, paymentid):
super(TransferPopup, self).__init__()
self.amount = amount
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(
float(amount), address, mixin, paymentid)
self.popup_label.text = self.popuptext
def transfer(self):
txid = transferfundsrpccall(self.amount, self.address, self.mixin, self.paymentid)
p = TxIDPopup(txid)
p.open()
class TxIDPopup(Popup):
txid_label = ObjectProperty()
def __init__(self, txid):
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)
def selecttxid(self):
Clipboard.put(self.txid)
class RootWidget(Accordion):
"""Root Kivy widget class"""
#Ininitalize variables
# Check to see if wallet name and password passed as arguments
if len(argv) == 1:
walletname, walletpw = "", ""
elif len(argv) == 3:
walletname, walletpw = argv[1], argv[2]
# Initialize other variables
address, rawaddress = "uninitialized", "uninitialized"
balance, unlockedbalance = "uninitialized", "uninitialized"
#Setup object properties to be modified/used
blockinfotext = "Last block info stats go here..."
namecheckmessage = "uninitialized"
isname = None
# Setup object properties to be modified/used by Kivy
# bitmonerod daemon tab
daemonchecker_label = ObjectProperty()
daemoninfo_label = ObjectProperty()
# init simplewallet tab
namechecker_label = ObjectProperty()
walletchecker_label = ObjectProperty()
input_name = ObjectProperty()
input_pw = ObjectProperty()
label_myaddress = ObjectProperty()
label_balance = ObjectProperty()
label_unlockedbalance = ObjectProperty()
# transfer tab
input_address = ObjectProperty()
input_amount = ObjectProperty()
input_mixin = ObjectProperty()
input_paymentid = ObjectProperty()
# mining tab
minerurl_input = ObjectProperty()
mineruser_input = ObjectProperty()
minerpw_input = ObjectProperty()
minerthreads_input = ObjectProperty()
walletqueue = Queue()
# Setup queues, signals, and workers
isrunningjobqueue, isrunningresultsqueue = Queue(), Queue()
checklastblockjobqueue, checklastblockresultsqueue = Queue(), Queue()
loadwalletresultsqueue = Queue()
checkbalancejobqueue, checkbalanceresultsqueue = Queue(), Queue()
checknamejobqueue, checknameresultsqueue = Queue(), Queue()
daemonrunning = None
walletrunning = None
minerrunning = None
workers = [
Process(target=isrunning,
args=(isrunningjobqueue, isrunningresultsqueue)),
Process(target=checklastblock,
args=(checklastblockjobqueue, checklastblockresultsqueue)),
Process(target=balancecheck,
args=(checkbalancejobqueue, checkbalanceresultsqueue)),
Process(target=namecheck,
args=(checknamejobqueue, checknameresultsqueue))
]
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.workers[0].start()
self.workers[1].start()
self.workers[2].start()
self.workers[3].start()
Clock.schedule_interval(self.checkisrunning, 0.1)
Clock.schedule_interval(self.getblockinfo, 1)
Clock.schedule_interval(self.checkbalance, 1)
Clock.schedule_interval(self.checkname, 0.1)
# load data if it exists
if isfile('forms.json'):
try:
store = JsonStore('forms.json')
self.input_name.text = store.get('forms')['walletname']
self.input_address.text = store.get('forms')['sendtoaddress']
self.input_amount.text = store.get('forms')['amount']
self.input_mixin.text = store.get('forms')['mixin']
self.input_paymentid.text = store.get('forms')['paymentid']
self.minerurl_input.text = store.get('forms')['mineraddress']
self.mineruser_input.text = store.get('forms')['mineruser']
self.minerpw_input.text = store.get('forms')['minerpw']
self.minerthreads_input.text = store.get('forms')[
'minerthreads']
except:
pass
def checkisrunning(self, dt):
"""Check if daemon is running"""
try:
self.daemonrunning, daemoncheckerlabeltext, self.walletrunning, walletcheckerlabeltext, self.minerrunning = self.isrunningresultsqueue.get_nowait()
self.daemonchecker_label.text = daemoncheckerlabeltext
self.walletchecker_label.text = walletcheckerlabeltext
except:
pass
self.isrunningjobqueue.put(kivysignal)
def getblockinfo(self, dt):
"""Try to update daemon stats"""
try:
self.blockinfotext = self.checklastblockresultsqueue.get_nowait()
except:
pass
# blockinfotext = "Last block info:\n No RPC info available."
self.daemoninfo_label.text = self.blockinfotext
self.checklastblockjobqueue.put((self.daemonrunning, kivysignal))
def launchdaemon(self):
"""launch the bitmonerod daemon in rpc mode"""
bitmonerodloader()
if not self.daemonrunning:
self.launchdaemonthread = Process(target=bitmonerodloader)
self.launchdaemonthread.start()
self.daemonrunning = True
def save_bc(self):
p = SaveBCPopup()
p.open()
def checkbalance(self, dt):
"""Try to update balance stats"""
try:
self.balance, self.unlockedbalance, self.rawaddress = self.checkbalanceresultsqueue.get_nowait()
self.label_balance.text = self.balance
self.label_unlockedbalance.text = self.unlockedbalance
self.address = '[color=00ffff][ref=addressselection]' + self.rawaddress + '[/ref][/color]'
self.label_myaddress.text = self.address
except:
pass
try:
wallet, self.address, self.rawaddress = self.loadwalletresultsqueue.get_nowait()
self.label_myaddress.text = self.address
except:
pass
self.checkbalancejobqueue.put((self.walletrunning, kivysignal))
def launchwallet(self):
"""create wallet if necessary and then launch in rpc mode"""
walletthread = Process(target=simplewalletloader, args=(self.input_name.text, self.input_pw.text, self.walletqueue))
walletthread.start()
walletthread.join()
self.walletname, self.address, self.rawaddress = self.walletqueue.get()
self.input_name.text = self.walletname
self.input_name.background_color = (0.1,0.8,0.8,1)
self.label_myaddress.text = self.address
if not self.walletrunning:
self.walletname = self.input_name.text
self.walletpw = self.input_pw.text
self.launchwalletthread = Process(target=simplewalletloader,
args=(self.walletname,
self.walletpw,
self.isname))
self.launchwalletthread.start()
self.walletrunning = True
self.storeformdata()
def checkbalance(self):
"""get balance info from rpc"""
self.balance, self.unlockedbalance = checkbalancerpccall()
self.label_balance.text = self.balance
self.label_unlockedbalance.text = self.unlockedbalance
def checkname(self, dt):
"""Check if wallet name exists in local directory"""
self.walletname = str(self.input_name.text)
self.checknamejobqueue.put((self.walletname, kivysignal))
if not self.walletname:
self.walletname = "No filename"
# print "no file!"
try:
self.isname, self.namecheckmessage = self.checknameresultsqueue.get_nowait()
# print self.isname
except:
pass
if self.walletrunning:
self.namecheckmessage = ""
self.namechecker_label.text = self.namecheckmessage
def selectaddress(self):
"""copy address to clipboard when user clicks"""
print('User clicked on ', self.rawaddress)
Clipboard.put(self.rawaddress)
# Clipboard.put(self.rawaddress)
self.input_address.copy(self.rawaddress)
def savewallet(self):
self.storewalletthread = Process(target=storewallet)
self.storewalletthread.start()
self.storewalletthread.join(timeout=3)
self.storewalletthread.terminate()
self.storewalletthread.join()
def transferfunds(self):
"""initiate transfer of funds to new address"""
transferfundsrpccall(self.input_amount.text, self.input_address.text, self.input_mixin.text)
self.checkbalance()
p = TransferPopup(self.input_amount.text, self.input_address.text,
self.input_mixin.text, self.input_paymentid.text)
p.open()
def transfer(self):
self.transferthread = Process(target=transferfundsrpccall,
args=(self.amount.text, self.address.text,
self.mixin.text,
self.paymentid.text))
self.transferthread.start()
self.transferthread.join()
self.transferthread.terminate()
self.transferthread.join(timeout=3)
def launchminer(self):
try:
if not self.minerrunning:
self.launchminerthread = Process(target=cpuminerloader,
args=(self.minerurl_input.text,
self.mineruser_input.text,
self.minerpw_input.text,
self.minerthreads_input.text))
self.launchminerthread.start()
self.minerrunning = True
self.storeformdata()
except:
pass
def storeformdata(self):
store = JsonStore('forms.json')
store.put('forms',
walletname=self.input_name.text,
sendtoaddress=self.input_address.text,
amount=self.input_amount.text,
mixin=self.input_mixin.text,
paymentid=self.input_paymentid.text,
mineraddress=self.minerurl_input.text,
mineruser=self.mineruser_input.text,
minerpw=self.minerpw_input.text,
minerthreads=self.minerthreads_input.text)
class KivyWalletApp(App):
@@ -77,4 +292,10 @@ class KivyWalletApp(App):
if __name__ == '__main__':
KivyWalletApp().run()
KivyWalletApp().run()
kivysignal = False
for i in RootWidget.workers:
print i.name
i.terminate()
i.join()
+49
View File
@@ -0,0 +1,49 @@
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
@@ -0,0 +1,16 @@
import subprocess
from sys import platform
import os
def bitmonerodloader():
"""Start bitmonerod and/or simplewallet and collect wallet name and address"""
print "Start daemon button pressed..."
#Start bitmonerod daemon if not running
if platform == 'win32':
daemonproc = subprocess.Popen("start bitmonerod.exe --rpc-bind-port 18081 --log-level 0",
shell=True)
elif platform == 'linux' or platform == 'linux2' or platform == 'linux32':
# print "linux!"
daemonproc = subprocess.Popen('xterm -bg black -e "./bitmonerod --rpc-bind-port 18081 --log-level 0"',
shell=True)
+55
View File
@@ -0,0 +1,55 @@
import requests
import json
import time
import datetime
serverURL = 'http://localhost:18081/json_rpc'
headers = {'content-type': 'application/json'}
payload = json.dumps({
"jsonrpc": "2.0",
"id": "test",
"method": "getlastblockheader"
})
def checklastblock(jobqueue, resultsqueue):
"""Try and get last block info and return formatted text"""
kivysignal = True
while kivysignal:
time.sleep(1)
daemonrunning, kivysignal = jobqueue.get()
if daemonrunning:
try:
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
# print(output)
reward = output[u'result'][u'block_header'][u'reward']
linuxblocktime = output[u'result'][u'block_header'][u'timestamp']
linuxtimenow = time.time()
timesince = linuxtimenow - linuxblocktime
localtime = datetime.datetime.fromtimestamp(int(linuxblocktime
)).strftime('%Y-%m-%d %H:%M:%S')
blocktext = "Last block height: [color=00ffff]{0}[/color]".format(
output[u'result'][u'block_header'][u'height'])
rewardtext = "Last block reward: [color=00ffff]{0:2.2f}[/color] XMR".format(float(reward)/1e12)
timetext = "Last block time: [color=00ffff]{0}[/color]".format(localtime)
timesincetext = "Time since last block: [color=00ffff]{0:4.2f} s[/color]".format(timesince)
difftext = "Difficulty: [color=00ffff]{0}[/color]".format(
output[u'result'][u'block_header'][u'difficulty'])
orphantext = "Orphan status: [color=00ffff]{0}[/color]".format(
output[u'result'][u'block_header'][u'orphan_status'])
except:
blocktext = "Last block height: Not connected to daemon..."
rewardtext = "Last block reward: Not connected to daemon..."
timetext = "Last block time: Not connected to daemon..."
timesincetext = "Time since last block: Not connected to daemon..."
difftext = "Difficulty: Not connected to daemon..."
orphantext = "Orphan status: connected to daemon..."
daemoninfo_labeltext = "[b]Last block info:[/b]\n{0}\n{1}\n{2}\n{3}\n{4}\n{5}".format(
blocktext, rewardtext, timetext, timesincetext, difftext, orphantext)
resultsqueue.put(daemoninfo_labeltext)
+16
View File
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,46 @@
#!/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()
+58
View File
@@ -0,0 +1,58 @@
# !/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
@@ -0,0 +1,22 @@
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
@@ -0,0 +1,26 @@
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
+25
View File
@@ -0,0 +1,25 @@
import requests
import json
import time
serverURL = 'http://localhost:19091/json_rpc'
headers = {'content-type': 'application/json'}
payload = json.dumps({
"jsonrpc": "2.0",
"method": "store",
"params": {}
})
def storewallet():
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
+62
View File
@@ -0,0 +1,62 @@
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
+64
View File
@@ -0,0 +1,64 @@
import requests
import json
from ctypes import c_uint64
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))
address = str(address)
mixin = int(mixin)
paymentid = str(paymentid)
mro_fee = c_uint64(int(5e9))
if len(paymentid) > 1:
payload = json.dumps({
"jsonrpc":"2.0",
"method":"transfer",
"params":{
"destinations":[
{
"amount":atomicamount.value,
"address":address
}
],
"fee":mro_fee.value,
"mixin":mixin,
"unlock_time":0,
"payment_id":paymentid
}
})
else:
payload = json.dumps({
"jsonrpc":"2.0",
"method":"transfer",
"params":{
"destinations":[
{
"amount":atomicamount.value,
"address":address
}
],
"fee":mro_fee.value,
"mixin":mixin,
"unlock_time":0
}
})
print payload
try:
headers = {'content-type': 'application/json'}
resp = requests.get(serverURL, headers=headers, data=payload)
output = json.loads(resp.text)
print output
txid = output[u'result'][u'tx_hash']
return txid
except:
print "transfer error :0 !!!"
return "error"
if __name__ == "__main__":
checkbalance()