2013-09-14 12:07:54 -07:00
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2012 thomasv@gitorious
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 sys , time , datetime , re , threading
from electrum . i18n import _ , set_language
from electrum . util import print_error , print_msg
import os . path , json , ast , traceback
import shutil
import StringIO
try :
import PyQt4
2013-11-10 12:30:57 -08:00
except Exception :
2013-09-14 12:07:54 -07:00
sys . exit ( " Error: Could not import PyQt4 on Linux systems, you may try ' sudo apt-get install python-qt4 ' " )
from PyQt4 . QtGui import *
from PyQt4 . QtCore import *
import PyQt4 . QtCore as QtCore
from electrum import transaction
2015-02-26 04:59:29 -08:00
from electrum . bitcoin import base_encode
2014-06-12 13:24:10 -07:00
from electrum . plugins import run_hook
2015-03-14 11:08:56 -07:00
from util import *
2013-09-14 12:07:54 -07:00
class TxDialog ( QDialog ) :
def __init__ ( self , tx , parent ) :
self . tx = tx
tx_dict = tx . as_dict ( )
self . parent = parent
self . wallet = parent . wallet
2015-03-25 02:46:15 -07:00
self . saved = True
2014-10-21 10:05:51 -07:00
2013-09-14 12:07:54 -07:00
QDialog . __init__ ( self )
self . setMinimumWidth ( 600 )
2013-09-16 20:19:23 -07:00
self . setWindowTitle ( _ ( " Transaction " ) )
2013-09-14 12:07:54 -07:00
self . setModal ( 1 )
vbox = QVBoxLayout ( )
self . setLayout ( vbox )
2013-09-16 20:19:23 -07:00
vbox . addWidget ( QLabel ( _ ( " Transaction ID: " ) ) )
2015-04-20 02:49:27 -07:00
self . tx_hash_e = ButtonsLineEdit ( )
qr_show = lambda : self . parent . show_qrcode ( str ( self . tx_hash_e . text ( ) ) , ' Transaction ID ' )
self . tx_hash_e . addButton ( " :icons/qrcode.png " , qr_show , _ ( " Show as QR code " ) )
2013-09-14 12:07:54 -07:00
self . tx_hash_e . setReadOnly ( True )
vbox . addWidget ( self . tx_hash_e )
self . status_label = QLabel ( )
vbox . addWidget ( self . status_label )
self . date_label = QLabel ( )
vbox . addWidget ( self . date_label )
self . amount_label = QLabel ( )
vbox . addWidget ( self . amount_label )
self . fee_label = QLabel ( )
vbox . addWidget ( self . fee_label )
2013-09-15 04:29:09 -07:00
self . add_io ( vbox )
2013-09-15 02:41:06 -07:00
vbox . addStretch ( 1 )
2013-09-14 12:07:54 -07:00
self . sign_button = b = QPushButton ( _ ( " Sign " ) )
b . clicked . connect ( self . sign )
self . broadcast_button = b = QPushButton ( _ ( " Broadcast " ) )
2015-03-25 02:46:15 -07:00
b . clicked . connect ( self . do_broadcast )
2013-09-14 12:07:54 -07:00
b . hide ( )
self . save_button = b = QPushButton ( _ ( " Save " ) )
b . clicked . connect ( self . save )
2015-03-14 11:08:56 -07:00
self . cancel_button = b = QPushButton ( _ ( " Close " ) )
2015-03-25 02:46:15 -07:00
b . clicked . connect ( self . close )
2015-03-14 11:08:56 -07:00
b . setDefault ( True )
2014-06-12 13:24:10 -07:00
2015-03-14 11:08:56 -07:00
self . qr_button = b = QPushButton ( )
2014-06-23 00:42:07 -07:00
b . setIcon ( QIcon ( " :icons/qrcode.png " ) )
2014-06-17 07:24:01 -07:00
b . clicked . connect ( self . show_qr )
2013-09-14 12:07:54 -07:00
2015-04-20 05:44:59 -07:00
self . copy_button = CopyButton ( lambda : str ( self . tx ) , self . parent . app )
self . buttons = [ self . copy_button , self . qr_button , self . sign_button , self . broadcast_button , self . save_button , self . cancel_button ]
2014-06-20 02:55:34 -07:00
run_hook ( ' transaction_dialog ' , self )
2014-10-21 10:05:51 -07:00
2015-03-14 11:08:56 -07:00
vbox . addLayout ( Buttons ( * self . buttons ) )
2014-06-24 05:48:15 -07:00
self . update ( )
2014-06-20 02:55:34 -07:00
2015-03-25 02:46:15 -07:00
def do_broadcast ( self ) :
self . parent . broadcast_transaction ( self . tx )
self . saved = True
def close ( self ) :
if not self . saved :
if QMessageBox . question ( self , _ ( ' Message ' ) , _ ( ' This transaction is not saved. Close anyway? ' ) , QMessageBox . Yes | QMessageBox . No , QMessageBox . No ) == QMessageBox . No :
return
self . done ( 0 )
2013-09-14 12:07:54 -07:00
2014-06-17 07:24:01 -07:00
def show_qr ( self ) :
2014-06-21 12:06:09 -07:00
text = self . tx . raw . decode ( ' hex ' )
2015-02-26 04:59:29 -08:00
text = base_encode ( text , base = 43 )
2014-06-17 07:24:01 -07:00
try :
2014-06-21 12:06:09 -07:00
self . parent . show_qrcode ( text , ' Transaction ' )
2014-06-17 07:24:01 -07:00
except Exception as e :
2014-06-19 00:42:19 -07:00
self . show_message ( str ( e ) )
2013-09-14 12:07:54 -07:00
def sign ( self ) :
2014-06-21 12:06:09 -07:00
self . parent . sign_raw_transaction ( self . tx )
2013-09-14 12:07:54 -07:00
self . update ( )
def save ( self ) :
2014-05-21 02:36:37 -07:00
name = ' signed_ %s .txn ' % ( self . tx . hash ( ) [ 0 : 8 ] ) if self . tx . is_complete ( ) else ' unsigned.txn '
2013-11-12 02:14:16 -08:00
fileName = self . parent . getSaveFileName ( _ ( " Select where to save your signed transaction " ) , name , " *.txn " )
2013-09-14 12:07:54 -07:00
if fileName :
with open ( fileName , " w+ " ) as f :
f . write ( json . dumps ( self . tx . as_dict ( ) , indent = 4 ) + ' \n ' )
self . show_message ( _ ( " Transaction saved successfully " ) )
2015-03-25 02:46:15 -07:00
self . saved = True
2013-09-14 12:07:54 -07:00
2013-09-15 04:29:09 -07:00
2013-09-14 12:07:54 -07:00
def update ( self ) :
2015-03-20 14:37:06 -07:00
is_relevant , is_mine , v , fee = self . wallet . get_wallet_delta ( self . tx )
tx_hash = self . tx . hash ( )
2014-06-24 04:22:10 -07:00
if self . wallet . can_sign ( self . tx ) :
self . sign_button . show ( )
else :
self . sign_button . hide ( )
2013-09-14 12:07:54 -07:00
2014-05-21 02:36:37 -07:00
if self . tx . is_complete ( ) :
2014-06-22 03:07:41 -07:00
status = _ ( " Signed " )
2013-09-14 12:07:54 -07:00
if tx_hash in self . wallet . transactions . keys ( ) :
conf , timestamp = self . wallet . verifier . get_confirmations ( tx_hash )
if timestamp :
time_str = datetime . datetime . fromtimestamp ( timestamp ) . isoformat ( ' ' ) [ : - 3 ]
else :
time_str = ' pending '
2014-06-22 03:07:41 -07:00
status = _ ( " %d confirmations " ) % conf
2013-09-14 12:07:54 -07:00
self . broadcast_button . hide ( )
else :
time_str = None
conf = 0
self . broadcast_button . show ( )
else :
2014-06-22 03:07:41 -07:00
s , r = self . tx . signature_count ( )
2015-02-02 10:17:08 -08:00
status = _ ( " Unsigned " ) if s == 0 else _ ( ' Partially signed ' ) + ' ( %d / %d ) ' % ( s , r )
2013-09-14 12:07:54 -07:00
time_str = None
self . broadcast_button . hide ( )
2013-11-12 02:14:16 -08:00
tx_hash = ' unknown '
2013-09-14 12:07:54 -07:00
self . tx_hash_e . setText ( tx_hash )
2014-06-22 03:07:41 -07:00
self . status_label . setText ( _ ( ' Status: ' ) + ' ' + status )
2013-09-14 12:07:54 -07:00
if time_str is not None :
2013-09-16 20:19:23 -07:00
self . date_label . setText ( _ ( " Date: %s " ) % time_str )
2013-09-14 12:07:54 -07:00
self . date_label . show ( )
else :
self . date_label . hide ( )
2014-03-15 02:01:25 -07:00
# if we are not synchronized, we cannot tell
if self . parent . network is None or not self . parent . network . is_running ( ) or not self . parent . network . is_connected ( ) :
return
if not self . wallet . up_to_date :
return
2014-10-21 10:05:51 -07:00
if is_relevant :
2013-09-14 12:07:54 -07:00
if is_mine :
2014-10-21 10:05:51 -07:00
if fee is not None :
2015-03-20 14:37:06 -07:00
self . amount_label . setText ( _ ( " Amount sent: " ) + ' %s ' % self . parent . format_amount ( - v + fee ) + ' ' + self . parent . base_unit ( ) )
self . fee_label . setText ( _ ( " Transaction fee " ) + ' : %s ' % self . parent . format_amount ( - fee ) + ' ' + self . parent . base_unit ( ) )
2013-09-14 12:07:54 -07:00
else :
2015-03-20 14:37:06 -07:00
self . amount_label . setText ( _ ( " Amount sent: " ) + ' %s ' % self . parent . format_amount ( - v ) + ' ' + self . parent . base_unit ( ) )
2013-11-05 15:24:58 -08:00
self . fee_label . setText ( _ ( " Transaction fee " ) + ' : ' + _ ( " unknown " ) )
2013-09-14 12:07:54 -07:00
else :
2013-09-16 20:19:23 -07:00
self . amount_label . setText ( _ ( " Amount received: " ) + ' %s ' % self . parent . format_amount ( v ) + ' ' + self . parent . base_unit ( ) )
2013-09-14 12:07:54 -07:00
else :
2013-09-16 20:19:23 -07:00
self . amount_label . setText ( _ ( " Transaction unrelated to your wallet " ) )
2013-09-14 12:07:54 -07:00
2014-06-24 05:48:15 -07:00
run_hook ( ' transaction_dialog_update ' , self )
2013-09-14 12:07:54 -07:00
2013-09-15 04:29:09 -07:00
def add_io ( self , vbox ) :
2013-09-14 12:07:54 -07:00
2014-03-05 13:04:31 -08:00
if self . tx . locktime > 0 :
vbox . addWidget ( QLabel ( " LockTime: %d \n " % self . tx . locktime ) )
2013-09-15 04:29:09 -07:00
vbox . addWidget ( QLabel ( _ ( " Inputs " ) ) )
2015-03-28 12:26:30 -07:00
ext = QTextCharFormat ( )
own = QTextCharFormat ( )
own . setBackground ( QBrush ( QColor ( " lightgreen " ) ) )
own . setToolTip ( _ ( " Own address " ) )
2014-03-02 09:11:56 -08:00
i_text = QTextEdit ( )
2014-10-23 07:45:51 -07:00
i_text . setFont ( QFont ( MONOSPACE_FONT ) )
2013-09-15 04:29:09 -07:00
i_text . setReadOnly ( True )
i_text . setMaximumHeight ( 100 )
2015-03-28 12:26:30 -07:00
cursor = i_text . textCursor ( )
for x in self . tx . inputs :
if x . get ( ' is_coinbase ' ) :
cursor . insertText ( ' coinbase ' )
else :
2015-03-28 12:53:49 -07:00
prevout_hash = x . get ( ' prevout_hash ' )
prevout_n = x . get ( ' prevout_n ' )
cursor . insertText ( prevout_hash [ 0 : 8 ] + ' ... ' + prevout_hash [ - 8 : ] + " : %d " % prevout_n , ext )
2015-03-28 12:26:30 -07:00
cursor . insertText ( ' \t ' )
addr = x . get ( ' address ' )
2015-03-28 12:53:49 -07:00
if addr == " (pubkey) " :
_addr = self . wallet . find_pay_to_pubkey_address ( prevout_hash , prevout_n )
if _addr :
addr = _addr
2015-03-28 12:26:30 -07:00
cursor . insertText ( addr , own if self . wallet . is_mine ( addr ) else ext )
cursor . insertBlock ( )
2013-09-14 12:07:54 -07:00
2015-03-28 12:26:30 -07:00
vbox . addWidget ( i_text )
2013-09-15 04:29:09 -07:00
vbox . addWidget ( QLabel ( _ ( " Outputs " ) ) )
o_text = QTextEdit ( )
2014-10-23 07:45:51 -07:00
o_text . setFont ( QFont ( MONOSPACE_FONT ) )
2013-09-15 04:29:09 -07:00
o_text . setReadOnly ( True )
o_text . setMaximumHeight ( 100 )
2015-03-28 12:26:30 -07:00
cursor = o_text . textCursor ( )
for addr , v in self . tx . get_outputs ( ) :
cursor . insertText ( addr , own if self . wallet . is_mine ( addr ) else ext )
if v is not None :
cursor . insertText ( ' \t ' , ext )
cursor . insertText ( self . parent . format_amount ( v ) , ext )
cursor . insertBlock ( )
2013-09-15 04:29:09 -07:00
vbox . addWidget ( o_text )
2013-09-14 12:07:54 -07:00
2014-10-21 10:05:51 -07:00
2013-09-14 12:07:54 -07:00
def show_message ( self , msg ) :
QMessageBox . information ( self , _ ( ' Message ' ) , msg , _ ( ' OK ' ) )