tSize dependent tx fee. Allow user to override the tx fee - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 53b74689a1b44f1a793730d67d0d62d29a4487c3 DIR parent 72aefa7c1600845c4703bc8c615703b664fb22c5 HTML Author: thomasv <thomasv@gitorious> Date: Wed, 7 Dec 2011 18:54:32 +0100 Size dependent tx fee. Allow user to override the tx fee Diffstat: M client/electrum.py | 23 ++++++++++++++--------- M client/gui.py | 104 ++++++++++++++++++++++++------- 2 files changed, 94 insertions(+), 33 deletions(-) --- DIR diff --git a/client/electrum.py b/client/electrum.py t@@ -491,9 +491,8 @@ class Wallet: else: return False - def choose_inputs_outputs( self, to_addr, amount, fee, password): + def choose_tx_inputs( self, amount, fixed_fee ): """ todo: minimize tx size """ - total = 0 inputs = [] for addr in self.addresses: t@@ -503,11 +502,18 @@ class Wallet: v = item.get('value') total += v inputs.append((addr, v, item['tx_hash'], item['pos'], item['raw_scriptPubKey'], None, None) ) + if fixed_fee is not None: + fee = fixed_fee + else: + fee = self.fee * len(inputs) if total >= amount + fee: break if total >= amount + fee: break else: - print "not enough funds: %d %d"%(total, fee) - return False, "not enough funds: %d %d"%(total, fee) + #print "not enough funds: %d %d"%(total, fee) + inputs = [] + return inputs, total, fee + + def choose_tx_outputs( self, to_addr, amount, fee, total, password ): outputs = [ (to_addr, amount) ] change_amount = total - ( amount + fee ) if change_amount != 0: t@@ -522,7 +528,7 @@ class Wallet: change_address = self.create_new_address(True, password) print "new change address", change_address outputs.append( (change_address, change_amount) ) - return inputs, outputs + return outputs def sign_inputs( self, inputs, outputs, password ): s_inputs = [] t@@ -611,11 +617,10 @@ class Wallet: def mktx(self, to_address, amount, label, password, fee=None): if not self.is_valid(to_address): return False, "Invalid address" - if fee is None: fee = self.fee try: - inputs, outputs = wallet.choose_inputs_outputs( to_address, amount, fee, password ) - if not inputs: - return False, "Not enough funds" + inputs, total, fee = wallet.choose_tx_inputs( amount, fee ) + if not inputs: return False, "Not enough funds %d %d"%(total, fee) + outputs = wallet.choose_tx_outputs( to_address, amount, fee, total, password ) s_inputs = wallet.sign_inputs( inputs, outputs, password ) except InvalidPassword: return False, "Wrong password" DIR diff --git a/client/gui.py b/client/gui.py t@@ -41,6 +41,17 @@ def numbify(entry, is_int = False): s = ''.join([i for i in text if i in '0123456789.']) entry.set_text(s) + #entry.set_text( str( Decimal( amount ) / 100000000 ) ) + + if not is_int: + try: + amount = int( Decimal(entry.get_text()) * 100000000 ) + except: + amount = 0 + return amount + + + def show_seed_dialog(wallet, password, parent): import mnemonic t@@ -208,7 +219,7 @@ def run_settings_dialog(wallet, is_create, is_recovery, parent): fee_entry.connect('changed', numbify, False) fee_entry.show() fee.pack_start(fee_entry,False,False, 10) - add_help_button(fee, 'Transaction fee. Recommended value:0.005. Note that this fee is per transaction, not per kilobyte. Size-dependent fees still need to be implemented.') + add_help_button(fee, 'Fee per transaction input. Transactions involving multiple inputs tend to have a higher fee. Recommended value:0.0005') fee.show() vbox.pack_start(fee, False,False, 5) t@@ -266,9 +277,9 @@ def run_settings_dialog(wallet, is_create, is_recovery, parent): -def show_message(message): +def show_message(message, parent=None): dialog = gtk.MessageDialog( - parent = None, + parent = parent, flags = gtk.DIALOG_MODAL, buttons = gtk.BUTTONS_CLOSE, message_format = message ) t@@ -373,6 +384,9 @@ gtk.binding_entry_add_signal(MyWindow, gtk.keysyms.Q, gtk.gdk.CONTROL_MASK, 'myk class BitcoinGUI: + def show_message(self, msg): + show_message(msg, self.window) + def __init__(self, wallet): self.error = '' self.is_connected = False t@@ -384,7 +398,7 @@ class BitcoinGUI: self.window.connect("destroy", gtk.main_quit) self.window.set_border_width(0) self.window.connect('mykeypress', gtk.main_quit) - self.window.set_default_size(670, 350) + self.window.set_default_size(720, 350) vbox = gtk.VBox() t@@ -453,6 +467,7 @@ class BitcoinGUI: self.window.add(vbox) self.window.show_all() + self.fee_box.hide() self.context_id = self.status_bar.get_context_id("statusbar") self.update_status_bar() t@@ -539,22 +554,56 @@ class BitcoinGUI: label.pack_start(label_entry, False) vbox.pack_start(label, False, False, 5) - amount = gtk.HBox() + amount_box = gtk.HBox() amount_label = gtk.Label('Amount:') - amount_label.set_size_request(100,10) + amount_label.set_size_request(100,-1) amount_label.show() - amount.pack_start(amount_label, False) + amount_box.pack_start(amount_label, False) amount_entry = gtk.Entry() - amount_entry.set_size_request(100, 26) - amount_entry.connect('changed', numbify) + amount_entry.set_size_request(120, -1) amount_entry.show() - amount.pack_start(amount_entry, False) - vbox.pack_start(amount, False, False, 5) + amount_box.pack_start(amount_entry, False) + vbox.pack_start(amount_box, False, False, 5) - button = gtk.Button("Send") - button.connect("clicked", self.do_send, (payto_entry, label_entry, amount_entry)) - button.show() - amount.pack_start(button, False, False, 5) + send_button = gtk.Button("Send") + send_button.show() + amount_box.pack_start(send_button, False, False, 5) + + self.fee_box = fee_box = gtk.HBox() + fee_label = gtk.Label('Fee:') + fee_label.set_size_request(100,10) + fee_box.pack_start(fee_label, False) + fee_entry = gtk.Entry() + fee_entry.set_size_request(120, 26) + fee_entry.set_has_frame(False) + fee_entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("#eeeeee")) + fee_box.pack_start(fee_entry, False) + + send_button.connect("clicked", self.do_send, (payto_entry, label_entry, amount_entry, fee_entry)) + vbox.pack_start(fee_box, False, False, 5) + + self.user_fee = False + + def entry_changed( entry, is_fee ): + amount = numbify(amount_entry) + fee = numbify(fee_entry) + if not is_fee: fee = None + inputs, total, fee = self.wallet.choose_tx_inputs( amount, fee ) + if not is_fee: + fee_entry.set_text( str( Decimal( fee ) / 100000000 ) ) + self.fee_box.show() + if inputs: + amount_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) + fee_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) + send_button.set_sensitive(True) + else: + send_button.set_sensitive(False) + amount_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cc0000")) + fee_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cc0000")) + self.error = 'Not enough funds' + + amount_entry.connect('changed', entry_changed, False) + fee_entry.connect('changed', entry_changed, True) self.payto_entry = payto_entry self.payto_amount_entry = amount_entry t@@ -575,38 +624,45 @@ class BitcoinGUI: self.add_tab(page, 'Wall') def do_send(self, w, data): - payto_entry, label_entry, amount_entry = data + payto_entry, label_entry, amount_entry, fee_entry = data label = label_entry.get_text() to_address = payto_entry.get_text() if not self.wallet.is_valid(to_address): - show_message( "invalid bitcoin address" ) + self.show_message( "invalid bitcoin address") return try: amount = int( Decimal(amount_entry.get_text()) * 100000000 ) except: - show_message( "invalid amount" ) + self.show_message( "invalid amount") + return + try: + fee = int( Decimal(fee_entry.get_text()) * 100000000 ) + except: + self.show_message( "invalid fee") return password = password_dialog() if self.wallet.use_encryption else None - status, tx = self.wallet.mktx( to_address, amount, label, password ) + status, tx = self.wallet.mktx( to_address, amount, label, password, fee ) self.wallet.new_session() # we created a new change address if not status: - show_message(tx) + self.show_message(tx) return status, msg = self.wallet.sendtx( tx ) if status: - show_message( "payment sent.\n" + msg ) + self.show_message( "payment sent.\n" + msg ) payto_entry.set_text("") label_entry.set_text("") amount_entry.set_text("") + fee_entry.set_text("") + self.fee_box.hide() self.update_sending_tab() else: - show_message( msg ) + self.show_message( msg ) def treeview_key_press(self, treeview, event): t@@ -617,7 +673,7 @@ class BitcoinGUI: treeview.set_cursor((0,)) elif event.keyval == gtk.keysyms.Return and treeview == self.history_treeview: tx_details = self.history_list.get_value( self.history_list.get_iter(c), 8) - show_message(tx_details) + self.show_message(tx_details) return False def create_history_tab(self): t@@ -1031,7 +1087,7 @@ class BitcoinGUI: host = hh port = 50000 except: - show_message("error") + self.show_message("error") return if host!= wallet.host or port!=wallet.port: