improve requests

This commit is contained in:
ThomasV 2015-06-07 18:44:33 +02:00
parent fbc68d94d6
commit 48e53498db
4 changed files with 114 additions and 63 deletions

View File

@ -41,6 +41,7 @@ from electrum import mnemonic
from electrum import util, bitcoin, commands, Wallet
from electrum import SimpleConfig, Wallet, WalletStorage
from electrum import Imported_Wallet
from electrum import paymentrequest
from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit
from network_dialog import NetworkDialog
@ -721,8 +722,8 @@ class ElectrumWindow(QMainWindow):
def export_payment_request(self, addr):
r = self.wallet.get_payment_request(addr)
pr = self.wallet.make_bip70_request(self.config, r)
name = 'request.bip70'
pr = paymentrequest.make_request(self.config, r)
name = r['key'] + '.bip70'
fileName = self.getSaveFileName(_("Select where to save your payment request"), name, "*.bip70")
if fileName:
with open(fileName, "wb+") as f:
@ -804,17 +805,18 @@ class ElectrumWindow(QMainWindow):
# clear the list and fill it again
self.receive_list.clear()
for address, req in self.wallet.receive_requests.viewitems():
timestamp, amount = req['time'], req['amount']
expiration = req.get('expiration', None)
message = self.wallet.labels.get(address, '')
# only show requests for the current account
for req in self.wallet.get_sorted_requests():
address = req['address']
if address not in domain:
continue
timestamp = req['time']
amount = req.get('amount')
expiration = req.get('expiration', None)
message = req.get('reason', '')
date = format_time(timestamp)
status = req.get('status')
account = self.wallet.get_account_name(self.wallet.get_account_from_address(address))
amount_str = self.format_amount(amount) if amount else ""
status = self.wallet.get_request_status(address, amount, timestamp, expiration)
item = QTreeWidgetItem([date, account, address, message, amount_str, pr_tooltips.get(status,'')])
if status is not PR_UNKNOWN:
item.setIcon(5, QIcon(pr_icons.get(status)))

View File

@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import datetime
import time
@ -31,7 +32,7 @@ from util import print_msg, format_satoshis, print_stderr
import bitcoin
from bitcoin import is_address, hash_160_to_bc_address, hash_160, COIN
from transaction import Transaction
import paymentrequest
known_commands = {}
@ -516,7 +517,7 @@ class Commands:
"""Decrypt a message encrypted with a public key."""
return self.wallet.decrypt_message(pubkey, encrypted, self.password)
def _format_request(self, v, show_status=False):
def _format_request(self, v):
from paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
pr_str = {
PR_UNKNOWN: 'Unknown',
@ -524,42 +525,66 @@ class Commands:
PR_PAID: 'Paid',
PR_EXPIRED: 'Expired',
}
key = v['key']
addr = v.get('address')
amount = v.get('amount')
timestamp = v.get('time')
expiration = v.get('expiration')
out = {
'key': key,
'address': addr,
'amount': format_satoshis(amount),
'time': timestamp,
'reason': self.wallet.get_label(addr)[0],
'timestamp': timestamp,
'reason': v.get('reason'),
'expiration': expiration,
'URI':'bitcoin:' + addr + '?amount=' + format_satoshis(amount),
'status': pr_str[v.get('status', PR_UNKNOWN)]
}
if v.get('path'):
url = 'file://' + v.get('path')
r = self.config.get('url_rewrite')
if r:
a, b = r
url = url.replace(a, b)
URI = 'bitcoin:?r=' + url
out['URI'] = URI
if show_status:
status = self.wallet.get_request_status(addr, amount, timestamp, expiration)
out['status'] = pr_str[status]
# check if bip70 file exists
rdir = self.config.get('requests_dir')
if rdir:
path = os.path.join(rdir, key + '.bip70')
if os.path.exists(path):
out['path'] = path
url = 'file://' + path
r = self.config.get('url_rewrite')
if r:
a, b = r
url = url.replace(a, b)
out['request_url'] = url
out['URI'] += '&r=' + url
return out
@command('w')
def listrequests(self, status=False):
"""List the payment requests you made, and their status"""
return map(lambda x: self._format_request(x, status), self.wallet.receive_requests.values())
@command('wn')
def getrequest(self, key):
"""Return a payment request"""
r = self.wallet.get_payment_request(key)
if not r:
raise BaseException("Request not found")
return self._format_request(r)
@command('w')
def addrequest(self, requested_amount, reason='', expiration=60*60):
"""Create a payment request.
"""
def ackrequest(self, serialized):
"""<Not implemented>"""
pass
@command('w')
def listrequests(self):
"""List the payment requests you made, and their status"""
return map(self._format_request, self.wallet.get_sorted_requests())
@command('w')
def addrequest(self, requested_amount, reason='', expiration=None):
"""Create a payment request."""
amount = int(Decimal(requested_amount)*COIN)
key = self.wallet.add_payment_request(self.config, amount, reason, expiration)
return self._format_request(self.wallet.get_payment_request(key)) if key else False
key = self.wallet.add_payment_request(amount, reason, expiration)
if key is None:
return
# create file
req = self.wallet.get_payment_request(key)
paymentrequest.publish_request(self.config, key, req)
return self._format_request(req)
@command('w')
def rmrequest(self, address):
@ -659,6 +684,8 @@ def set_default_subparser(self, name, args=None):
argparse.ArgumentParser.set_default_subparser = set_default_subparser
def add_network_options(parser):
parser.add_argument("-1", "--oneserver", action="store_true", dest="oneserver", default=False, help="connect to one server only")
parser.add_argument("-s", "--server", dest="server", default=None, help="set server host:port:protocol, where protocol is either t (tcp) or s (ssl)")

View File

@ -262,13 +262,12 @@ class PaymentRequest:
def make_payment_request(outputs, memo, time, expires, key_path, cert_path):
pd = pb2.PaymentDetails()
for script, amount in outputs:
pd.outputs.add(amount=amount, script=script)
pd.time = time
pd.expires = expires
pd.expires = expires if expires else 0
pd.memo = memo
pr = pb2.PaymentRequest()
pr.serialized_payment_details = pd.SerializeToString()
@ -294,6 +293,37 @@ def make_payment_request(outputs, memo, time, expires, key_path, cert_path):
return pr.SerializeToString()
def make_request(config, req):
from transaction import Transaction
addr = req['address']
time = req['time']
amount = req['amount']
expiration = req['expiration']
message = req['reason']
script = Transaction.pay_script('address', addr).decode('hex')
outputs = [(script, amount)]
key_path = config.get('ssl_privkey')
cert_path = config.get('ssl_chain')
return make_payment_request(outputs, message, time, time + expiration if expiration else None, key_path, cert_path)
def publish_request(config, key, req):
import shutil, os
rdir = config.get('requests_dir')
if not rdir:
return
if not os.path.exists(rdir):
os.mkdir(rdir)
index = os.path.join(rdir, 'index.html')
if not os.path.exists(index):
src = os.path.join(os.path.dirname(__file__), 'payrequest.html')
shutil.copy(src, index)
pr = make_request(config, req)
path = os.path.join(rdir, key + '.bip70')
with open(path, 'w') as f:
f.write(pr)
return path
class InvoiceStore(object):

View File

@ -1231,25 +1231,22 @@ class Abstract_Wallet(object):
if not self.history.get(addr) and addr not in self.receive_requests.keys():
return addr
def make_bip70_request(self, config, req):
from paymentrequest import make_payment_request
addr = req['address']
time = req['time']
amount = req['amount']
expiration = req['expiration']
message = self.labels.get(addr, '')
script = Transaction.pay_script('address', addr).decode('hex')
outputs = [(script, amount)]
key_path = config.get('ssl_privkey')
cert_path = config.get('ssl_chain')
return make_payment_request(outputs, message, time, time + expiration, key_path, cert_path)
def get_payment_request(self, key):
return self.receive_requests.get(key)
r = self.receive_requests.get(key)
if not r:
return
r['reason'] = self.labels.get(key, '')
r['status'] = self.get_request_status(key)
r['key'] = key
return r
def get_request_status(self, address, amount, timestamp, expiration):
def get_request_status(self, key):
from paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
r = self.receive_requests[key]
address = r['address']
amount = r.get('amount')
timestamp = r.get('time')
expiration = r.get('expiration')
if amount:
paid = amount <= self.get_addr_received(address)
status = PR_PAID if paid else PR_UNPAID
@ -1259,27 +1256,18 @@ class Abstract_Wallet(object):
status = PR_UNKNOWN
return status
def save_payment_request(self, config, addr, amount, message, expiration):
#if addr in self.receive_requests:
# self.receive_requests[addr]['amount'] = amount
def save_payment_request(self, addr, amount, message, expiration):
self.set_label(addr, message)
now = int(time.time())
r = {'time':now, 'amount':amount, 'expiration':expiration, 'address':addr}
rdir = config.get('requests_dir')
if rdir:
pr = self.make_bip70_request(config, r)
path = os.path.join(rdir, addr + '.bip70')
with open(path, 'w') as f:
f.write(pr)
r['path'] = path
self.receive_requests[addr] = r
self.storage.put('receive_requests2', self.receive_requests)
def add_payment_request(self, config, amount, message, expiration):
def add_payment_request(self, amount, message, expiration):
addr = self.get_unused_address(None)
if addr is None:
return False
self.save_payment_request(config, addr, amount, message, expiration)
return
self.save_payment_request(addr, amount, message, expiration)
return addr
def remove_payment_request(self, addr):
@ -1289,6 +1277,10 @@ class Abstract_Wallet(object):
self.storage.put('receive_requests2', self.receive_requests)
return True
def get_sorted_requests(self):
return sorted(map(self.get_payment_request, self.receive_requests.keys()), key=itemgetter('time'))
class Imported_Wallet(Abstract_Wallet):
wallet_type = 'imported'