diff --git a/ArmoryQt.py b/ArmoryQt.py
index abdfb12f8..ad7892ead 100644
--- a/ArmoryQt.py
+++ b/ArmoryQt.py
@@ -1315,6 +1315,8 @@ def execImportWallet(self):
print 'The highest index used was:', highestIdx
self.addWalletToApplication(dlgPaper.newWallet, walletIsNew=False)
print 'Import Complete!'
+ elif dlg.importType_migrate:
+ DlgMigrateSatoshiWallet(self, self).exec_()
else:
return
diff --git a/armoryengine.py b/armoryengine.py
index 95450feb2..977cc867f 100644
--- a/armoryengine.py
+++ b/armoryengine.py
@@ -7195,7 +7195,7 @@ def deleteImportedAddress(self, addr160):
def importExternalAddressData(self, privKey=None, privChk=None, \
pubKey=None, pubChk=None, \
addr20=None, addrChk=None, \
- firstTime=0, firstBlk=0, \
+ firstTime=UINT32_MAX, firstBlk=UINT32_MAX, \
lastTime=0, lastBlk=0):
"""
This wallet fully supports importing external keys, even though it is
@@ -8939,7 +8939,6 @@ def castVal(v):
import json
import struct
-
class BCDataStream(object):
def __init__(self):
self.input = None
@@ -9096,14 +9095,9 @@ def GetKeyFromPassphraseSatoshi(vKeyData, vSalt, nIter, deriveMethod):
################################################################################
-def read_wallet(json_db, db_env, wltFile):
+def read_wallet(db_env, wltFile):
db = open_wallet(db_env, wltFile)
- json_db['keys'] = []
- json_db['pool'] = []
- json_db['names'] = {}
-
-
# Moved parse_wallet code inline here
kds = BCDataStream()
vds = BCDataStream()
@@ -9112,6 +9106,7 @@ def read_wallet(json_db, db_env, wltFile):
cryptPrivList = []
masterEncrKey = {}
poolKeysList = []
+ addrNames = {}
for (key, value) in db.items():
d = { }
@@ -9129,8 +9124,6 @@ def read_wallet(json_db, db_env, wltFile):
try:
- # This is a weird merge of two if-then-else blocks...
- # It didn't seem to be necessary to keep them separate
if dType == "key":
priv = SecureBinaryData(vds.read_bytes(vds.read_compact_size())[9:9+32])
plainPrivList.append(priv)
@@ -9138,27 +9131,23 @@ def read_wallet(json_db, db_env, wltFile):
pub = kds.read_bytes(kds.read_compact_size())
ckey = vds.read_bytes(vds.read_compact_size())
cryptPrivList.append( [pub, ckey] )
-
elif dType == "mkey":
masterEncrKey['mkey'] = vds.read_bytes(vds.read_compact_size())
masterEncrKey['salt'] = vds.read_bytes(vds.read_compact_size())
masterEncrKey['mthd'] = vds.read_int32()
masterEncrKey['iter'] = vds.read_int32()
masterEncrKey['othr'] = vds.read_bytes(vds.read_compact_size())
-
- print len(masterEncrKey['mkey'])
- print len(masterEncrKey['salt'])
- print len(masterEncrKey['othr'])
-
elif dType == "pool":
d['n'] = kds.read_int64()
ver = vds.read_int32()
ntime = vds.read_int64()
pubkey = vds.read_bytes(vds.read_compact_size())
poolKeysList.append(pubkey_to_addrStr(pubkey))
-
+ elif dType == "name":
+ addrB58 = kds.read_string()
+ name = vds.read_string()
+ addrNames[addrB58] = name
except Exception, e:
- #traceback.print_exc()
print("ERROR parsing wallet.dat, type %s" % dType)
print("key data in hex: %s"%key.encode('hex_codec'))
print("value data in hex: %s"%value.encode('hex_codec'))
@@ -9166,34 +9155,23 @@ def read_wallet(json_db, db_env, wltFile):
db.close()
- return (plainPrivList, masterEncrKey, cryptPrivList, poolKeysList)
-
-
-
-def checkSatoshiEncrypted(wltPath):
- if not os.path.exists(wltPath):
- raise FileExistsError, 'Specified Satoshi wallet does not exist!'
+ return (plainPrivList, masterEncrKey, cryptPrivList, poolKeysList, addrNames)
- wltDir,wltFile = os.path.split(wltPath)
- db_env = create_env(wltDir)
- json_db = {}
- plain,mkey,crypt,pool = read_wallet(json_db, db_env, wltFile)
- return len(crypt)>0
def extractSatoshiKeys(wltPath, passphrase=None):
+ # Returns a list of [privKey, usedYet] pairs
if not os.path.exists(wltPath):
raise FileExistsError, 'Specified Satoshi wallet does not exist!'
wltDir,wltFile = os.path.split(wltPath)
db_env = create_env(wltDir)
- json_db = {}
- plainkeys,mkey,crypt,pool = read_wallet(json_db, db_env, wltFile)
+ plainkeys,mkey,crypt,pool,names = read_wallet(db_env, wltFile)
if len(crypt)>0:
# Satoshi Wallet is encrypted!
@@ -9209,22 +9187,38 @@ def extractSatoshiKeys(wltPath, passphrase=None):
masterKey = CryptoAES().DecryptCBC( SecureBinaryData(mkey['mkey']), \
SecureBinaryData(pKey), \
SecureBinaryData(IV) )
-
- print masterKey.toHexStr()
masterKey.resize(32)
+ checkedCorrectPassphrase = False
for pub,ckey in crypt:
iv = hash256(pub)[:16]
privKey = CryptoAES().DecryptCBC( SecureBinaryData(ckey), \
SecureBinaryData(masterKey), \
SecureBinaryData(iv))
privKey.resize(32)
+ if not checkedCorrectPassphrase:
+ checkedCorrectPassphrase = True
+ if not CryptoECDSA().CheckPubPrivKeyMatch(privKey, SecureBinaryData(pub)):
+ raise EncryptionError, 'Incorrect Passphrase!'
plainkeys.append(privKey)
- return plainkeys
+ outputList = []
+ for key in plainkeys:
+ addr = hash160_to_addrStr(convertKeyDataToAddress(key.toBinStr()))
+ strName = ''
+ if names.has_key(addr):
+ strName = names[addr]
+ outputList.append( [addr, key, (not addr in pool), strName] )
+ return outputList
+def checkSatoshiEncrypted(wltPath):
+ try:
+ extractSatoshiKeys(wltPath, '')
+ return False
+ except EncryptionError:
+ return True
diff --git a/qtdialogs.py b/qtdialogs.py
index a94a1d2cb..b59383608 100755
--- a/qtdialogs.py
+++ b/qtdialogs.py
@@ -23,7 +23,6 @@ def __init__(self, wlt, parent=None, main=None, unlockMsg='Unlock Wallet'):
self.edtPasswd = QLineEdit()
self.edtPasswd.setEchoMode(QLineEdit.Password)
self.edtPasswd.setMinimumWidth(MIN_PASSWD_WIDTH(self))
- fm = QFontMetricsF(QFont(self.font()))
self.edtPasswd.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
self.btnAccept = QPushButton("Unlock")
@@ -55,6 +54,38 @@ def acceptPassphrase(self):
return
+################################################################################
+class DlgGenericGetPassword(QDialog):
+ def __init__(self, wlt, descriptionStr, parent=None, main=None):
+ super(DlgUnlockWallet, self).__init__(parent)
+
+ self.parent = parent
+ self.main = main
+
+ lblDescr = QRichLabel(descriptionStr)
+ lblPasswd = QRichLabel("Password:")
+ self.edtPasswd = QLineEdit()
+ self.edtPasswd.setEchoMode(QLineEdit.Password)
+ self.edtPasswd.setMinimumWidth(MIN_PASSWD_WIDTH(self))
+ self.edtPasswd.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
+
+ self.btnAccept = QPushButton("OK")
+ self.btnCancel = QPushButton("Cancel")
+ self.connect(self.btnAccept, SIGNAL('clicked()'), self.accept)
+ self.connect(self.btnCancel, SIGNAL('clicked()'), self.reject)
+ buttonBox = QDialogButtonBox()
+ buttonBox.addButton(self.btnAccept, QDialogButtonBox.AcceptRole)
+ buttonBox.addButton(self.btnCancel, QDialogButtonBox.RejectRole)
+
+ layout = QGridLayout()
+ layout.addWidget(lblDescr, 1, 0, 1, 2)
+ layout.addWidget(lblPasswd, 2, 0, 1, 1)
+ layout.addWidget(self.edtPasswd, 2, 1, 1, 1)
+ layout.addWidget(buttonBox, 3, 1, 1, 2)
+
+ self.setLayout(layout)
+ self.setWindowTitle('Enter Password')
+ self.setWindowIcon(QIcon(self.main.iconfile))
################################################################################
@@ -479,7 +510,6 @@ def __init__(self, currName='', currDescr='', parent=None, main=None):
self.edtDescr = QTextEdit()
tightHeight = tightSizeNChar(self.edtDescr, 1)[1]
- #fm = QFontMetricsF(QFont(self.edtDescr.font()))
self.edtDescr.setMaximumHeight(tightHeight*4.2)
lblDescr = QLabel("Wallet &description:")
lblDescr.setAlignment(Qt.AlignVCenter)
@@ -1493,13 +1523,24 @@ def __init__(self, wlt, parent=None, main=None):
## Import option
- self.radioSweep = QRadioButton('Sweep any funds owned by this address '
- 'into your wallet\n'
- 'Select this option if someone else gave you this key')
self.radioImport = QRadioButton('Import this address to your wallet\n'
'Only select this option if you are positive '
'that no one else has access to this key')
+ ## Sweep option (only available when online)
+ if self.main.isOnline:
+ self.radioSweep = QRadioButton('Sweep any funds owned by this address '
+ 'into your wallet\n'
+ 'Select this option if someone else gave you this key')
+ self.radioSweep.setChecked(True)
+ else:
+ self.radioSweep = QRadioButton('Sweep any funds owned by this address '
+ 'into your wallet\n'
+ '(Not available in offline mode)')
+ self.radioImport.setChecked(True)
+ self.radioSweep.setEnabled(False)
+
+
sweepTooltip = createToolTipObject( \
'You should never add an untrusted key to your wallet. By choosing this '
'option, you are only moving the funds into your wallet, but not the key '
@@ -1516,7 +1557,7 @@ def __init__(self, wlt, parent=None, main=None):
btngrp.addButton(self.radioSweep)
btngrp.addButton(self.radioImport)
btngrp.setExclusive(True)
- self.radioSweep.setChecked(True)
+
frmWarn = QFrame()
@@ -1708,6 +1749,7 @@ def processUserString(self):
+#############################################################################
class DlgVerifySweep(QDialog):
def __init__(self, inputStr, outputStr, outVal, fee, parent=None, main=None):
super(DlgVerifySweep, self).__init__(parent)
@@ -1763,6 +1805,7 @@ def __init__(self, parent=None, main=None):
lblImportDescr = QLabel('Chose the wallet import source:')
self.btnImportFile = QPushButton("Import from &file")
self.btnImportPaper = QPushButton("Import from &paper backup")
+ self.btnMigrate = QPushButton("Import wallet.dat from main Bitcoin client")
self.btnImportFile.setMinimumWidth(300)
@@ -1772,6 +1815,9 @@ def __init__(self, parent=None, main=None):
self.connect( self.btnImportPaper, SIGNAL('clicked()'), \
self.acceptPaper)
+ self.connect( self.btnMigrate, SIGNAL('clicked()'), \
+ self.acceptMigrate)
+
ttip1 = createToolTipObject('Import an existing Armory wallet, usually with a '
'*.wallet extension. Any wallet that you import will '
'be copied into your settings directory, and maintained '
@@ -1781,6 +1827,9 @@ def __init__(self, parent=None, main=None):
'a wallet, you can manually enter the wallet '
'data into Armory to recover the wallet.')
+ ttip3 = createToolTipObject('Migrate all your wallet.dat addresses '
+ 'from the regular Bitcoin client to an Armory '
+ 'wallet.')
w,h = relaxedSizeStr(ttip1, '(?)')
for ttip in (ttip1, ttip2):
@@ -1792,6 +1841,7 @@ def __init__(self, parent=None, main=None):
layout.addWidget(lblImportDescr, 0,0, 1, 2)
layout.addWidget(self.btnImportFile, 1,0, 1, 2); layout.addWidget(ttip1, 1,2,1,1)
layout.addWidget(self.btnImportPaper, 2,0, 1, 2); layout.addWidget(ttip2, 2,2,1,1)
+ layout.addWidget(self.btnMigrate, 3,0, 1, 2); layout.addWidget(ttip3, 3,2,1,1)
if self.main.usermode in (USERMODE.Advanced, USERMODE.Developer):
lbl = QLabel('You can manually add wallets to armory by copying them '
@@ -1829,10 +1879,295 @@ def acceptPaper(self):
We will accept this dialog but signal to the caller that paper-import
was selected so that it can open the dialog for itself
"""
- self.importType_file = False
- self.importType_paper = True
+ self.importType_file = False
+ self.importType_paper = True
+ self.importType_migrate = False
self.accept()
+ def acceptMigrate(self):
+ self.importType_file = False
+ self.importType_paper = False
+ self.importType_migrate = True
+ self.accept()
+
+#############################################################################
+class DlgMigrateSatoshiWallet(QDialog):
+ def __init__(self, parent=None, main=None):
+ super(DlgMigrateSatoshiWallet, self).__init__(parent)
+
+ self.parent = parent
+ self.main = main
+
+ lblDescr = QRichLabel( \
+ 'Specify the location of your regular Bitcoin wallet (wallet.dat) '
+ 'to be imported into Armory. All private '
+ 'keys will be migrated from the wallet.dat allowing you to use the '
+ 'same addresses in Armory as you use with the regular '
+ 'Bitcoin client.\n\nNOTE: It is strongly recommended that all '
+ 'Bitcoin addresses be used in only one program at a time. If you '
+ 'import your entire wallet.dat, it is recommended to stop using the '
+ 'regular Bitcoin client, and only use Armory to send transactions. '
+ 'Armory developers will not be responsible for coins getting "locked" '
+ 'or "stuck" due to multiple applications attempting to spend coins '
+ 'from the same addresses.')
+
+ lblSatoshiWlt = QRichLabel('Wallet File to be Migrated (usually "wallet.dat")')
+ self.txtWalletPath = QLineEdit()
+ self.chkAllKeys = QCheckBox('Include Address Pool (unused keys)')
+
+ btnGetFilename = QPushButton('Find...')
+ self.connect(btnGetFilename, SIGNAL('clicked()'), self.getSatoshiFilename)
+
+ defaultWalletPath = os.path.join(BTC_HOME_DIR,'wallet.dat')
+ if os.path.exists(defaultWalletPath):
+ self.txtWalletPath.setText(defaultWalletPath)
+
+ buttonBox = QDialogButtonBox()
+ self.btnAccept = QPushButton("Import")
+ self.btnReject = QPushButton("Cancel")
+ self.connect(self.btnAccept, SIGNAL('clicked()'), self.execMigrate)
+ self.connect(self.btnReject, SIGNAL('clicked()'), self.reject)
+ buttonBox.addButton(self.btnAccept, QDialogButtonBox.AcceptRole)
+ buttonBox.addButton(self.btnReject, QDialogButtonBox.RejectRole)
+
+
+ # Select the wallet into which you want to import
+ self.wltidlist = ['']
+ self.lstWallets = QListWidget()
+ self.lstWallets.addItem(QListWidgetItem('New Wallet...'))
+ for wltID in self.main.walletIDList:
+ wlt = self.main.walletMap[wltID]
+ wlttype = determineWalletType(self.main.walletMap[wltID], self.main)[0]
+ if wlttype in (WLTTYPES.WatchOnly, WLTTYPES.Offline):
+ continue
+ self.lstWallets.addItem( \
+ QListWidgetItem('%s (%s)' % (wlt.labelName, wlt.uniqueIDB58) ))
+ self.wltidlist.append(wlt.uniqueIDB58)
+ self.lstWallets.setCurrentRow(0)
+
+
+ dlgLayout = QVBoxLayout()
+ dlgLayout.addWidget(lblDescr)
+ dlgLayout.addWidget(HLINE())
+ dlgLayout.addWidget(lblSatoshiWlt)
+ dlgLayout.addWidget(makeHorizFrame([self.txtWalletPath, btnGetFilename]))
+ dlgLayout.addWidget(makeHorizFrame([self.chkAllKeys, 'Stretch']))
+ dlgLayout.addWidget(HLINE())
+ dlgLayout.addWidget(buttonBox)
+
+ self.setLayout(dlgLayout)
+
+ self.setWindowTitle('Migrate Satoshi Wallet')
+ self.setWindowIcon(QIcon( self.main.iconfile))
+
+
+ def getSatoshiFilename(self):
+ # Temporarily reset the "LastDir" to where the default wallet.dat is
+ prevLastDir = self.settings.get('LastDirectory')
+ self.settings.set('LastDirectory', BTC_HOME_DIR)
+ satoshiWltFile = getFileLoad('Load Bitcoin Wallet File', ['Bitcoin Wallets (*.dat)'])
+ self.settings.set('LastDirectory', prevLastDir)
+ if len(str(satoshiWltFile))>0:
+ self.txtWalletPath.setText(satoshiWltFile)
+
+
+
+ def execMigrate(self):
+ satoshiWltFile = str(self.txtWalletPath.text())
+ if not os.path.exists(satoshiWltFile):
+ QMessageBox.critical(self, 'File does not exist!', \
+ 'The specified file does not exist:\n\n' + satoshiWltFile,
+ QMessageBox.Ok)
+ return
+
+ selectedRow = self.lstWallets.currentRow()
+ toWalletID = None
+ if selectedRow>0:
+ toWalletID = self.wltidlist[selectedRow-1]
+
+ # KeyList is [addrB58, privKey, usedYet, acctName]
+ keyList = []
+ if not checkSatoshiEncrypted(satoshiWltFile):
+ keyList = extractSatoshiKeys(satoshiWltFile, str(dlg.edtPasswd.text()))
+ else:
+ correctPassphrase = False
+ firstAsk = True
+ while not correctPassphrase:
+ redText = ''
+ if not firstAsk:
+ redText = 'Incorrect passphrase.\n\n'
+ firstAsk = False
+
+ dlg = DlgGenericGetPassword( \
+ redText + 'The wallet.dat file you specified is encrypted. '
+ 'Please provide the passphrase to decrypt it.')
+
+ if not dlg.exec_():
+ return
+ else:
+ try:
+ keyList = extractSatoshiKeys(satoshiWltFile, str(dlg.edtPasswd.text()))
+ correctPassphrase = True
+ except EncryptionError:
+ pass
+
+
+ if not self.chkAllKeys.isChecked():
+ keyList = filter(lambda x: x[2], keyList)
+
+
+ # Warn about addresses that would be duplicates.
+ # This filters the list down to addresses already in a wallet that isn't selected
+ # Addresses already in the selected wallet will simply be skipped, no need to
+ # do anything about that
+ addr_to_wltID = lambda a: self.main.getWalletForAddr160(addrStr_to_hash160(a))
+ allWltList = [[addr_to_wltID(k[0]), k[0]] for k in keyList]
+
+ dupeWltList = filter(lambda a: (len(a[0])>0 and a[0]!=toWalletID), allWltList)
+ dispStrList = [d[0].ljust(40) + d[0] for d in dupeWltList]
+
+ if len(dispStrList)>0:
+ dlg = DlgDuplicateAddr(dispStrList, self, self.main)
+ if dlg.exec_():
+ dupeAddrList = [a[1] for a in dupeWltList]
+ keyList = filter(lambda x: (x[0] not in dupeAddrList), keyList)
+
+
+ # Confirm import
+ addrList = [k[0].ljust(40)+k[3] for k in keyList]
+ dlg = DlgConfirmBulkImport(addrList, toWallet, self, self.main)
+ if not dlg.exec_():
+ return
+
+ # Okay, let's do it!
+ if self.wlt.useEncryption and self.wlt.isLocked:
+ # Target wallet is encrypted...
+ unlockdlg = DlgUnlockWallet(self.wlt, self, self.main, 'Unlock Wallet to Import')
+ if not unlockdlg.exec_():
+ QMessageBox.critical(self, 'Wallet is Locked', \
+ 'Cannot import private keys without unlocking wallet!', \
+ QMessageBox.Ok)
+ return
+
+
+ nImport = 0
+ for i,key4 in enumerate(keyList):
+ addrB58, sbdKey, isUsed, addrName = key4[:]
+ try:
+ a160 = addrStr_to_hash160(addrB58)
+ self.wlt.importExternalAddressData(privKey=sbdKey)
+ cmt = 'Imported #%03d'%i
+ if len(addrName)>0:
+ cmt += ': %s' % addrName
+ self.wlt.setComment(a160, cmt)
+ nImport += 1
+ except Exception,msg:
+ print '***ERROR importing:', addrB58
+ print ' Error Msg:', msg
+
+ MsgBoxCustom(MSGBOX.Good, 'Success!', \
+ 'Success: %d private keys were imported into your wallet. '
+ 'Please restart Armory to guarantee that balances are computed '
+ 'correctly')
+ self.accept()
+
+
+
+
+
+
+
+
+
+#############################################################################
+class DlgConfirmBulkImport(QDialog):
+ def __init__(self, addrList, wlt, parent=None, main=None):
+ super(DlgConfirmBulkImport, self).__init__(parent)
+
+ self.parent = parent
+ self.main = main
+ self.wlt = wlt
+
+ if len(addrList)==0:
+ QMessageBox.warning(self, 'No Addresses to Import', \
+ 'There are no addresses to import!', QMessageBox.Ok)
+ self.reject()
+
+ lblDescr = QRichLabel( \
+ 'You are about to import %d private keys into wallet, %s (%s). '
+ 'The following is a list of addresses corresponding to the keys to '
+ 'be imported:' % (len(addrList), wlt.uniqueIDB58, wlt.labelName))
+
+ fnt = GETFONT('Fixed',8)
+ w,h = tightSizeNChar(fnt, 50)
+ txtDispAddr = QTextEdit()
+ txtDispAddr.setFont(fnt)
+ txtDispAddr.setReadOnly(True)
+ txtDispAddr.setMinimumWidth(w)
+ txtDispAddr.setMinimumHeight(16.2*h)
+ txtDispAddr.setText( '\n'.join(addrList) )
+
+ buttonBox = QDialogButtonBox()
+ self.btnAccept = QPushButton("Import")
+ self.btnReject = QPushButton("Cancel")
+ self.connect(self.btnAccept, SIGNAL('clicked()'), self.accept)
+ self.connect(self.btnReject, SIGNAL('clicked()'), self.reject)
+ buttonBox.addButton(self.btnAccept, QDialogButtonBox.AcceptRole)
+ buttonBox.addButton(self.btnReject, QDialogButtonBox.RejectRole)
+
+ dlgLayout = QVBoxLayout()
+ dlgLayout.addWidget(lblDescr)
+ dlgLayout.addWidget(txtDispAddr)
+ dlgLayout.addWidget(buttonBox)
+ self.setLayout(dlgLayout)
+
+ self.setWindowTitle('Greetings!')
+ self.setWindowIcon(QIcon( self.main.iconfile))
+
+
+#############################################################################
+class DlgDuplicateAddr(QDialog):
+ def __init__(self, addrList, wlt, parent=None, main=None):
+ super(DlgDuplicateAddr, self).__init__(parent)
+
+ self.parent = parent
+ self.main = main
+ self.wlt = wlt
+
+ if len(addrList)==0:
+ QMessageBox.warning(self, 'No Addresses to Import', \
+ 'There are no addresses to import!', QMessageBox.Ok)
+ self.reject()
+
+ lblDescr = QRichLabel( \
+ 'Duplicate addresses detected! '
+ 'The following addresses already exist in other Armory wallets:')
+
+ fnt = GETFONT('Fixed',8)
+ w,h = tightSizeNChar(fnt, 50)
+ txtDispAddr = QTextEdit()
+ txtDispAddr.setFont(fnt)
+ txtDispAddr.setReadOnly(True)
+ txtDispAddr.setMinimumWidth(w)
+ txtDispAddr.setMinimumHeight(8.2*h)
+ txtDispAddr.setText( '\n'.join(addrList) )
+
+ buttonBox = QDialogButtonBox()
+ self.btnAccept = QPushButton("Import")
+ self.btnReject = QPushButton("Cancel")
+ self.connect(self.btnAccept, SIGNAL('clicked()'), self.accept)
+ self.connect(self.btnReject, SIGNAL('clicked()'), self.reject)
+ buttonBox.addButton(self.btnAccept, QDialogButtonBox.AcceptRole)
+ buttonBox.addButton(self.btnReject, QDialogButtonBox.RejectRole)
+
+ dlgLayout = QVBoxLayout()
+ dlgLayout.addWidget(lblDescr)
+ dlgLayout.addWidget(txtDispAddr)
+ dlgLayout.addWidget(buttonBox)
+ self.setLayout(dlgLayout)
+
+ self.setWindowTitle('Greetings!')
+ self.setWindowIcon(QIcon( self.main.iconfile))
#############################################################################
class DlgAddressInfo(QDialog):
@@ -3144,11 +3479,8 @@ def __init__(self, parent=None, main=None, title='Select Wallet:', \
self.accept()
return
-
-
if wltIDList==None:
wltIDList = list(self.main.walletIDList)
-
self.rowList = []
diff --git a/unittest.py b/unittest.py
index ffbca61f0..66f8ececb 100644
--- a/unittest.py
+++ b/unittest.py
@@ -14,13 +14,14 @@
Test_TxSimpleCreate = False
Test_EncryptedAddress = False
Test_EncryptedWallet = False
-Test_TxDistProposals = True
+Test_TxDistProposals = False
Test_SelectCoins = False
Test_CryptoTiming = False
Test_NetworkObjects = False
Test_ReactorLoop = False
Test_SettingsFile = False
+Test_WalletMigrate = True
'''
import optparse
@@ -1802,5 +1803,25 @@ def printstat():
os.remove(testFile2)
+if Test_WalletMigrate:
+
+ import getpass
+ p = '/home/alan/winlinshare/wallet_plain.dat'
+ print 'Encrypted? ', checkSatoshiEncrypted(p)
+ plain = extractSatoshiKeys(p)
+
+ print len(plain)
+ print sum([1 if p[2] else 0 for p in plain])
+ print sum([0 if p[2] else 1 for p in plain])
+
+ p = '/home/alan/.bitcoin/wallet.dat'
+ print 'Encrypted? ', checkSatoshiEncrypted(p)
+ k = getpass.getpass('decrypt passphrase:')
+ crypt = extractSatoshiKeys(p, k)
+
+
+ print len(crypt)
+ print sum([1 if p[2] else 0 for p in crypt])
+ print sum([0 if p[2] else 1 for p in crypt])