tmove payment requests logic to wallet, add basic commands - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 0938299e9bf858817d3c391ebcdca3d48d5dd3d4
 (DIR) parent e5b6b05482dffb2d6370dad3f0fd21276fff5747
 (HTM) Author: ThomasV <thomasv@gitorious>
       Date:   Mon,  1 Jun 2015 13:02:09 +0200
       
       move payment requests logic to wallet, add basic commands
       
       Diffstat:
         M gui/qt/main_window.py               |      60 +++++++------------------------
         M lib/commands.py                     |      29 +++++++++++++++++++++++++++++
         M lib/wallet.py                       |      40 +++++++++++++++++++++++++++++++
       
       3 files changed, 82 insertions(+), 47 deletions(-)
       ---
 (DIR) diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -666,7 +666,7 @@ class ElectrumWindow(QMainWindow):
                if not self.receive_list.isItemSelected(item):
                    return
                addr = str(item.text(2))
       -        req = self.receive_requests[addr]
       +        req = self.wallet.receive_requests[addr]
                expires = _('Never') if req.get('expiration') is None else format_time(req['time'] + req['expiration'])
                amount = req['amount']
                message = self.wallet.labels.get(addr, '')
       t@@ -680,8 +680,7 @@ class ElectrumWindow(QMainWindow):
        
            def delete_payment_request(self, item):
                addr = str(item.text(2))
       -        self.receive_requests.pop(addr)
       -        self.wallet.storage.put('receive_requests2', self.receive_requests)
       +        self.wallet.remove_payment_request(addr)
                self.update_receive_tab()
                self.clear_receive_tab()
        
       t@@ -695,7 +694,7 @@ class ElectrumWindow(QMainWindow):
            def receive_list_menu(self, position):
                item = self.receive_list.itemAt(position)
                addr = str(item.text(2))
       -        req = self.receive_requests[addr]
       +        req = self.wallet.receive_requests[addr]
                time, amount = req['time'], req['amount']
                message = self.wallet.labels.get(addr, '')
                URI = util.create_URI(addr, amount, message)
       t@@ -713,35 +712,15 @@ class ElectrumWindow(QMainWindow):
                if not message and not amount:
                    QMessageBox.warning(self, _('Error'), _('No message or amount'), _('OK'))
                    return
       -        self.receive_requests = self.wallet.storage.get('receive_requests2', {})
       -        if addr in self.receive_requests:
       -            self.receive_requests[addr]['amount'] = amount
       -        else:
       -            now = int(time.time())
       -            i = self.expires_combo.currentIndex()
       -            expiration = map(lambda x: x[1], expiration_values)[i]
       -            self.receive_requests[addr] = {'time':now, 'amount':amount, 'expiration':expiration}
       -
       -        self.wallet.storage.put('receive_requests2', self.receive_requests)
       -        self.wallet.set_label(addr, message)
       +        i = self.expires_combo.currentIndex()
       +        expiration = map(lambda x: x[1], expiration_values)[i]
       +        self.wallet.save_payment_request(addr, amount, message, expiration)
                self.update_receive_tab()
                self.update_address_tab()
                self.save_request_button.setEnabled(False)
        
       -    def make_payment_request(self, addr):
       -        req = self.receive_requests[addr]
       -        time = req['time']
       -        amount = req['amount']
       -        expiration = req['expiration']
       -        message = self.wallet.labels.get(addr, '')
       -        script = Transaction.pay_script('address', addr).decode('hex')
       -        outputs = [(script, amount)]
       -        key_path = self.config.get('ssl_key_path')
       -        cert_path = self.config.get('ssl_cert_path')
       -        return make_payment_request(outputs, message, time, time + expiration, key_path, cert_path)
       -
            def export_payment_request(self, addr):
       -        pr = self.make_payment_request(addr)
       +        pr = self.wallet.make_bip70_request(self.config, addr)
                name = 'request.bip70'
                fileName = self.getSaveFileName(_("Select where to save your payment request"), name, "*.bip70")
                if fileName:
       t@@ -750,14 +729,8 @@ class ElectrumWindow(QMainWindow):
                    self.show_message(_("Request saved successfully"))
                    self.saved = True
        
       -    def get_receive_address(self):
       -        domain = self.wallet.get_account_addresses(self.current_account, include_change=False)
       -        for addr in domain:
       -            if not self.wallet.history.get(addr) and addr not in self.receive_requests.keys():
       -                return addr
       -
            def new_payment_request(self):
       -        addr = self.get_receive_address()
       +        addr = self.wallet.get_unused_address(self.current_account)
                if addr is None:
                    if isinstance(self.wallet, Imported_Wallet):
                        self.show_message(_('No more addresses in your wallet.'))
       t@@ -777,14 +750,8 @@ class ElectrumWindow(QMainWindow):
                self.receive_amount_e.setAmount(None)
        
            def clear_receive_tab(self):
       -        self.receive_requests = self.wallet.storage.get('receive_requests2',{})
       -        domain = self.wallet.get_account_addresses(self.current_account, include_change=False)
       -        for addr in domain:
       -            if not self.wallet.history.get(addr) and addr not in self.receive_requests.keys():
       -                break
       -        else:
       -            addr = ''
       -        self.receive_address_e.setText(addr)
       +        addr = self.wallet.get_unused_address(self.current_account)
       +        self.receive_address_e.setText(addr if addr else '')
                self.receive_message_e.setText('')
                self.receive_amount_e.setAmount(None)
                self.expires_label.hide()
       t@@ -814,10 +781,9 @@ class ElectrumWindow(QMainWindow):
                self.new_request_button.setEnabled(True)
        
            def update_receive_tab(self):
       -        self.receive_requests = self.wallet.storage.get('receive_requests2',{})
        
                # hide receive tab if no receive requests available
       -        b = len(self.receive_requests) > 0
       +        b = len(self.wallet.receive_requests) > 0
                self.receive_list.setVisible(b)
                self.receive_requests_label.setVisible(b)
                if not b:
       t@@ -830,14 +796,14 @@ class ElectrumWindow(QMainWindow):
                # update the receive address if necessary
                current_address = self.receive_address_e.text()
                domain = self.wallet.get_account_addresses(self.current_account, include_change=False)
       -        addr = self.get_receive_address()
       +        addr = self.wallet.get_unused_address(self.current_account)
                if not current_address in domain and addr:
                    self.set_receive_address(addr)
                self.new_request_button.setEnabled(addr != current_address)
        
                # clear the list and fill it again
                self.receive_list.clear()
       -        for address, req in self.receive_requests.viewitems():
       +        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, '')
 (DIR) diff --git a/lib/commands.py b/lib/commands.py
       t@@ -506,7 +506,34 @@ class Commands:
                """Decrypt a message encrypted with a public key."""
                return self.wallet.decrypt_message(pubkey, encrypted, self.password)
        
       +    @command('w')
       +    def listrequests(self):
       +        """List the payment requests you made"""
       +        out = []
       +        for addr, v in self.wallet.receive_requests.items():
       +            out.append({
       +                'address': addr,
       +                'amount': format_satoshis(v.get('amount')),
       +                'time': v.get('time'),
       +                'reason': self.wallet.get_label(addr)[0],
       +                'expiration': v.get('expiration'),
       +            })
       +        return out
        
       +    @command('w')
       +    def addrequest(self, amount, reason='', expiration=60*60):
       +        """Create a payment request"""
       +        addr = self.wallet.get_unused_address(None)
       +        if addr is None:
       +            return False
       +        amount = int(Decimal(amount)*COIN)
       +        self.wallet.save_payment_request(addr, amount, reason, expiration)
       +        return addr
       +
       +    @command('w')
       +    def removerequest(self, address):
       +        """Remove a payment request"""
       +        return self.wallet.remove_payment_request(address)
        
        param_descriptions = {
            'privkey': 'Private key. Type \'?\' to get a prompt.',
       t@@ -548,6 +575,8 @@ command_options = {
            'unsigned':    ("-u", "--unsigned",    "Do not sign transaction"),
            'domain':      ("-D", "--domain",      "List of addresses"),
            'account':     (None, "--account",     "Account"),
       +    'reason':      (None, "--reason",      "Description of the request"),
       +    'expiration':  (None, "--expiration",  "Time in seconds"),
        }
        
        
 (DIR) diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -164,6 +164,9 @@ class Abstract_Wallet(object):
                self.load_accounts()
                self.load_transactions()
        
       +        # load requests
       +        self.receive_requests = self.storage.get('receive_requests2', {})
       +
                # spv
                self.verifier = None
                # Transactions pending verification.  Each value is the transaction height.  Access with self.lock.
       t@@ -1221,6 +1224,43 @@ class Abstract_Wallet(object):
            def can_change_password(self):
                return not self.is_watching_only()
        
       +    def get_unused_address(self, account):
       +        # fixme: use slots from expired requests
       +        domain = self.get_account_addresses(account, include_change=False)
       +        for addr in domain:
       +            if not self.history.get(addr) and addr not in self.receive_requests.keys():
       +                return addr
       +
       +    def remove_payment_request(self, addr):
       +        if addr not in self.receive_requests:
       +            return False
       +        self.receive_requests.pop(addr)
       +        self.storage.put('receive_requests2', self.receive_requests)
       +        return True
       +
       +    def save_payment_request(self, addr, amount, message, expiration):
       +        self.set_label(addr, message)
       +        if addr in self.receive_requests:
       +            self.receive_requests[addr]['amount'] = amount
       +        else:
       +            now = int(time.time())
       +            self.receive_requests[addr] = {'time':now, 'amount':amount, 'expiration':expiration}
       +        self.storage.put('receive_requests2', self.receive_requests, True)
       +
       +    def make_bip70_request(self, config, addr):
       +        from paymentrequest import make_payment_request
       +        req = self.receive_requests[addr]
       +        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_key_path')
       +        cert_path = config.get('ssl_cert_path')
       +        return make_payment_request(outputs, message, time, time + expiration, key_path, cert_path)
       +
       +
        class Imported_Wallet(Abstract_Wallet):
            wallet_type = 'imported'