diff --git a/AUTHORS b/AUTHORS index 9cff06784e0c..936932dcc678 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,4 +9,6 @@ Genjix - Porting pro-mode functionality to lite-gui and worked on server Slush - Work on the server. Designed the original Stratum spec. Julian Toash (Tuxavant) - Various fixes to the client. rdymac - Website and translations. -kyuupichan - Miscellaneous. \ No newline at end of file +kyuupichan - Miscellaneous. +pooler - Litecoin port. +sn-ntu - Zcoin port. diff --git a/Info.plist b/Info.plist index a8f58f733958..22c46a94aa26 100644 --- a/Info.plist +++ b/Info.plist @@ -6,10 +6,10 @@ CFBundleURLName - bitcoin + zcoin CFBundleURLSchemes - bitcoin + zcoin diff --git a/MANIFEST.in b/MANIFEST.in index 4fa5491a6d48..cb52871c28ff 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,9 +1,9 @@ include LICENCE RELEASE-NOTES AUTHORS include README.rst -include electrum.conf.sample -include electrum.desktop +include electrum-xzc.conf.sample +include electrum-xzc.desktop include *.py -include electrum +include electrum-xzc recursive-include lib *.py recursive-include gui *.py recursive-include plugins *.py diff --git a/README.rst b/README.rst index 9b183235477a..fbc11c3fe3a3 100644 --- a/README.rst +++ b/README.rst @@ -1,20 +1,13 @@ -Electrum - Lightweight Bitcoin client -===================================== +Electrum-XZC - Lightweight Zcoin client +======================================= :: Licence: MIT Licence - Author: Thomas Voegtlin + Original Author: Thomas Voegtlin + Port Maintainer: Pooler, SN Language: Python - Homepage: https://electrum.org/ - - -.. image:: https://travis-ci.org/spesmilo/electrum.svg?branch=master - :target: https://travis-ci.org/spesmilo/electrum - :alt: Build Status -.. image:: https://coveralls.io/repos/github/spesmilo/electrum/badge.svg?branch=master - :target: https://coveralls.io/github/spesmilo/electrum?branch=master - :alt: Test coverage statistics + Homepage: https://electrum.zcoin.io/ @@ -34,7 +27,7 @@ Electrum from its root directory, without installing it on your system; all the python dependencies are included in the 'packages' directory. To run Electrum from its root directory, just do:: - ./electrum + ./electrum-xzc You can also install Electrum on your system, by running this command:: @@ -53,10 +46,32 @@ Version". Development version =================== +ElectrumX developer decided to use newer Python 3 which isn't installed on many operating systems by default. Let's install it manually:: + + sudo add-apt-repository ppa:jonathonf/python-3.6 + sudo apt-get update && sudo apt-get install python3.6 python3.6-dev python3-pip python3-pyqt5 + +To make python3 use the new installed python 3.6 instead of the default 3.5 release, run following 3 commands:: + + sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1 + sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2 + sudo update-alternatives --config python3 + +Install dependencies:: + + sudo apt-get install pyqt5-dev-tools protobuf-compiler python-requests gettext + pip3 install --upgrade pip setuptools wheel + Check out the code from Github:: - git clone git://github.com/spesmilo/electrum.git - cd electrum + git clone git://github.com/sn-ntu/electrum-xzc.git + cd electrum-xzc + +Install lyra2z lib:: + + cd ./exlib/lyra2z-py/ + sudo python3 setup.py install + cd ../../ Run install (this should install dependencies):: @@ -64,17 +79,14 @@ Run install (this should install dependencies):: Compile the icons file for Qt:: - sudo apt-get install pyqt5-dev-tools pyrcc5 icons.qrc -o gui/qt/icons_rc.py Compile the protobuf description file:: - sudo apt-get install protobuf-compiler protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto Create translations (optional):: - sudo apt-get install python-requests gettext ./contrib/make_locale @@ -93,12 +105,13 @@ This directory contains the python dependencies used by Electrum. Mac OS X / macOS -------- -See `contrib/build-osx/`. +See `contrib/build-osx/README`. + Windows ------- -See `contrib/build-wine/`. +See `contrib/build-wine/README` file. Android diff --git a/RELEASE-NOTES b/RELEASE-NOTES index ddadee13d6b4..2a06061e836b 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,50 +1,3 @@ -# Release 3.1 - (to be released) - - * Mempory pool based fee estimates. If this option is activated, - users can set transaction fees that target a desired depth in the - memory pool. This feature might be controversial, because miners - could conspire and fill the memory pool with expensive transactions - that never get mined. However, our current time-based fee estimates - results in sticky fees, which cause inexperienced users to overpay, - while more advanced users visit (and trust) websites that display - memorypool data, and set their fee accordingly. - * Local transactions: Transactions that have not been broadcasted can - be saved in the wallet file, and their outputs can be used in - subsequent transactions. Transactions that disapear from the memory - pool stay in the wallet, and can be rebroadcasted. This feature can - be combined with cold storage, to create several transactions - before broadcasting. - * The initial headers download was replaced with hardcoded - checkpoints, one per retargeting period. Past headers are - downloaded when needed. - * The two coin selection policies have been merged, and the policy - choice was removed from preferences. Previously, the 'privacy' - policy has been unusable because it was was not prioritizing - confirmed coins. - * The 'Send' tab of the Qt GUI displays how transaction fees are - computed from transaction size. - * RBF is enabled by default. This might cause some issues with - merchants that use wallets that do not display RBF transactions - until they are confirmed. - * Watching-only wallets and hardware wallets can be encrypted. - * Semi-automated crash reporting - * The SSL checkbox option was removed from the GUI. - * Capital gains: For each outgoing transaction, the difference - between the acquisition and liquidation prices of outgoing coins is - displayed in the wallet history. By default, historical exchange - rates are used to compute acquisition and liquidation prices. These - value can also be entered manually, in order to match the actual - price realized by the user. The order of liquidation of coins is - the natural order defined by the blockchain; this results in - capital gain values that are invariant to changes in the set of - addresses that are in the wallet. Any other ordering strategy (such - as FIFO, LIFO) would result in capital gain values that depend on - the set of addresses in the wallet. - - -# Release 3.0.6 : - * Fix transaction parsing bug #3788 - # Release 3.0.5 : (Security update) This is a follow-up to the 3.0.4 release, which did not completely fix diff --git a/contrib/build-wine/build-electrum-git.sh b/contrib/build-wine/build-electrum-git.sh index a8f743588f98..0878eaefc8f2 100755 --- a/contrib/build-wine/build-electrum-git.sh +++ b/contrib/build-wine/build-electrum-git.sh @@ -1,6 +1,6 @@ #!/bin/bash -NAME_ROOT=electrum +NAME_ROOT=electrum-xzc PYTHON_VERSION=3.5.4 # These settings probably don't need any change @@ -18,19 +18,19 @@ set -e cd tmp -for repo in electrum electrum-locale electrum-icons; do +for repo in electrum-xzc electrum-xzc-locale electrum-xzc-icons; do if [ -d $repo ]; then cd $repo git pull git checkout master cd .. else - URL=https://github.com/spesmilo/$repo.git + URL=https://github.com/sn-ntu/$repo.git git clone -b master $URL $repo fi done -pushd electrum-locale +pushd electrum-xzc-locale for i in ./locale/*; do dir=$i/LC_MESSAGES mkdir -p $dir @@ -38,7 +38,7 @@ for i in ./locale/*; do done popd -pushd electrum +pushd electrum-xzc if [ ! -z "$1" ]; then git checkout $1 fi @@ -48,17 +48,16 @@ echo "Last commit: $VERSION" find -exec touch -d '2000-11-11T11:11:11+00:00' {} + popd -rm -rf $WINEPREFIX/drive_c/electrum -cp -r electrum $WINEPREFIX/drive_c/electrum -cp electrum/LICENCE . -cp -r electrum-locale/locale $WINEPREFIX/drive_c/electrum/lib/ -cp electrum-icons/icons_rc.py $WINEPREFIX/drive_c/electrum/gui/qt/ +rm -rf $WINEPREFIX/drive_c/electrum-xzc +cp -r electrum-xzc $WINEPREFIX/drive_c/electrum-xzc +cp electrum-xzc/LICENCE . +cp -r electrum-xzc-locale/locale $WINEPREFIX/drive_c/electrum-xzc/lib/ +cp electrum-xzc-icons/icons_rc.py $WINEPREFIX/drive_c/electrum-xzc/gui/qt/ # Install frozen dependencies -$PYTHON -m pip install -r ../../deterministic-build/requirements.txt -$PYTHON -m pip install -r ../../deterministic-build/requirements-hw.txt +$PYTHON -m pip install -r ../../requirements.txt -pushd $WINEPREFIX/drive_c/electrum +pushd $WINEPREFIX/drive_c/electrum-xzc $PYTHON setup.py install popd @@ -79,7 +78,7 @@ popd wine "$WINEPREFIX/drive_c/Program Files (x86)/NSIS/makensis.exe" /DPRODUCT_VERSION=$VERSION electrum.nsi cd dist -mv electrum-setup.exe $NAME_ROOT-$VERSION-setup.exe +mv electrum-xzc-setup.exe $NAME_ROOT-$VERSION-setup.exe cd .. echo "Done." diff --git a/contrib/build-wine/build.sh b/contrib/build-wine/build.sh index 8bf650626c9b..efd23bc17c0f 100755 --- a/contrib/build-wine/build.sh +++ b/contrib/build-wine/build.sh @@ -13,7 +13,9 @@ echo "Clearing $here/build and $here/dist..." rm "$here"/build/* -rf rm "$here"/dist/* -rf -$here/prepare-wine.sh || exit 1 +$here/prepare-wine.sh && \ +$here/prepare-pyinstaller.sh && \ +$here/prepare-hw.sh || exit 1 echo "Resetting modification time in C:\Python..." # (Because of some bugs in pyinstaller) diff --git a/contrib/build-wine/deterministic.spec b/contrib/build-wine/deterministic.spec index 3dc5953b537b..80f13e4586f4 100644 --- a/contrib/build-wine/deterministic.spec +++ b/contrib/build-wine/deterministic.spec @@ -11,36 +11,38 @@ else: raise BaseException('no name') -home = 'C:\\electrum\\' +home = 'C:\\electrum-xzc\\' # see https://github.com/pyinstaller/pyinstaller/issues/2005 hiddenimports = [] hiddenimports += collect_submodules('trezorlib') hiddenimports += collect_submodules('btchip') hiddenimports += collect_submodules('keepkeylib') +hiddenimports += ['_scrypt'] datas = [ - (home+'lib/currencies.json', 'electrum'), - (home+'lib/servers.json', 'electrum'), - (home+'lib/checkpoints.json', 'electrum'), - (home+'lib/servers_testnet.json', 'electrum'), - (home+'lib/checkpoints_testnet.json', 'electrum'), - (home+'lib/wordlist/english.txt', 'electrum/wordlist'), - (home+'lib/locale', 'electrum/locale'), - (home+'plugins', 'electrum_plugins'), + (home+'lib/currencies.json', 'electrum_xzc'), + (home+'lib/servers.json', 'electrum_xzc'), + (home+'lib/checkpoints.json', 'electrum_xzc'), + (home+'lib/servers_testnet.json', 'electrum_xzc'), + (home+'lib/checkpoints_testnet.json', 'electrum_xzc'), + (home+'lib/wordlist/english.txt', 'electrum_xzc/wordlist'), + (home+'lib/locale', 'electrum_xzc/locale'), + (home+'plugins', 'electrum_xzc_plugins'), ] datas += collect_data_files('trezorlib') datas += collect_data_files('btchip') datas += collect_data_files('keepkeylib') # We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports -a = Analysis([home+'electrum', +a = Analysis([home+'electrum-xzc', home+'gui/qt/main_window.py', home+'gui/text.py', home+'lib/util.py', home+'lib/wallet.py', home+'lib/simple_config.py', home+'lib/bitcoin.py', + home+'lib/blockchain.py', home+'lib/dnssec.py', home+'lib/commands.py', home+'plugins/cosigner_pool/qt.py', @@ -77,7 +79,7 @@ exe_standalone = EXE( a.scripts, a.binaries, a.datas, - name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + ".exe"), + name=os.path.join('build\\pyi.win32\\electrum-xzc', cmdline_name + ".exe"), debug=False, strip=None, upx=False, @@ -90,7 +92,7 @@ exe_portable = EXE( a.scripts, a.binaries, a.datas + [ ('is_portable', 'README.md', 'DATA' ) ], - name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + "-portable.exe"), + name=os.path.join('build\\pyi.win32\\electrum-xzc', cmdline_name + "-portable.exe"), debug=False, strip=None, upx=False, @@ -104,7 +106,7 @@ exe_dependent = EXE( pyz, a.scripts, exclude_binaries=True, - name=os.path.join('build\\pyi.win32\\electrum', cmdline_name), + name=os.path.join('build\\pyi.win32\\electrum-xzc', cmdline_name), debug=False, strip=None, upx=False, @@ -121,4 +123,4 @@ coll = COLLECT( debug=False, icon=home+'icons/electrum.ico', console=False, - name=os.path.join('dist', 'electrum')) + name=os.path.join('dist', 'electrum-xzc')) diff --git a/contrib/build-wine/electrum.nsi b/contrib/build-wine/electrum.nsi index 0a30033257ea..d70747b2a304 100644 --- a/contrib/build-wine/electrum.nsi +++ b/contrib/build-wine/electrum.nsi @@ -6,8 +6,8 @@ ;-------------------------------- ;Variables - !define PRODUCT_NAME "Electrum" - !define PRODUCT_WEB_SITE "https://github.com/spesmilo/electrum" + !define PRODUCT_NAME "Electrum-XZC" + !define PRODUCT_WEB_SITE "https://github.com/sn-ntu/electrum-xzc" !define PRODUCT_PUBLISHER "Electrum Technologies GmbH" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" @@ -16,7 +16,7 @@ ;Name and file Name "${PRODUCT_NAME}" - OutFile "dist/electrum-setup.exe" + OutFile "dist/electrum-xzc-setup.exe" ;Default installation folder InstallDir "$PROGRAMFILES\${PRODUCT_NAME}" @@ -72,7 +72,7 @@ !define MUI_ABORTWARNING !define MUI_ABORTWARNING_TEXT "Are you sure you wish to abort the installation of ${PRODUCT_NAME}?" - !define MUI_ICON "tmp\electrum\icons\electrum.ico" + !define MUI_ICON "tmp\electrum-xzc\icons\electrum.ico" ;-------------------------------- ;Pages @@ -110,7 +110,7 @@ Section Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*" ;Files to pack into the installer - File /r "dist\electrum\*.*" + File /r "dist\electrum-xzc\*.*" File "..\..\icons\electrum.ico" ;Store installation folder @@ -122,21 +122,21 @@ Section ;Create desktop shortcut DetailPrint "Creating desktop shortcut..." - CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" + CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe" "" ;Create start-menu items DetailPrint "Creating start-menu items..." CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0 + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe" 0 + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe" 0 ;Links bitcoin: URI's to Electrum - WriteRegStr HKCU "Software\Classes\bitcoin" "" "URL:bitcoin Protocol" - WriteRegStr HKCU "Software\Classes\bitcoin" "URL Protocol" "" - WriteRegStr HKCU "Software\Classes\bitcoin" "DefaultIcon" "$\"$INSTDIR\electrum.ico, 0$\"" - WriteRegStr HKCU "Software\Classes\bitcoin\shell\open\command" "" "$\"$INSTDIR\electrum-${PRODUCT_VERSION}.exe$\" $\"%1$\"" + WriteRegStr HKCU "Software\Classes\zcoin" "" "URL:zcoin Protocol" + WriteRegStr HKCU "Software\Classes\zcoin" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\zcoin" "DefaultIcon" "$\"$INSTDIR\electrum.ico, 0$\"" + WriteRegStr HKCU "Software\Classes\zcoin\shell\open\command" "" "$\"$INSTDIR\electrum-xzc-${PRODUCT_VERSION}.exe$\" $\"%1$\"" ;Adds an uninstaller possibilty to Windows Uninstall or change a program section WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" @@ -167,7 +167,7 @@ Section "Uninstall" Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*" RMDir "$SMPROGRAMS\${PRODUCT_NAME}" - DeleteRegKey HKCU "Software\Classes\bitcoin" + DeleteRegKey HKCU "Software\Classes\zcoin" DeleteRegKey HKCU "Software\${PRODUCT_NAME}" DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}" SectionEnd diff --git a/contrib/build-wine/prepare-hw.sh b/contrib/build-wine/prepare-hw.sh new file mode 100755 index 000000000000..1851b7b0ffd9 --- /dev/null +++ b/contrib/build-wine/prepare-hw.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +TREZOR_GIT_URL=https://github.com/trezor/python-trezor.git +KEEPKEY_GIT_URL=https://github.com/keepkey/python-keepkey.git +BTCHIP_GIT_URL=https://github.com/LedgerHQ/btchip-python.git + +BRANCH=master + +PYTHON_VERSION=3.5.4 + +# These settings probably don't need any change +export WINEPREFIX=/opt/wine64 + +PYHOME=c:/python$PYTHON_VERSION +PYTHON="wine $PYHOME/python.exe -OO -B" + +# Let's begin! +cd `dirname $0` +set -e + +cd tmp + +$PYTHON -m pip install setuptools --upgrade +$PYTHON -m pip install cython --upgrade +$PYTHON -m pip install trezor==0.7.16 --upgrade +$PYTHON -m pip install keepkey==4.0.0 --upgrade +$PYTHON -m pip install btchip-python==0.1.23 --upgrade + diff --git a/contrib/build-wine/prepare-pyinstaller.sh b/contrib/build-wine/prepare-pyinstaller.sh new file mode 100755 index 000000000000..cf8a326cdf7f --- /dev/null +++ b/contrib/build-wine/prepare-pyinstaller.sh @@ -0,0 +1,24 @@ +#!/bin/bash +PYTHON_VERSION=3.5.4 + +PYINSTALLER_GIT_URL=https://github.com/ecdsa/pyinstaller.git +BRANCH=fix_2952 + +export WINEPREFIX=/opt/wine64 +PYHOME=c:/python$PYTHON_VERSION +PYTHON="wine $PYHOME/python.exe -OO -B" + +cd `dirname $0` +set -e +cd tmp +if [ ! -d "pyinstaller" ]; then + git clone -b $BRANCH $PYINSTALLER_GIT_URL pyinstaller +fi + +cd pyinstaller +git pull +git checkout $BRANCH +$PYTHON setup.py install +cd .. + +wine "C:/python$PYTHON_VERSION/scripts/pyinstaller.exe" -v diff --git a/contrib/build-wine/prepare-wine.sh b/contrib/build-wine/prepare-wine.sh index d62b4c63da7f..1282dc0bc870 100755 --- a/contrib/build-wine/prepare-wine.sh +++ b/contrib/build-wine/prepare-wine.sh @@ -72,22 +72,28 @@ done # upgrade pip $PYTHON -m pip install pip --upgrade -# Install pywin32-ctypes (needed by pyinstaller) -$PYTHON -m pip install pywin32-ctypes==0.1.2 +# Install PyWin32 +$PYTHON -m pip install pypiwin32 -# install PySocks -$PYTHON -m pip install win_inet_pton==1.0.1 - -$PYTHON -m pip install -r ../../deterministic-build/requirements-binaries.txt +# Install PyQt +$PYTHON -m pip install PyQt5 -# Install PyInstaller +## Install pyinstaller +#$PYTHON -m pip install pyinstaller==3.3 -$PYTHON -m pip install git+https://github.com/ecdsa/pyinstaller@fix_2952 # Install ZBar #wget -q -O zbar.exe "https://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download" #wine zbar.exe +# install Cryptodome +$PYTHON -m pip install pycryptodomex + +# install PySocks +$PYTHON -m pip install win_inet_pton + +# install websocket (python2) +$PYTHON -m pip install websocket-client # Upgrade setuptools (so Electrum can be installed later) $PYTHON -m pip install setuptools --upgrade @@ -105,4 +111,21 @@ wine nsis.exe /S # add dlls needed for pyinstaller: cp $WINEPREFIX/drive_c/python$PYTHON_VERSION/Lib/site-packages/PyQt5/Qt/bin/* $WINEPREFIX/drive_c/python$PYTHON_VERSION/ + +# Install MinGW +wget http://downloads.sourceforge.net/project/mingw/Installer/mingw-get-setup.exe +wine mingw-get-setup.exe + +echo "add c:\MinGW\bin to PATH using regedit" +echo "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" +regedit + +wine mingw-get install gcc +wine mingw-get install mingw-utils +wine mingw-get install mingw32-libz + +printf "[build]\ncompiler=mingw32\n" > $WINEPREFIX/drive_c/python$PYTHON_VERSION/Lib/distutils/distutils.cfg + +$PYTHON -m pip install scrypt + echo "Wine is configured. Please run prepare-pyinstaller.sh" diff --git a/contrib/freeze_packages.sh b/contrib/freeze_packages.sh index 3471e528bff5..c8e4527b968f 100755 --- a/contrib/freeze_packages.sh +++ b/contrib/freeze_packages.sh @@ -6,17 +6,17 @@ contrib=$(dirname "$0") which virtualenv > /dev/null 2>&1 || { echo "Please install virtualenv" && exit 1; } -for i in '' '-hw' '-binaries'; do - rm "$venv_dir" -rf - virtualenv -p $(which python3) $venv_dir +rm "$venv_dir" -rf +virtualenv -p $(which python3) $venv_dir - source $venv_dir/bin/activate +source $venv_dir/bin/activate - echo "Installing $i dependencies" +echo "Installing dependencies" - python -m pip install -r $contrib/requirements/requirements${i}.txt --upgrade +pushd $contrib/.. +python setup.py install +popd - pip freeze | sed '/^Electrum/ d' > $contrib/deterministic-build/requirements${i}.txt -done +pip freeze | sed '/^Electrum/ d' > $contrib/requirements.txt -echo "Done. Updated requirements" +echo "Updated requirements" diff --git a/contrib/make_download b/contrib/make_download index 84e4ff21b6ca..cfc0812aa88b 100755 --- a/contrib/make_download +++ b/contrib/make_download @@ -15,17 +15,17 @@ string = string.replace("##VERSION_ANDROID##", version_android) string = string.replace("##VERSION_APK##", version_apk) files = { - 'tgz': "Electrum-%s.tar.gz" % version, - 'zip': "Electrum-%s.zip" % version, - 'mac': "electrum-%s.dmg" % version_mac, - 'win': "electrum-%s.exe" % version_win, - 'win_setup': "electrum-%s-setup.exe" % version_win, - 'win_portable': "electrum-%s-portable.exe" % version_win, + 'tgz': "Electrum-XZC-%s.tar.gz" % version, + 'zip': "Electrum-XZC-%s.zip" % version, + 'mac': "electrum-xzc-%s.dmg" % version_mac, + 'win': "electrum-xzc-%s.exe" % version_win, + 'win_setup': "electrum-xzc-%s-setup.exe" % version_win, + 'win_portable': "electrum-xzc-%s-portable.exe" % version_win, } for k, n in files.items(): path = "dist/%s"%n - link = "https://download.electrum.org/%s/%s"%(version,n) + link = "https://download.electrum-xzc.org/%s"%n if not os.path.exists(path): os.system("wget -q %s -O %s" % (link, path)) if not os.path.getsize(path): diff --git a/contrib/make_osx b/contrib/make_osx new file mode 100755 index 000000000000..c634645f3dfc --- /dev/null +++ b/contrib/make_osx @@ -0,0 +1,6 @@ +#!/bin/bash +rm -rf dist +export PYTHONHASHSEED=22 +VERSION=`git describe --tags` +pyinstaller --noconfirm --ascii --name $VERSION contrib/osx.spec +hdiutil create -fs HFS+ -volname "Electrum-XZC" -srcfolder dist/Electrum-XZC.app dist/electrum-xzc-$VERSION.dmg diff --git a/contrib/make_packages b/contrib/make_packages index 9cfd32bb24cc..b3a36049722e 100755 --- a/contrib/make_packages +++ b/contrib/make_packages @@ -9,5 +9,5 @@ if [ $? -ne 0 ] ; then echo "Install pip3" ; exit ; fi rm "$contrib"/../packages/ -r #Install pure python modules in electrum directory -pip3 install -r $contrib/deterministic-build/requirements.txt -t $contrib/../packages +pip3 install -r $contrib/requirements.txt -t $contrib/../packages diff --git a/contrib/osx.spec b/contrib/osx.spec new file mode 100644 index 000000000000..7864b08292b3 --- /dev/null +++ b/contrib/osx.spec @@ -0,0 +1,87 @@ +# -*- mode: python -*- + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +import sys +import os + +for i, x in enumerate(sys.argv): + if x == '--name': + VERSION = sys.argv[i+1] + break +else: + raise BaseException('no version') + +electrum = "../" +block_cipher=None + +# see https://github.com/pyinstaller/pyinstaller/issues/2005 +hiddenimports = [] +hiddenimports += collect_submodules('trezorlib') +hiddenimports += collect_submodules('btchip') +hiddenimports += collect_submodules('keepkeylib') +hiddenimports += ['_scrypt'] + +datas = [ + (electrum+'lib/currencies.json', 'electrum_xzc'), + (electrum+'lib/servers.json', 'electrum_xzc'), + (electrum+'lib/checkpoints.json', 'electrum_xzc'), + (electrum+'lib/servers_testnet.json', 'electrum_xzc'), + (electrum+'lib/checkpoints_testnet.json', 'electrum_xzc'), + (electrum+'lib/wordlist/english.txt', 'electrum_xzc/wordlist'), + (electrum+'lib/locale', 'electrum_xzc/locale'), + (electrum+'plugins', 'electrum_xzc_plugins'), +] +datas += collect_data_files('trezorlib') +datas += collect_data_files('btchip') +datas += collect_data_files('keepkeylib') + +# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports +a = Analysis([electrum+'electrum-xzc', + electrum+'gui/qt/main_window.py', + electrum+'gui/text.py', + electrum+'lib/util.py', + electrum+'lib/wallet.py', + electrum+'lib/simple_config.py', + electrum+'lib/bitcoin.py', + electrum+'lib/dnssec.py', + electrum+'lib/commands.py', + electrum+'plugins/cosigner_pool/qt.py', + electrum+'plugins/email_requests/qt.py', + electrum+'plugins/trezor/client.py', + electrum+'plugins/trezor/qt.py', + electrum+'plugins/keepkey/qt.py', + electrum+'plugins/ledger/qt.py', + ], + datas=datas, + hiddenimports=hiddenimports, + hookspath=[]) + +# http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal +for d in a.datas: + if 'pyconfig' in d[0]: + a.datas.remove(d) + break + +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE(pyz, + a.scripts, + a.binaries, + a.datas, + name='Electrum-XZC', + debug=False, + strip=False, + upx=True, + icon=electrum+'electrum.icns', + console=False) + +app = BUNDLE(exe, + version = VERSION, + name='Electrum-XZC.app', + icon=electrum+'electrum.icns', + bundle_identifier=None, + info_plist = { + 'NSHighResolutionCapable':'True' + } +) diff --git a/contrib/requirements.txt b/contrib/requirements.txt new file mode 100644 index 000000000000..828818a6e5ef --- /dev/null +++ b/contrib/requirements.txt @@ -0,0 +1,15 @@ +certifi==2017.11.5 +chardet==3.0.4 +dnspython==1.15.0 +ecdsa==0.13 +idna==2.6 +jsonrpclib-pelix==0.3.1 +pbkdf2==1.3 +protobuf==3.5.0.post1 +pyaes==1.6.1 +PySocks==1.6.7 +qrcode==5.3 +requests==2.18.4 +scrypt==0.8.0 +six==1.11.0 +urllib3==1.22 diff --git a/electrum b/electrum index 25495f79e389..9df3e612af2c 100755 --- a/electrum +++ b/electrum @@ -193,8 +193,6 @@ def init_daemon(config_options): print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") sys.exit(0) if storage.is_encrypted(): - if storage.is_encrypted_with_hw_device(): - raise NotImplementedError("CLI functionality of encrypted hw wallets") if config.get('password'): password = config.get('password') else: @@ -239,8 +237,6 @@ def init_cmdline(config_options, server): # commands needing password if (cmd.requires_wallet and storage.is_encrypted() and server is None)\ or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())): - if storage.is_encrypted_with_hw_device(): - raise NotImplementedError("CLI functionality of encrypted hw wallets") if config.get('password'): password = config.get('password') else: @@ -267,14 +263,12 @@ def run_offline_command(config, config_options): if cmd.requires_wallet: storage = WalletStorage(config.get_wallet_path()) if storage.is_encrypted(): - if storage.is_encrypted_with_hw_device(): - raise NotImplementedError("CLI functionality of encrypted hw wallets") storage.decrypt(password) wallet = Wallet(storage) else: wallet = None # check password - if cmd.requires_password and wallet.has_password(): + if cmd.requires_password and storage.get('use_encryption'): try: seed = wallet.check_password(password) except InvalidPassword: diff --git a/electrum-env b/electrum-env index 42220edab67c..b44bd496b4e6 100755 --- a/electrum-env +++ b/electrum-env @@ -19,6 +19,6 @@ fi export PYTHONPATH="/usr/local/lib/python3.5/site-packages:$PYTHONPATH" -./electrum "$@" +./electrum-xzc "$@" deactivate diff --git a/electrum-xzc b/electrum-xzc new file mode 100755 index 000000000000..5bf33bd3be51 --- /dev/null +++ b/electrum-xzc @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# -*- mode: python -*- +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2011 thomasv@gitorious +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +import os +import sys + +# from https://gist.github.com/tito/09c42fb4767721dc323d +import threading +try: + import jnius +except: + jnius = None +if jnius: + orig_thread_run = threading.Thread.run + def thread_check_run(*args, **kwargs): + try: + return orig_thread_run(*args, **kwargs) + finally: + jnius.detach() + threading.Thread.run = thread_check_run + +script_dir = os.path.dirname(os.path.realpath(__file__)) +is_bundle = getattr(sys, 'frozen', False) +is_local = not is_bundle and os.path.exists(os.path.join(script_dir, "electrum-xzc.desktop")) +is_android = 'ANDROID_DATA' in os.environ + +# move this back to gui/kivy/__init.py once plugins are moved +os.environ['KIVY_DATA_DIR'] = os.path.abspath(os.path.dirname(__file__)) + '/gui/kivy/data/' + +if is_local or is_android: + sys.path.insert(0, os.path.join(script_dir, 'packages')) + + +def check_imports(): + # pure-python dependencies need to be imported here for pyinstaller + try: + import dns + import pyaes + import ecdsa + import requests + import qrcode + import pbkdf2 + import google.protobuf + import jsonrpclib + except ImportError as e: + sys.exit("Error: %s. Try 'sudo pip install '"%str(e)) + # the following imports are for pyinstaller + from google.protobuf import descriptor + from google.protobuf import message + from google.protobuf import reflection + from google.protobuf import descriptor_pb2 + from jsonrpclib import SimpleJSONRPCServer + # make sure that certificates are here + assert os.path.exists(requests.utils.DEFAULT_CA_BUNDLE_PATH) + + +if not is_android: + check_imports() + +# load local module as electrum +if is_local or is_android: + import imp + imp.load_module('electrum_xzc', *imp.find_module('lib')) + imp.load_module('electrum_xzc_gui', *imp.find_module('gui')) + imp.load_module('electrum_xzc_plugins', *imp.find_module('plugins')) + + + +from electrum_xzc import bitcoin, util +from electrum_xzc import SimpleConfig, Network +from electrum_xzc.wallet import Wallet, Imported_Wallet +from electrum_xzc.storage import WalletStorage +from electrum_xzc.util import print_msg, print_stderr, json_encode, json_decode +from electrum_xzc.util import set_verbosity, InvalidPassword +from electrum_xzc.commands import get_parser, known_commands, Commands, config_variables +from electrum_xzc import daemon +from electrum_xzc import keystore +from electrum_xzc.mnemonic import Mnemonic +import electrum_xzc_plugins + +# get password routine +def prompt_password(prompt, confirm=True): + import getpass + password = getpass.getpass(prompt, stream=None) + if password and confirm: + password2 = getpass.getpass("Confirm: ") + if password != password2: + sys.exit("Error: Passwords do not match.") + if not password: + password = None + return password + + + +def run_non_RPC(config): + cmdname = config.get('cmd') + + storage = WalletStorage(config.get_wallet_path()) + if storage.file_exists(): + sys.exit("Error: Remove the existing wallet first!") + + def password_dialog(): + return prompt_password("Password (hit return if you do not wish to encrypt your wallet):") + + if cmdname == 'restore': + text = config.get('text').strip() + passphrase = config.get('passphrase', '') + password = password_dialog() if keystore.is_private(text) else None + if keystore.is_address_list(text): + wallet = Imported_Wallet(storage) + for x in text.split(): + wallet.import_address(x) + elif keystore.is_private_key_list(text): + k = keystore.Imported_KeyStore({}) + storage.put('keystore', k.dump()) + storage.put('use_encryption', bool(password)) + wallet = Imported_Wallet(storage) + for x in text.split(): + wallet.import_private_key(x, password) + storage.write() + else: + if keystore.is_seed(text): + k = keystore.from_seed(text, passphrase, False) + elif keystore.is_master_key(text): + k = keystore.from_master_key(text) + else: + sys.exit("Error: Seed or key not recognized") + if password: + k.update_password(None, password) + storage.put('keystore', k.dump()) + storage.put('wallet_type', 'standard') + storage.put('use_encryption', bool(password)) + storage.write() + wallet = Wallet(storage) + if not config.get('offline'): + network = Network(config) + network.start() + wallet.start_threads(network) + print_msg("Recovering wallet...") + wallet.synchronize() + wallet.wait_until_synchronized() + msg = "Recovery successful" if wallet.is_found() else "Found no history for this wallet" + else: + msg = "This wallet was restored offline. It may contain more addresses than displayed." + print_msg(msg) + + elif cmdname == 'create': + password = password_dialog() + passphrase = config.get('passphrase', '') + seed_type = 'segwit' if config.get('segwit') else 'standard' + seed = Mnemonic('en').make_seed(seed_type) + k = keystore.from_seed(seed, passphrase, False) + storage.put('keystore', k.dump()) + storage.put('wallet_type', 'standard') + wallet = Wallet(storage) + wallet.update_password(None, password, True) + wallet.synchronize() + print_msg("Your wallet generation seed is:\n\"%s\"" % seed) + print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.") + + wallet.storage.write() + print_msg("Wallet saved in '%s'" % wallet.storage.path) + sys.exit(0) + + +def init_daemon(config_options): + config = SimpleConfig(config_options) + storage = WalletStorage(config.get_wallet_path()) + if not storage.file_exists(): + print_msg("Error: Wallet file not found.") + print_msg("Type 'electrum-xzc create' to create a new wallet, or provide a path to a wallet with the -w option") + sys.exit(0) + if storage.is_encrypted(): + if config.get('password'): + password = config.get('password') + else: + password = prompt_password('Password:', False) + if not password: + print_msg("Error: Password required") + sys.exit(1) + else: + password = None + config_options['password'] = password + + +def init_cmdline(config_options, server): + config = SimpleConfig(config_options) + cmdname = config.get('cmd') + cmd = known_commands[cmdname] + + if cmdname == 'signtransaction' and config.get('privkey'): + cmd.requires_wallet = False + cmd.requires_password = False + + if cmdname in ['payto', 'paytomany'] and config.get('unsigned'): + cmd.requires_password = False + + if cmdname in ['payto', 'paytomany'] and config.get('broadcast'): + cmd.requires_network = True + + # instanciate wallet for command-line + storage = WalletStorage(config.get_wallet_path()) + + if cmd.requires_wallet and not storage.file_exists(): + print_msg("Error: Wallet file not found.") + print_msg("Type 'electrum-xzc create' to create a new wallet, or provide a path to a wallet with the -w option") + sys.exit(0) + + # important warning + if cmd.name in ['getprivatekeys']: + print_stderr("WARNING: ALL your private keys are secret.") + print_stderr("Exposing a single private key can compromise your entire wallet!") + print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.") + + # commands needing password + if (cmd.requires_wallet and storage.is_encrypted() and server is None)\ + or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())): + if config.get('password'): + password = config.get('password') + else: + password = prompt_password('Password:', False) + if not password: + print_msg("Error: Password required") + sys.exit(1) + else: + password = None + + config_options['password'] = password + + if cmd.name == 'password': + new_password = prompt_password('New password:') + config_options['new_password'] = new_password + + return cmd, password + + +def run_offline_command(config, config_options): + cmdname = config.get('cmd') + cmd = known_commands[cmdname] + password = config_options.get('password') + if cmd.requires_wallet: + storage = WalletStorage(config.get_wallet_path()) + if storage.is_encrypted(): + storage.decrypt(password) + wallet = Wallet(storage) + else: + wallet = None + # check password + if cmd.requires_password and storage.get('use_encryption'): + try: + seed = wallet.check_password(password) + except InvalidPassword: + print_msg("Error: This password does not decode this wallet.") + sys.exit(1) + if cmd.requires_network: + print_msg("Warning: running command offline") + # arguments passed to function + args = [config.get(x) for x in cmd.params] + # decode json arguments + if cmdname not in ('setconfig',): + args = list(map(json_decode, args)) + # options + kwargs = {} + for x in cmd.options: + kwargs[x] = (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)) + cmd_runner = Commands(config, wallet, None) + func = getattr(cmd_runner, cmd.name) + result = func(*args, **kwargs) + # save wallet + if wallet: + wallet.storage.write() + return result + +def init_plugins(config, gui_name): + from electrum_xzc.plugins import Plugins + return Plugins(config, is_local or is_android, gui_name) + + +if __name__ == '__main__': + # The hook will only be used in the Qt GUI right now + util.setup_thread_excepthook() + # on osx, delete Process Serial Number arg generated for apps launched in Finder + sys.argv = list(filter(lambda x: not x.startswith('-psn'), sys.argv)) + + # old 'help' syntax + if len(sys.argv) > 1 and sys.argv[1] == 'help': + sys.argv.remove('help') + sys.argv.append('-h') + + # read arguments from stdin pipe and prompt + for i, arg in enumerate(sys.argv): + if arg == '-': + if not sys.stdin.isatty(): + sys.argv[i] = sys.stdin.read() + break + else: + raise BaseException('Cannot get argument from stdin') + elif arg == '?': + sys.argv[i] = input("Enter argument:") + elif arg == ':': + sys.argv[i] = prompt_password('Enter argument (will not echo):', False) + + # parse command line + parser = get_parser() + args = parser.parse_args() + + # config is an object passed to the various constructors (wallet, interface, gui) + if is_android: + config_options = { + 'verbose': True, + 'cmd': 'gui', + 'gui': 'kivy', + } + else: + config_options = args.__dict__ + f = lambda key: config_options[key] is not None and key not in config_variables.get(args.cmd, {}).keys() + config_options = {key: config_options[key] for key in filter(f, config_options.keys())} + if config_options.get('server'): + config_options['auto_connect'] = False + + config_options['cwd'] = os.getcwd() + + # fixme: this can probably be achieved with a runtime hook (pyinstaller) + if is_bundle and os.path.exists(os.path.join(sys._MEIPASS, 'is_portable')): + config_options['portable'] = True + + if config_options.get('portable'): + config_options['electrum_path'] = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'electrum-xzc_data') + + # kivy sometimes freezes when we write to sys.stderr + set_verbosity(config_options.get('verbose') and config_options.get('gui')!='kivy') + + # check uri + uri = config_options.get('url') + if uri: + if not uri.startswith('zcoin:'): + print_stderr('unknown command:', uri) + sys.exit(1) + config_options['url'] = uri + + # todo: defer this to gui + config = SimpleConfig(config_options) + cmdname = config.get('cmd') + + if config.get('testnet'): + bitcoin.NetworkConstants.set_testnet() + + # run non-RPC commands separately + if cmdname in ['create', 'restore']: + run_non_RPC(config) + sys.exit(0) + + if cmdname == 'gui': + fd, server = daemon.get_fd_or_server(config) + if fd is not None: + plugins = init_plugins(config, config.get('gui', 'qt')) + d = daemon.Daemon(config, fd, True) + d.start() + d.init_gui(config, plugins) + sys.exit(0) + else: + result = server.gui(config_options) + + elif cmdname == 'daemon': + subcommand = config.get('subcommand') + if subcommand in ['load_wallet']: + init_daemon(config_options) + + if subcommand in [None, 'start']: + fd, server = daemon.get_fd_or_server(config) + if fd is not None: + if subcommand == 'start': + pid = os.fork() + if pid: + print_stderr("starting daemon (PID %d)" % pid) + sys.exit(0) + init_plugins(config, 'cmdline') + d = daemon.Daemon(config, fd, False) + d.start() + if config.get('websocket_server'): + from electrum_xzc import websockets + websockets.WebSocketServer(config, d.network).start() + if config.get('requests_dir'): + path = os.path.join(config.get('requests_dir'), 'index.html') + if not os.path.exists(path): + print("Requests directory not configured.") + print("You can configure it using https://github.com/sn-ntu/electrum-xzc-merchant") + sys.exit(1) + d.join() + sys.exit(0) + else: + result = server.daemon(config_options) + else: + server = daemon.get_server(config) + if server is not None: + result = server.daemon(config_options) + else: + print_msg("Daemon not running") + sys.exit(1) + else: + # command line + server = daemon.get_server(config) + init_cmdline(config_options, server) + if server is not None: + result = server.run_cmdline(config_options) + else: + cmd = known_commands[cmdname] + if cmd.requires_network: + print_msg("Daemon not running; try 'electrum-xzc daemon start'") + sys.exit(1) + else: + init_plugins(config, 'cmdline') + result = run_offline_command(config, config_options) + # print result + if isinstance(result, str): + print_msg(result) + elif type(result) is dict and result.get('error'): + print_stderr(result.get('error')) + elif result is not None: + print_msg(json_encode(result)) + sys.exit(0) diff --git a/electrum-xzc.conf.sample b/electrum-xzc.conf.sample new file mode 100644 index 000000000000..f2afaf5daf3e --- /dev/null +++ b/electrum-xzc.conf.sample @@ -0,0 +1,16 @@ +# Configuration file for the electrum client +# Settings defined here are shared across wallets +# +# copy this file to /etc/electrum-xzc.conf if you want read-only settings + +[client] +server = 45.63.92.224:50001:t +proxy = None +gap_limit = 5 +# booleans use python syntax +use_change = True +gui = qt +num_zeros = 2 +# default transaction fee is in Satoshis +fee = 100000 +winpos-qt = [799, 226, 877, 435] diff --git a/electrum-xzc.desktop b/electrum-xzc.desktop new file mode 100644 index 000000000000..1706961438ef --- /dev/null +++ b/electrum-xzc.desktop @@ -0,0 +1,17 @@ +# If you want electrum to appear in a linux app launcher ("start menu"), install this by doing: +# sudo desktop-file-install electrum.desktop + +[Desktop Entry] +Comment=Lightweight Zcoin Client +Exec=electrum-xzc %u +GenericName[en_US]=Zcoin Wallet +GenericName=Zcoin Wallet +Icon=electrum-xzc +Name[en_US]=Electrum Zcoin Wallet +Name=Electrum Zcoin Wallet +Categories=Finance;Network; +StartupNotify=false +Terminal=false +Type=Application +MimeType=x-scheme-handler/zcoin; + diff --git a/electrum.icns b/electrum.icns index 977b124d0d26..57efaa563ed3 100644 Binary files a/electrum.icns and b/electrum.icns differ diff --git a/exlib/lyra2z-py/Lyra2.c b/exlib/lyra2z-py/Lyra2.c new file mode 100644 index 000000000000..a1a07b2f5b43 --- /dev/null +++ b/exlib/lyra2z-py/Lyra2.c @@ -0,0 +1,197 @@ +/** + * Implementation of the Lyra2 Password Hashing Scheme (PHS). + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#ifndef _MSC_VER +# include +#endif +#include +#include "Lyra2.h" +#include "Sponge.h" + +/** + * Executes Lyra2 based on the G function from Blake2b. This version supports salts and passwords + * whose combined length is smaller than the size of the memory matrix, (i.e., (nRows x nCols x b) bits, + * where "b" is the underlying sponge's bitrate). In this implementation, the "basil" is composed by all + * integer parameters (treated as type "unsigned int") in the order they are provided, plus the value + * of nCols, (i.e., basil = kLen || pwdlen || saltlen || timeCost || nRows || nCols). + * + * @param K The derived key to be output by the algorithm + * @param kLen Desired key length + * @param pwd User password + * @param pwdlen Password length + * @param salt Salt + * @param saltlen Salt length + * @param timeCost Parameter to determine the processing time (T) + * @param nRows Number or rows of the memory matrix (R) + * @param nCols Number of columns of the memory matrix (C) + * + * @return 0 if the key is generated correctly; -1 if there is an error (usually due to lack of memory for allocation) + */ +int LYRA2(uint64_t* wholeMatrix, void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols) { + + //============================= Basic variables ============================// + int64_t row = 2; //index of row to be processed + int64_t prev = 1; //index of prev (last row ever computed/modified) + int64_t rowa = 0; //index of row* (a previous row, deterministically picked during Setup and randomly picked while Wandering) + int64_t tau; //Time Loop iterator + int64_t step = 1; //Visitation step (used during Setup and Wandering phases) + int64_t window = 2; //Visitation window (used to define which rows can be revisited during Setup) + int64_t gap = 1; //Modifier to the step, assuming the values 1 or -1 + //==========================================================================/ + + //========== Initializing the Memory Matrix and pointers to it =============// + //Tries to allocate enough space for the whole memory matrix + + + const int64_t ROW_LEN_INT64 = BLOCK_LEN_INT64 * nCols; + const int64_t ROW_LEN_BYTES = ROW_LEN_INT64 * 8; + + if (wholeMatrix == NULL) { + return -1; + } + + //==========================================================================/ + + //============= Getting the password + salt + basil padded with 10*1 ===============// + //OBS.:The memory matrix will temporarily hold the password: not for saving memory, + //but this ensures that the password copied locally will be overwritten as soon as possible + + //First, we clean enough blocks for the password, salt, basil and padding + uint64_t nBlocksInput = ((saltlen + pwdlen + 6 * sizeof (uint64_t)) / BLOCK_LEN_BLAKE2_SAFE_BYTES) + 1; + byte *ptrByte = (byte*) wholeMatrix; + memset(ptrByte, 0, nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES); + + //Prepends the password + memcpy(ptrByte, pwd, pwdlen); + ptrByte += pwdlen; + + //Concatenates the salt + memcpy(ptrByte, salt, saltlen); + ptrByte += saltlen; + + //Concatenates the basil: every integer passed as parameter, in the order they are provided by the interface + memcpy(ptrByte, &kLen, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + memcpy(ptrByte, &pwdlen, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + memcpy(ptrByte, &saltlen, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + memcpy(ptrByte, &timeCost, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + memcpy(ptrByte, &nRows, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + memcpy(ptrByte, &nCols, sizeof (uint64_t)); + ptrByte += sizeof (uint64_t); + + //Now comes the padding + *ptrByte = 0x80; //first byte of padding: right after the password + ptrByte = (byte*) wholeMatrix; //resets the pointer to the start of the memory matrix + ptrByte += nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - 1; //sets the pointer to the correct position: end of incomplete block + *ptrByte ^= 0x01; //last byte of padding: at the end of the last incomplete block + //==========================================================================/ + + //======================= Initializing the Sponge State ====================// + //Sponge state: 16 uint64_t, BLOCK_LEN_INT64 words of them for the bitrate (b) and the remainder for the capacity (c) + uint64_t *state = _mm_malloc(16 * sizeof (uint64_t), 32); + if (state == NULL) { + return -1; + } + initState(state); + //==========================================================================/ + + //================================ Setup Phase =============================// + //Absorbing salt, password and basil: this is the only place in which the block length is hard-coded to 512 bits + uint64_t *ptrWord = wholeMatrix; + for (int i = 0; i < nBlocksInput; i++) { + absorbBlockBlake2Safe(state, ptrWord); //absorbs each block of pad(pwd || salt || basil) + ptrWord += BLOCK_LEN_BLAKE2_SAFE_INT64; //goes to next block of pad(pwd || salt || basil) + } + + //Initializes M[0] and M[1] + reducedSqueezeRow0(state, &wholeMatrix[0], nCols); //The locally copied password is most likely overwritten here + reducedDuplexRow1(state, &wholeMatrix[0], &wholeMatrix[ROW_LEN_INT64], nCols); + + do { + //M[row] = rand; //M[row*] = M[row*] XOR rotW(rand) + reducedDuplexRowSetup(state, &wholeMatrix[prev*ROW_LEN_INT64], &wholeMatrix[rowa*ROW_LEN_INT64], &wholeMatrix[row*ROW_LEN_INT64], nCols); + + //updates the value of row* (deterministically picked during Setup)) + rowa = (rowa + step) & (window - 1); + //update prev: it now points to the last row ever computed + prev = row; + //updates row: goes to the next row to be computed + row++; + + //Checks if all rows in the window where visited. + if (rowa == 0) { + step = window + gap; //changes the step: approximately doubles its value + window *= 2; //doubles the size of the re-visitation window + gap = -gap; //inverts the modifier to the step + } + + } while (row < nRows); + //==========================================================================/ + + //============================ Wandering Phase =============================// + row = 0; //Resets the visitation to the first row of the memory matrix + for (tau = 1; tau <= timeCost; tau++) { + //Step is approximately half the number of all rows of the memory matrix for an odd tau; otherwise, it is -1 + step = (tau % 2 == 0) ? -1 : nRows / 2 - 1; + do { + //Selects a pseudorandom index row* + //------------------------------------------------------------------------------------------ + //rowa = ((unsigned int)state[0]) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + rowa = ((uint64_t) (state[0])) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + //Performs a reduced-round duplexing operation over M[row*] XOR M[prev], updating both M[row*] and M[row] + reducedDuplexRow(state, &wholeMatrix[prev*ROW_LEN_INT64], &wholeMatrix[rowa*ROW_LEN_INT64], &wholeMatrix[row*ROW_LEN_INT64], nCols); + + //update prev: it now points to the last row ever computed + prev = row; + + //updates row: goes to the next row to be computed + //------------------------------------------------------------------------------------------ + //row = (row + step) & (nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + row = (row + step) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + } while (row != 0); + } + //==========================================================================/ + + //============================ Wrap-up Phase ===============================// + //Absorbs the last block of the memory matrix + absorbBlock(state, &wholeMatrix[rowa*ROW_LEN_INT64]); + + //Squeezes the key + squeeze(state, K, kLen); + //==========================================================================/ + + //========================= Freeing the memory =============================// + _mm_free(state); + //==========================================================================/ + + return 0; +} + diff --git a/exlib/lyra2z-py/Lyra2.h b/exlib/lyra2z-py/Lyra2.h new file mode 100644 index 000000000000..0e53680ca2e1 --- /dev/null +++ b/exlib/lyra2z-py/Lyra2.h @@ -0,0 +1,51 @@ +/** + * Header file for the Lyra2 Password Hashing Scheme (PHS). + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef LYRA2_H_ +#define LYRA2_H_ + +#include + +typedef unsigned char byte; + +//Block length required so Blake2's Initialization Vector (IV) is not overwritten (THIS SHOULD NOT BE MODIFIED) +#define BLOCK_LEN_BLAKE2_SAFE_INT64 8 //512 bits (=64 bytes, =8 uint64_t) +#define BLOCK_LEN_BLAKE2_SAFE_BYTES (BLOCK_LEN_BLAKE2_SAFE_INT64 * 8) //same as above, in bytes + + +#ifdef BLOCK_LEN_BITS + #define BLOCK_LEN_INT64 (BLOCK_LEN_BITS/64) //Block length: 768 bits (=96 bytes, =12 uint64_t) + #define BLOCK_LEN_BYTES (BLOCK_LEN_BITS/8) //Block length, in bytes +#else //default block lenght: 768 bits + #define BLOCK_LEN_INT64 12 //Block length: 768 bits (=96 bytes, =12 uint64_t) + #define BLOCK_LEN_BYTES (BLOCK_LEN_INT64 * 8) //Block length, in bytes +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + int LYRA2(uint64_t* matrix, void *K, uint64_t kLen, const void *pwd, uint64_t pwdlen, const void *salt, uint64_t saltlen, uint64_t timeCost, uint64_t nRows, uint64_t nCols); + +#ifdef __cplusplus +} + +#endif + +#endif /* LYRA2_H_ */ diff --git a/exlib/lyra2z-py/README.md b/exlib/lyra2z-py/README.md new file mode 100644 index 000000000000..08acbf44cff6 --- /dev/null +++ b/exlib/lyra2z-py/README.md @@ -0,0 +1,55 @@ + +---------------------------------- +Python C module for lyra2z hashing +---------------------------------- + +Notes for Zcoin: +---------------- + +Module: lyra2z_hash + +Please see the "test.py" for a testcase + +From a previous readme from ocminer (updated): + +Requirements: +------------- +In order to run P2Pool and other Python based pools with the Zcoin network, you would need to build and install the +lyra2z_hash module for Python that includes the lyra2z proof of work code that Zcoin uses for hashes. + +Linux: + + sudo python setup.py install + + +Windows (mingw): +* Install MinGW: http://www.mingw.org/wiki/Getting_Started +* Install Python 2.7: http://www.python.org/getit/ + +In cmd type this: + + C:\Python27\python.exe setup.py build --compile=mingw32 install + + - untested + + +Windows (microsoft visual c++) +* Open visual studio console + +In cmd type this: + + SET VS90COMNTOOLS=%VS140COMNTOOLS% # For visual c++ 2015 + C:\Python27\python.exe setup.py install + + Test the install: + + C:\Python27\python.exe + ... + >>>import lyra2z_hash + >>>help('lyra2z_hash') + >>>quit() + + - tested ok + + + diff --git a/exlib/lyra2z-py/Sponge.c b/exlib/lyra2z-py/Sponge.c new file mode 100644 index 000000000000..c82f2ae54313 --- /dev/null +++ b/exlib/lyra2z-py/Sponge.c @@ -0,0 +1,832 @@ +/** + * A simple implementation of Blake2b's internal permutation + * in the form of a sponge. + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "Sponge.h" +#include "Lyra2.h" + +#include + +/** + * Initializes the Sponge State. The first 512 bits are set to zeros and the remainder + * receive Blake2b's IV as per Blake2b's specification. Note: Even though sponges + * typically have their internal state initialized with zeros, Blake2b's G function + * has a fixed point: if the internal state and message are both filled with zeros. the + * resulting permutation will always be a block filled with zeros; this happens because + * Blake2b does not use the constants originally employed in Blake2 inside its G function, + * relying on the IV for avoiding possible fixed points. + * + * @param state The 1024-bit array to be initialized + */ +inline void initState(uint64_t state[/*16*/]) { + //First 512 bis are zeros + memset(state, 0, 64); + //Remainder BLOCK_LEN_BLAKE2_SAFE_BYTES are reserved to the IV + state[8] = blake2b_IV[0]; + state[9] = blake2b_IV[1]; + state[10] = blake2b_IV[2]; + state[11] = blake2b_IV[3]; + state[12] = blake2b_IV[4]; + state[13] = blake2b_IV[5]; + state[14] = blake2b_IV[6]; + state[15] = blake2b_IV[7]; +} + +/** + * Execute Blake2b's G function, with all 12 rounds. + * + * @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function + */ +inline static void blake2bLyra(uint64_t *v) { + ROUND_LYRA(0); + ROUND_LYRA(1); + ROUND_LYRA(2); + ROUND_LYRA(3); + ROUND_LYRA(4); + ROUND_LYRA(5); + ROUND_LYRA(6); + ROUND_LYRA(7); + ROUND_LYRA(8); + ROUND_LYRA(9); + ROUND_LYRA(10); + ROUND_LYRA(11); +} + +/** + * Executes a reduced version of Blake2b's G function with only one round + * @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function + */ +inline static void reducedBlake2bLyra(uint64_t *v) { + ROUND_LYRA(0); +} + +/** + * Performs a squeeze operation, using Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param out Array that will receive the data squeezed + * @param len The number of bytes to be squeezed into the "out" array + */ +inline void squeeze(uint64_t *state, byte *out, unsigned int len) { + int fullBlocks = len / BLOCK_LEN_BYTES; + byte *ptr = out; + int i; + //Squeezes full blocks + for (i = 0; i < fullBlocks; i++) { + memcpy(ptr, state, BLOCK_LEN_BYTES); + blake2bLyra(state); + ptr += BLOCK_LEN_BYTES; + } + + //Squeezes remaining bytes + memcpy(ptr, state, (len % BLOCK_LEN_BYTES)); +} + +/** + * Performs an absorb operation for a single block (BLOCK_LEN_INT64 words + * of type uint64_t), using Blake2b's G function as the internal permutation + * + * @param state The current state of the sponge + * @param in The block to be absorbed (BLOCK_LEN_INT64 words) + */ +inline void absorbBlock(uint64_t *state, const uint64_t *in) { + //XORs the first BLOCK_LEN_INT64 words of "in" with the current state + state[0] ^= in[0]; + state[1] ^= in[1]; + state[2] ^= in[2]; + state[3] ^= in[3]; + state[4] ^= in[4]; + state[5] ^= in[5]; + state[6] ^= in[6]; + state[7] ^= in[7]; + state[8] ^= in[8]; + state[9] ^= in[9]; + state[10] ^= in[10]; + state[11] ^= in[11]; + + //Applies the transformation f to the sponge's state + blake2bLyra(state); +} + +/** + * Performs an absorb operation for a single block (BLOCK_LEN_BLAKE2_SAFE_INT64 + * words of type uint64_t), using Blake2b's G function as the internal permutation + * + * @param state The current state of the sponge + * @param in The block to be absorbed (BLOCK_LEN_BLAKE2_SAFE_INT64 words) + */ +inline void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in) { + //XORs the first BLOCK_LEN_BLAKE2_SAFE_INT64 words of "in" with the current state + + state[0] ^= in[0]; + state[1] ^= in[1]; + state[2] ^= in[2]; + state[3] ^= in[3]; + state[4] ^= in[4]; + state[5] ^= in[5]; + state[6] ^= in[6]; + state[7] ^= in[7]; + + + //Applies the transformation f to the sponge's state + blake2bLyra(state); + +} + +/** + * Performs a reduced squeeze operation for a single row, from the highest to + * the lowest index, using the reduced-round Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param rowOut Row to receive the data squeezed + */ +inline void reducedSqueezeRow0(uint64_t* state, uint64_t* rowOut, uint64_t nCols) { + uint64_t* ptrWord = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to M[0][C-1] + int i; + //M[row][C-1-col] = H.reduced_squeeze() + for (i = 0; i < nCols; i++) { + ptrWord[0] = state[0]; + ptrWord[1] = state[1]; + ptrWord[2] = state[2]; + ptrWord[3] = state[3]; + ptrWord[4] = state[4]; + ptrWord[5] = state[5]; + ptrWord[6] = state[6]; + ptrWord[7] = state[7]; + ptrWord[8] = state[8]; + ptrWord[9] = state[9]; + ptrWord[10] = state[10]; + ptrWord[11] = state[11]; + + //Goes to next block (column) that will receive the squeezed data + ptrWord -= BLOCK_LEN_INT64; + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + } +} + +/** + * Performs a reduced duplex operation for a single row, from the highest to + * the lowest index, using the reduced-round Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param rowIn Row to feed the sponge + * @param rowOut Row to receive the sponge's output + */ +inline void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut, uint64_t nCols) { + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordOut = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row + int i; + + for (i = 0; i < nCols; i++) { + + //Absorbing "M[prev][col]" + state[0] ^= (ptrWordIn[0]); + state[1] ^= (ptrWordIn[1]); + state[2] ^= (ptrWordIn[2]); + state[3] ^= (ptrWordIn[3]); + state[4] ^= (ptrWordIn[4]); + state[5] ^= (ptrWordIn[5]); + state[6] ^= (ptrWordIn[6]); + state[7] ^= (ptrWordIn[7]); + state[8] ^= (ptrWordIn[8]); + state[9] ^= (ptrWordIn[9]); + state[10] ^= (ptrWordIn[10]); + state[11] ^= (ptrWordIn[11]); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[row][C-1-col] = M[prev][col] XOR rand + ptrWordOut[0] = ptrWordIn[0] ^ state[0]; + ptrWordOut[1] = ptrWordIn[1] ^ state[1]; + ptrWordOut[2] = ptrWordIn[2] ^ state[2]; + ptrWordOut[3] = ptrWordIn[3] ^ state[3]; + ptrWordOut[4] = ptrWordIn[4] ^ state[4]; + ptrWordOut[5] = ptrWordIn[5] ^ state[5]; + ptrWordOut[6] = ptrWordIn[6] ^ state[6]; + ptrWordOut[7] = ptrWordIn[7] ^ state[7]; + ptrWordOut[8] = ptrWordIn[8] ^ state[8]; + ptrWordOut[9] = ptrWordIn[9] ^ state[9]; + ptrWordOut[10] = ptrWordIn[10] ^ state[10]; + ptrWordOut[11] = ptrWordIn[11] ^ state[11]; + + + //Input: next column (i.e., next block in sequence) + ptrWordIn += BLOCK_LEN_INT64; + //Output: goes to previous column + ptrWordOut -= BLOCK_LEN_INT64; + } +} + +/** + * Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e., + * the wordwise addition of two columns, ignoring carries between words). The + * output of this operation, "rand", is then used to make + * "M[rowOut][(N_COLS-1)-col] = M[rowIn][col] XOR rand" and + * "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit + * rotation to the left and N_COLS is a system parameter. + * + * @param state The current state of the sponge + * @param rowIn Row used only as input + * @param rowInOut Row used as input and to receive output after rotation + * @param rowOut Row receiving the output + * + */ +inline void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, uint64_t nCols) { + + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row* + uint64_t* ptrWordOut = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row + +#ifdef __AVX2__ + __m256i* vstate = (__m256i*)state; + __m256i* vptrWordIn = (__m256i*)ptrWordIn; //In Lyra2: pointer to prev + __m256i* vptrWordInOut = (__m256i*)ptrWordInOut; //In Lyra2: pointer to row* + __m256i* vptrWordOut = (__m256i*)ptrWordOut; //In Lyra2: pointer to row + + for (int i = 0; i < nCols; i++) { + //Absorbing "M[prev] [+] M[row*]" + vstate[0] = _mm256_xor_si256(vstate[0], _mm256_add_epi64(vptrWordIn[0], vptrWordInOut[0])); + vstate[1] = _mm256_xor_si256(vstate[1], _mm256_add_epi64(vptrWordIn[1], vptrWordInOut[1])); + vstate[2] = _mm256_xor_si256(vstate[2], _mm256_add_epi64(vptrWordIn[2], vptrWordInOut[2])); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[row][col] = M[prev][col] XOR rand + vptrWordOut[0] = _mm256_xor_si256(vptrWordIn[0], vstate[0]); + vptrWordOut[1] = _mm256_xor_si256(vptrWordIn[1], vstate[1]); + vptrWordOut[2] = _mm256_xor_si256(vptrWordIn[2], vstate[2]); + + //M[row*][col] = M[row*][col] XOR rotW(rand) + __m256i x1 = _mm256_permute4x64_epi64(vstate[0], 0x93); + __m256i x2 = _mm256_permute4x64_epi64(vstate[1], 0x93); + __m256i x3 = _mm256_permute4x64_epi64(vstate[2], 0x93); + vptrWordInOut[0] = _mm256_xor_si256(vptrWordInOut[0], _mm256_blend_epi32(x1, x3, 0x03)); + vptrWordInOut[1] = _mm256_xor_si256(vptrWordInOut[1], _mm256_blend_epi32(x2, x1, 0x03)); + vptrWordInOut[2] = _mm256_xor_si256(vptrWordInOut[2], _mm256_blend_epi32(x3, x2, 0x03)); + + //Inputs: next column (i.e., next block in sequence) + vptrWordInOut += (BLOCK_LEN_INT64 / 4); + vptrWordIn += (BLOCK_LEN_INT64 / 4); + //Output: goes to previous column + vptrWordOut -= (BLOCK_LEN_INT64 / 4); + } +#else + for (int i = 0; i < nCols; i++) { + //Absorbing "M[prev] [+] M[row*]" + state[0] ^= (ptrWordIn[0] + ptrWordInOut[0]); + state[1] ^= (ptrWordIn[1] + ptrWordInOut[1]); + state[2] ^= (ptrWordIn[2] + ptrWordInOut[2]); + state[3] ^= (ptrWordIn[3] + ptrWordInOut[3]); + state[4] ^= (ptrWordIn[4] + ptrWordInOut[4]); + state[5] ^= (ptrWordIn[5] + ptrWordInOut[5]); + state[6] ^= (ptrWordIn[6] + ptrWordInOut[6]); + state[7] ^= (ptrWordIn[7] + ptrWordInOut[7]); + state[8] ^= (ptrWordIn[8] + ptrWordInOut[8]); + state[9] ^= (ptrWordIn[9] + ptrWordInOut[9]); + state[10] ^= (ptrWordIn[10] + ptrWordInOut[10]); + state[11] ^= (ptrWordIn[11] + ptrWordInOut[11]); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[row][col] = M[prev][col] XOR rand + ptrWordOut[0] = ptrWordIn[0] ^ state[0]; + ptrWordOut[1] = ptrWordIn[1] ^ state[1]; + ptrWordOut[2] = ptrWordIn[2] ^ state[2]; + ptrWordOut[3] = ptrWordIn[3] ^ state[3]; + ptrWordOut[4] = ptrWordIn[4] ^ state[4]; + ptrWordOut[5] = ptrWordIn[5] ^ state[5]; + ptrWordOut[6] = ptrWordIn[6] ^ state[6]; + ptrWordOut[7] = ptrWordIn[7] ^ state[7]; + ptrWordOut[8] = ptrWordIn[8] ^ state[8]; + ptrWordOut[9] = ptrWordIn[9] ^ state[9]; + ptrWordOut[10] = ptrWordIn[10] ^ state[10]; + ptrWordOut[11] = ptrWordIn[11] ^ state[11]; + + //M[row*][col] = M[row*][col] XOR rotW(rand) + ptrWordInOut[0] ^= state[11]; + ptrWordInOut[1] ^= state[0]; + ptrWordInOut[2] ^= state[1]; + ptrWordInOut[3] ^= state[2]; + ptrWordInOut[4] ^= state[3]; + ptrWordInOut[5] ^= state[4]; + ptrWordInOut[6] ^= state[5]; + ptrWordInOut[7] ^= state[6]; + ptrWordInOut[8] ^= state[7]; + ptrWordInOut[9] ^= state[8]; + ptrWordInOut[10] ^= state[9]; + ptrWordInOut[11] ^= state[10]; + + //Inputs: next column (i.e., next block in sequence) + ptrWordInOut += BLOCK_LEN_INT64; + ptrWordIn += BLOCK_LEN_INT64; + //Output: goes to previous column + ptrWordOut -= BLOCK_LEN_INT64; + } +#endif +} + +/** + * Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e., + * the wordwise addition of two columns, ignoring carries between words). The + * output of this operation, "rand", is then used to make + * "M[rowOut][col] = M[rowOut][col] XOR rand" and + * "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit + * rotation to the left. + * + * @param state The current state of the sponge + * @param rowIn Row used only as input + * @param rowInOut Row used as input and to receive output after rotation + * @param rowOut Row receiving the output + * + */ +inline void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, uint64_t nCols) { + uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row* + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row + +#ifdef __AVX2__ + __m256i* vstate = (__m256i*)state; + __m256i* vptrWordIn = (__m256i*)ptrWordIn; //In Lyra2: pointer to prev + __m256i* vptrWordInOut = (__m256i*)ptrWordInOut; //In Lyra2: pointer to row* + __m256i* vptrWordOut = (__m256i*)ptrWordOut; //In Lyra2: pointer to row + + int prefetch_distance = 3*3; +#ifdef ROW_PREFETCH + for(int i=0; i + +#if defined(__GNUC__) +#define ALIGN __attribute__ ((aligned(32))) +#elif defined(_MSC_VER) +#define ALIGN __declspec(align(32)) +#else +#define ALIGN +#endif + + +/*Blake2b IV Array*/ +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/*Blake2b's rotation*/ +static inline uint64_t rotr64( const uint64_t w, const unsigned c ){ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/*Blake2b's G function*/ +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + + +/*One Round of the Blake2b's compression function*/ +#define ROUND_LYRA(r) \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); + +//---- Housekeeping +extern void initState(uint64_t state[/*16*/]); + +//---- Squeezes +extern void squeeze(uint64_t *state, unsigned char *out, unsigned int len); +extern void reducedSqueezeRow0(uint64_t* state, uint64_t* row, uint64_t nCols); + +//---- Absorbs +extern void absorbBlock(uint64_t *state, const uint64_t *in); +extern void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in); + +//---- Duplexes +extern void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut, uint64_t nCols); +extern void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, uint64_t nCols); +extern void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, uint64_t nCols); + +//---- Misc +void printArray(unsigned char *array, unsigned int size, char *name); + +//////////////////////////////////////////////////////////////////////////////////////////////// + + +////TESTS//// +//void reducedDuplexRowc(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut); +//void reducedDuplexRowd(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut); +//void reducedDuplexRowSetupv4(uint64_t *state, uint64_t *rowIn1, uint64_t *rowIn2, uint64_t *rowOut1, uint64_t *rowOut2); +//void reducedDuplexRowSetupv5(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut); +//void reducedDuplexRowSetupv5c(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut); +//void reducedDuplexRowSetupv5d(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut); +///////////// + + +#endif /* SPONGE_H_ */ diff --git a/exlib/lyra2z-py/blake.c b/exlib/lyra2z-py/blake.c new file mode 100644 index 000000000000..28b32a71495a --- /dev/null +++ b/exlib/lyra2z-py/blake.c @@ -0,0 +1,1121 @@ +/* $Id: blake.c 252 2011-06-07 17:55:14Z tp $ */ +/* + * BLAKE implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include +#include + +#include "sph_blake.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_BLAKE +#define SPH_SMALL_FOOTPRINT_BLAKE 1 +#endif + +#if SPH_SMALL_FOOTPRINT_BLAKE +#define SPH_COMPACT_BLAKE_32 1 +#endif + +#if SPH_64 && (SPH_SMALL_FOOTPRINT_BLAKE || !SPH_64_TRUE) +#define SPH_COMPACT_BLAKE_64 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV224[8] = { + SPH_C32(0xC1059ED8), SPH_C32(0x367CD507), + SPH_C32(0x3070DD17), SPH_C32(0xF70E5939), + SPH_C32(0xFFC00B31), SPH_C32(0x68581511), + SPH_C32(0x64F98FA7), SPH_C32(0xBEFA4FA4) +}; + +static const sph_u32 IV256[8] = { + SPH_C32(0x6A09E667), SPH_C32(0xBB67AE85), + SPH_C32(0x3C6EF372), SPH_C32(0xA54FF53A), + SPH_C32(0x510E527F), SPH_C32(0x9B05688C), + SPH_C32(0x1F83D9AB), SPH_C32(0x5BE0CD19) +}; + +#if SPH_64 + +static const sph_u64 IV384[8] = { + SPH_C64(0xCBBB9D5DC1059ED8), SPH_C64(0x629A292A367CD507), + SPH_C64(0x9159015A3070DD17), SPH_C64(0x152FECD8F70E5939), + SPH_C64(0x67332667FFC00B31), SPH_C64(0x8EB44A8768581511), + SPH_C64(0xDB0C2E0D64F98FA7), SPH_C64(0x47B5481DBEFA4FA4) +}; + +static const sph_u64 IV512[8] = { + SPH_C64(0x6A09E667F3BCC908), SPH_C64(0xBB67AE8584CAA73B), + SPH_C64(0x3C6EF372FE94F82B), SPH_C64(0xA54FF53A5F1D36F1), + SPH_C64(0x510E527FADE682D1), SPH_C64(0x9B05688C2B3E6C1F), + SPH_C64(0x1F83D9ABFB41BD6B), SPH_C64(0x5BE0CD19137E2179) +}; + +#endif + +#if SPH_COMPACT_BLAKE_32 || SPH_COMPACT_BLAKE_64 + +static const unsigned sigma[16][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } +}; + +/* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 + 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 + 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 + 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 + 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 + 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 + 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 + 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 + 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 +*/ +#endif + +#define Z00 0 +#define Z01 1 +#define Z02 2 +#define Z03 3 +#define Z04 4 +#define Z05 5 +#define Z06 6 +#define Z07 7 +#define Z08 8 +#define Z09 9 +#define Z0A A +#define Z0B B +#define Z0C C +#define Z0D D +#define Z0E E +#define Z0F F + +#define Z10 E +#define Z11 A +#define Z12 4 +#define Z13 8 +#define Z14 9 +#define Z15 F +#define Z16 D +#define Z17 6 +#define Z18 1 +#define Z19 C +#define Z1A 0 +#define Z1B 2 +#define Z1C B +#define Z1D 7 +#define Z1E 5 +#define Z1F 3 + +#define Z20 B +#define Z21 8 +#define Z22 C +#define Z23 0 +#define Z24 5 +#define Z25 2 +#define Z26 F +#define Z27 D +#define Z28 A +#define Z29 E +#define Z2A 3 +#define Z2B 6 +#define Z2C 7 +#define Z2D 1 +#define Z2E 9 +#define Z2F 4 + +#define Z30 7 +#define Z31 9 +#define Z32 3 +#define Z33 1 +#define Z34 D +#define Z35 C +#define Z36 B +#define Z37 E +#define Z38 2 +#define Z39 6 +#define Z3A 5 +#define Z3B A +#define Z3C 4 +#define Z3D 0 +#define Z3E F +#define Z3F 8 + +#define Z40 9 +#define Z41 0 +#define Z42 5 +#define Z43 7 +#define Z44 2 +#define Z45 4 +#define Z46 A +#define Z47 F +#define Z48 E +#define Z49 1 +#define Z4A B +#define Z4B C +#define Z4C 6 +#define Z4D 8 +#define Z4E 3 +#define Z4F D + +#define Z50 2 +#define Z51 C +#define Z52 6 +#define Z53 A +#define Z54 0 +#define Z55 B +#define Z56 8 +#define Z57 3 +#define Z58 4 +#define Z59 D +#define Z5A 7 +#define Z5B 5 +#define Z5C F +#define Z5D E +#define Z5E 1 +#define Z5F 9 + +#define Z60 C +#define Z61 5 +#define Z62 1 +#define Z63 F +#define Z64 E +#define Z65 D +#define Z66 4 +#define Z67 A +#define Z68 0 +#define Z69 7 +#define Z6A 6 +#define Z6B 3 +#define Z6C 9 +#define Z6D 2 +#define Z6E 8 +#define Z6F B + +#define Z70 D +#define Z71 B +#define Z72 7 +#define Z73 E +#define Z74 C +#define Z75 1 +#define Z76 3 +#define Z77 9 +#define Z78 5 +#define Z79 0 +#define Z7A F +#define Z7B 4 +#define Z7C 8 +#define Z7D 6 +#define Z7E 2 +#define Z7F A + +#define Z80 6 +#define Z81 F +#define Z82 E +#define Z83 9 +#define Z84 B +#define Z85 3 +#define Z86 0 +#define Z87 8 +#define Z88 C +#define Z89 2 +#define Z8A D +#define Z8B 7 +#define Z8C 1 +#define Z8D 4 +#define Z8E A +#define Z8F 5 + +#define Z90 A +#define Z91 2 +#define Z92 8 +#define Z93 4 +#define Z94 7 +#define Z95 6 +#define Z96 1 +#define Z97 5 +#define Z98 F +#define Z99 B +#define Z9A 9 +#define Z9B E +#define Z9C 3 +#define Z9D C +#define Z9E D +#define Z9F 0 + +#define Mx(r, i) Mx_(Z ## r ## i) +#define Mx_(n) Mx__(n) +#define Mx__(n) M ## n + +#define CSx(r, i) CSx_(Z ## r ## i) +#define CSx_(n) CSx__(n) +#define CSx__(n) CS ## n + +#define CS0 SPH_C32(0x243F6A88) +#define CS1 SPH_C32(0x85A308D3) +#define CS2 SPH_C32(0x13198A2E) +#define CS3 SPH_C32(0x03707344) +#define CS4 SPH_C32(0xA4093822) +#define CS5 SPH_C32(0x299F31D0) +#define CS6 SPH_C32(0x082EFA98) +#define CS7 SPH_C32(0xEC4E6C89) +#define CS8 SPH_C32(0x452821E6) +#define CS9 SPH_C32(0x38D01377) +#define CSA SPH_C32(0xBE5466CF) +#define CSB SPH_C32(0x34E90C6C) +#define CSC SPH_C32(0xC0AC29B7) +#define CSD SPH_C32(0xC97C50DD) +#define CSE SPH_C32(0x3F84D5B5) +#define CSF SPH_C32(0xB5470917) + +#if SPH_COMPACT_BLAKE_32 + +static const sph_u32 CS[16] = { + SPH_C32(0x243F6A88), SPH_C32(0x85A308D3), + SPH_C32(0x13198A2E), SPH_C32(0x03707344), + SPH_C32(0xA4093822), SPH_C32(0x299F31D0), + SPH_C32(0x082EFA98), SPH_C32(0xEC4E6C89), + SPH_C32(0x452821E6), SPH_C32(0x38D01377), + SPH_C32(0xBE5466CF), SPH_C32(0x34E90C6C), + SPH_C32(0xC0AC29B7), SPH_C32(0xC97C50DD), + SPH_C32(0x3F84D5B5), SPH_C32(0xB5470917) +}; + +#endif + +#if SPH_64 + +#define CBx(r, i) CBx_(Z ## r ## i) +#define CBx_(n) CBx__(n) +#define CBx__(n) CB ## n + +#define CB0 SPH_C64(0x243F6A8885A308D3) +#define CB1 SPH_C64(0x13198A2E03707344) +#define CB2 SPH_C64(0xA4093822299F31D0) +#define CB3 SPH_C64(0x082EFA98EC4E6C89) +#define CB4 SPH_C64(0x452821E638D01377) +#define CB5 SPH_C64(0xBE5466CF34E90C6C) +#define CB6 SPH_C64(0xC0AC29B7C97C50DD) +#define CB7 SPH_C64(0x3F84D5B5B5470917) +#define CB8 SPH_C64(0x9216D5D98979FB1B) +#define CB9 SPH_C64(0xD1310BA698DFB5AC) +#define CBA SPH_C64(0x2FFD72DBD01ADFB7) +#define CBB SPH_C64(0xB8E1AFED6A267E96) +#define CBC SPH_C64(0xBA7C9045F12C7F99) +#define CBD SPH_C64(0x24A19947B3916CF7) +#define CBE SPH_C64(0x0801F2E2858EFC16) +#define CBF SPH_C64(0x636920D871574E69) + +#if SPH_COMPACT_BLAKE_64 + +static const sph_u64 CB[16] = { + SPH_C64(0x243F6A8885A308D3), SPH_C64(0x13198A2E03707344), + SPH_C64(0xA4093822299F31D0), SPH_C64(0x082EFA98EC4E6C89), + SPH_C64(0x452821E638D01377), SPH_C64(0xBE5466CF34E90C6C), + SPH_C64(0xC0AC29B7C97C50DD), SPH_C64(0x3F84D5B5B5470917), + SPH_C64(0x9216D5D98979FB1B), SPH_C64(0xD1310BA698DFB5AC), + SPH_C64(0x2FFD72DBD01ADFB7), SPH_C64(0xB8E1AFED6A267E96), + SPH_C64(0xBA7C9045F12C7F99), SPH_C64(0x24A19947B3916CF7), + SPH_C64(0x0801F2E2858EFC16), SPH_C64(0x636920D871574E69) +}; + +#endif + +#endif + +#define GS(m0, m1, c0, c1, a, b, c, d) do { \ + a = SPH_T32(a + b + (m0 ^ c1)); \ + d = SPH_ROTR32(d ^ a, 16); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 12); \ + a = SPH_T32(a + b + (m1 ^ c0)); \ + d = SPH_ROTR32(d ^ a, 8); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 7); \ + } while (0) + +#if SPH_COMPACT_BLAKE_32 + +#define ROUND_S(r) do { \ + GS(M[sigma[r][0x0]], M[sigma[r][0x1]], \ + CS[sigma[r][0x0]], CS[sigma[r][0x1]], V0, V4, V8, VC); \ + GS(M[sigma[r][0x2]], M[sigma[r][0x3]], \ + CS[sigma[r][0x2]], CS[sigma[r][0x3]], V1, V5, V9, VD); \ + GS(M[sigma[r][0x4]], M[sigma[r][0x5]], \ + CS[sigma[r][0x4]], CS[sigma[r][0x5]], V2, V6, VA, VE); \ + GS(M[sigma[r][0x6]], M[sigma[r][0x7]], \ + CS[sigma[r][0x6]], CS[sigma[r][0x7]], V3, V7, VB, VF); \ + GS(M[sigma[r][0x8]], M[sigma[r][0x9]], \ + CS[sigma[r][0x8]], CS[sigma[r][0x9]], V0, V5, VA, VF); \ + GS(M[sigma[r][0xA]], M[sigma[r][0xB]], \ + CS[sigma[r][0xA]], CS[sigma[r][0xB]], V1, V6, VB, VC); \ + GS(M[sigma[r][0xC]], M[sigma[r][0xD]], \ + CS[sigma[r][0xC]], CS[sigma[r][0xD]], V2, V7, V8, VD); \ + GS(M[sigma[r][0xE]], M[sigma[r][0xF]], \ + CS[sigma[r][0xE]], CS[sigma[r][0xF]], V3, V4, V9, VE); \ + } while (0) + +#else + +#define ROUND_S(r) do { \ + GS(Mx(r, 0), Mx(r, 1), CSx(r, 0), CSx(r, 1), V0, V4, V8, VC); \ + GS(Mx(r, 2), Mx(r, 3), CSx(r, 2), CSx(r, 3), V1, V5, V9, VD); \ + GS(Mx(r, 4), Mx(r, 5), CSx(r, 4), CSx(r, 5), V2, V6, VA, VE); \ + GS(Mx(r, 6), Mx(r, 7), CSx(r, 6), CSx(r, 7), V3, V7, VB, VF); \ + GS(Mx(r, 8), Mx(r, 9), CSx(r, 8), CSx(r, 9), V0, V5, VA, VF); \ + GS(Mx(r, A), Mx(r, B), CSx(r, A), CSx(r, B), V1, V6, VB, VC); \ + GS(Mx(r, C), Mx(r, D), CSx(r, C), CSx(r, D), V2, V7, V8, VD); \ + GS(Mx(r, E), Mx(r, F), CSx(r, E), CSx(r, F), V3, V4, V9, VE); \ + } while (0) + +#endif + +#if SPH_64 + +#define GB(m0, m1, c0, c1, a, b, c, d) do { \ + a = SPH_T64(a + b + (m0 ^ c1)); \ + d = SPH_ROTR64(d ^ a, 32); \ + c = SPH_T64(c + d); \ + b = SPH_ROTR64(b ^ c, 25); \ + a = SPH_T64(a + b + (m1 ^ c0)); \ + d = SPH_ROTR64(d ^ a, 16); \ + c = SPH_T64(c + d); \ + b = SPH_ROTR64(b ^ c, 11); \ + } while (0) + +#if SPH_COMPACT_BLAKE_64 + +#define ROUND_B(r) do { \ + GB(M[sigma[r][0x0]], M[sigma[r][0x1]], \ + CB[sigma[r][0x0]], CB[sigma[r][0x1]], V0, V4, V8, VC); \ + GB(M[sigma[r][0x2]], M[sigma[r][0x3]], \ + CB[sigma[r][0x2]], CB[sigma[r][0x3]], V1, V5, V9, VD); \ + GB(M[sigma[r][0x4]], M[sigma[r][0x5]], \ + CB[sigma[r][0x4]], CB[sigma[r][0x5]], V2, V6, VA, VE); \ + GB(M[sigma[r][0x6]], M[sigma[r][0x7]], \ + CB[sigma[r][0x6]], CB[sigma[r][0x7]], V3, V7, VB, VF); \ + GB(M[sigma[r][0x8]], M[sigma[r][0x9]], \ + CB[sigma[r][0x8]], CB[sigma[r][0x9]], V0, V5, VA, VF); \ + GB(M[sigma[r][0xA]], M[sigma[r][0xB]], \ + CB[sigma[r][0xA]], CB[sigma[r][0xB]], V1, V6, VB, VC); \ + GB(M[sigma[r][0xC]], M[sigma[r][0xD]], \ + CB[sigma[r][0xC]], CB[sigma[r][0xD]], V2, V7, V8, VD); \ + GB(M[sigma[r][0xE]], M[sigma[r][0xF]], \ + CB[sigma[r][0xE]], CB[sigma[r][0xF]], V3, V4, V9, VE); \ + } while (0) + +#else + +#define ROUND_B(r) do { \ + GB(Mx(r, 0), Mx(r, 1), CBx(r, 0), CBx(r, 1), V0, V4, V8, VC); \ + GB(Mx(r, 2), Mx(r, 3), CBx(r, 2), CBx(r, 3), V1, V5, V9, VD); \ + GB(Mx(r, 4), Mx(r, 5), CBx(r, 4), CBx(r, 5), V2, V6, VA, VE); \ + GB(Mx(r, 6), Mx(r, 7), CBx(r, 6), CBx(r, 7), V3, V7, VB, VF); \ + GB(Mx(r, 8), Mx(r, 9), CBx(r, 8), CBx(r, 9), V0, V5, VA, VF); \ + GB(Mx(r, A), Mx(r, B), CBx(r, A), CBx(r, B), V1, V6, VB, VC); \ + GB(Mx(r, C), Mx(r, D), CBx(r, C), CBx(r, D), V2, V7, V8, VD); \ + GB(Mx(r, E), Mx(r, F), CBx(r, E), CBx(r, F), V3, V4, V9, VE); \ + } while (0) + +#endif + +#endif + +#define DECL_STATE32 \ + sph_u32 H0, H1, H2, H3, H4, H5, H6, H7; \ + sph_u32 S0, S1, S2, S3, T0, T1; + +#define READ_STATE32(state) do { \ + H0 = (state)->H[0]; \ + H1 = (state)->H[1]; \ + H2 = (state)->H[2]; \ + H3 = (state)->H[3]; \ + H4 = (state)->H[4]; \ + H5 = (state)->H[5]; \ + H6 = (state)->H[6]; \ + H7 = (state)->H[7]; \ + S0 = (state)->S[0]; \ + S1 = (state)->S[1]; \ + S2 = (state)->S[2]; \ + S3 = (state)->S[3]; \ + T0 = (state)->T0; \ + T1 = (state)->T1; \ + } while (0) + +#define WRITE_STATE32(state) do { \ + (state)->H[0] = H0; \ + (state)->H[1] = H1; \ + (state)->H[2] = H2; \ + (state)->H[3] = H3; \ + (state)->H[4] = H4; \ + (state)->H[5] = H5; \ + (state)->H[6] = H6; \ + (state)->H[7] = H7; \ + (state)->S[0] = S0; \ + (state)->S[1] = S1; \ + (state)->S[2] = S2; \ + (state)->S[3] = S3; \ + (state)->T0 = T0; \ + (state)->T1 = T1; \ + } while (0) + +#if SPH_COMPACT_BLAKE_32 + +#define COMPRESS32 do { \ + sph_u32 M[16]; \ + sph_u32 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u32 V8, V9, VA, VB, VC, VD, VE, VF; \ + unsigned r; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CS0; \ + V9 = S1 ^ CS1; \ + VA = S2 ^ CS2; \ + VB = S3 ^ CS3; \ + VC = T0 ^ CS4; \ + VD = T0 ^ CS5; \ + VE = T1 ^ CS6; \ + VF = T1 ^ CS7; \ + M[0x0] = sph_dec32be_aligned(buf + 0); \ + M[0x1] = sph_dec32be_aligned(buf + 4); \ + M[0x2] = sph_dec32be_aligned(buf + 8); \ + M[0x3] = sph_dec32be_aligned(buf + 12); \ + M[0x4] = sph_dec32be_aligned(buf + 16); \ + M[0x5] = sph_dec32be_aligned(buf + 20); \ + M[0x6] = sph_dec32be_aligned(buf + 24); \ + M[0x7] = sph_dec32be_aligned(buf + 28); \ + M[0x8] = sph_dec32be_aligned(buf + 32); \ + M[0x9] = sph_dec32be_aligned(buf + 36); \ + M[0xA] = sph_dec32be_aligned(buf + 40); \ + M[0xB] = sph_dec32be_aligned(buf + 44); \ + M[0xC] = sph_dec32be_aligned(buf + 48); \ + M[0xD] = sph_dec32be_aligned(buf + 52); \ + M[0xE] = sph_dec32be_aligned(buf + 56); \ + M[0xF] = sph_dec32be_aligned(buf + 60); \ + for (r = 0; r < 14; r ++) \ + ROUND_S(r); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#else + +#define COMPRESS32 do { \ + sph_u32 M0, M1, M2, M3, M4, M5, M6, M7; \ + sph_u32 M8, M9, MA, MB, MC, MD, ME, MF; \ + sph_u32 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u32 V8, V9, VA, VB, VC, VD, VE, VF; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CS0; \ + V9 = S1 ^ CS1; \ + VA = S2 ^ CS2; \ + VB = S3 ^ CS3; \ + VC = T0 ^ CS4; \ + VD = T0 ^ CS5; \ + VE = T1 ^ CS6; \ + VF = T1 ^ CS7; \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + M8 = sph_dec32be_aligned(buf + 32); \ + M9 = sph_dec32be_aligned(buf + 36); \ + MA = sph_dec32be_aligned(buf + 40); \ + MB = sph_dec32be_aligned(buf + 44); \ + MC = sph_dec32be_aligned(buf + 48); \ + MD = sph_dec32be_aligned(buf + 52); \ + ME = sph_dec32be_aligned(buf + 56); \ + MF = sph_dec32be_aligned(buf + 60); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + ROUND_S(4); \ + ROUND_S(5); \ + ROUND_S(6); \ + ROUND_S(7); \ + ROUND_S(8); \ + ROUND_S(9); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#endif + +#if SPH_64 + +#define DECL_STATE64 \ + sph_u64 H0, H1, H2, H3, H4, H5, H6, H7; \ + sph_u64 S0, S1, S2, S3, T0, T1; + +#define READ_STATE64(state) do { \ + H0 = (state)->H[0]; \ + H1 = (state)->H[1]; \ + H2 = (state)->H[2]; \ + H3 = (state)->H[3]; \ + H4 = (state)->H[4]; \ + H5 = (state)->H[5]; \ + H6 = (state)->H[6]; \ + H7 = (state)->H[7]; \ + S0 = (state)->S[0]; \ + S1 = (state)->S[1]; \ + S2 = (state)->S[2]; \ + S3 = (state)->S[3]; \ + T0 = (state)->T0; \ + T1 = (state)->T1; \ + } while (0) + +#define WRITE_STATE64(state) do { \ + (state)->H[0] = H0; \ + (state)->H[1] = H1; \ + (state)->H[2] = H2; \ + (state)->H[3] = H3; \ + (state)->H[4] = H4; \ + (state)->H[5] = H5; \ + (state)->H[6] = H6; \ + (state)->H[7] = H7; \ + (state)->S[0] = S0; \ + (state)->S[1] = S1; \ + (state)->S[2] = S2; \ + (state)->S[3] = S3; \ + (state)->T0 = T0; \ + (state)->T1 = T1; \ + } while (0) + +#if SPH_COMPACT_BLAKE_64 + +#define COMPRESS64 do { \ + sph_u64 M[16]; \ + sph_u64 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u64 V8, V9, VA, VB, VC, VD, VE, VF; \ + unsigned r; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CB0; \ + V9 = S1 ^ CB1; \ + VA = S2 ^ CB2; \ + VB = S3 ^ CB3; \ + VC = T0 ^ CB4; \ + VD = T0 ^ CB5; \ + VE = T1 ^ CB6; \ + VF = T1 ^ CB7; \ + M[0x0] = sph_dec64be_aligned(buf + 0); \ + M[0x1] = sph_dec64be_aligned(buf + 8); \ + M[0x2] = sph_dec64be_aligned(buf + 16); \ + M[0x3] = sph_dec64be_aligned(buf + 24); \ + M[0x4] = sph_dec64be_aligned(buf + 32); \ + M[0x5] = sph_dec64be_aligned(buf + 40); \ + M[0x6] = sph_dec64be_aligned(buf + 48); \ + M[0x7] = sph_dec64be_aligned(buf + 56); \ + M[0x8] = sph_dec64be_aligned(buf + 64); \ + M[0x9] = sph_dec64be_aligned(buf + 72); \ + M[0xA] = sph_dec64be_aligned(buf + 80); \ + M[0xB] = sph_dec64be_aligned(buf + 88); \ + M[0xC] = sph_dec64be_aligned(buf + 96); \ + M[0xD] = sph_dec64be_aligned(buf + 104); \ + M[0xE] = sph_dec64be_aligned(buf + 112); \ + M[0xF] = sph_dec64be_aligned(buf + 120); \ + for (r = 0; r < 16; r ++) \ + ROUND_B(r); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#else + +#define COMPRESS64 do { \ + sph_u64 M0, M1, M2, M3, M4, M5, M6, M7; \ + sph_u64 M8, M9, MA, MB, MC, MD, ME, MF; \ + sph_u64 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u64 V8, V9, VA, VB, VC, VD, VE, VF; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CB0; \ + V9 = S1 ^ CB1; \ + VA = S2 ^ CB2; \ + VB = S3 ^ CB3; \ + VC = T0 ^ CB4; \ + VD = T0 ^ CB5; \ + VE = T1 ^ CB6; \ + VF = T1 ^ CB7; \ + M0 = sph_dec64be_aligned(buf + 0); \ + M1 = sph_dec64be_aligned(buf + 8); \ + M2 = sph_dec64be_aligned(buf + 16); \ + M3 = sph_dec64be_aligned(buf + 24); \ + M4 = sph_dec64be_aligned(buf + 32); \ + M5 = sph_dec64be_aligned(buf + 40); \ + M6 = sph_dec64be_aligned(buf + 48); \ + M7 = sph_dec64be_aligned(buf + 56); \ + M8 = sph_dec64be_aligned(buf + 64); \ + M9 = sph_dec64be_aligned(buf + 72); \ + MA = sph_dec64be_aligned(buf + 80); \ + MB = sph_dec64be_aligned(buf + 88); \ + MC = sph_dec64be_aligned(buf + 96); \ + MD = sph_dec64be_aligned(buf + 104); \ + ME = sph_dec64be_aligned(buf + 112); \ + MF = sph_dec64be_aligned(buf + 120); \ + ROUND_B(0); \ + ROUND_B(1); \ + ROUND_B(2); \ + ROUND_B(3); \ + ROUND_B(4); \ + ROUND_B(5); \ + ROUND_B(6); \ + ROUND_B(7); \ + ROUND_B(8); \ + ROUND_B(9); \ + ROUND_B(0); \ + ROUND_B(1); \ + ROUND_B(2); \ + ROUND_B(3); \ + ROUND_B(4); \ + ROUND_B(5); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#endif + +#endif + +static const sph_u32 salt_zero_small[4] = { 0, 0, 0, 0 }; + +static void +blake32_init(sph_blake_small_context *sc, + const sph_u32 *iv, const sph_u32 *salt) +{ + memcpy(sc->H, iv, 8 * sizeof(sph_u32)); + memcpy(sc->S, salt, 4 * sizeof(sph_u32)); + sc->T0 = sc->T1 = 0; + sc->ptr = 0; +} + +static void +blake32(sph_blake_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE32 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE32(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((T0 = SPH_T32(T0 + 512)) < 512) + T1 = SPH_T32(T1 + 1); + COMPRESS32; + ptr = 0; + } + } + WRITE_STATE32(sc); + sc->ptr = ptr; +} + +static void +blake32_close(sph_blake_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + union { + unsigned char buf[64]; + sph_u32 dummy; + } u; + size_t ptr, k; + unsigned bit_len; + unsigned z; + sph_u32 th, tl; + unsigned char *out; + + ptr = sc->ptr; + bit_len = ((unsigned)ptr << 3) + n; + z = 0x80 >> n; + u.buf[ptr] = ((ub & -z) | z) & 0xFF; + tl = sc->T0 + bit_len; + th = sc->T1; + if (ptr == 0 && n == 0) { + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + } else if (sc->T0 == 0) { + sc->T0 = SPH_C32(0xFFFFFE00) + bit_len; + sc->T1 = SPH_T32(sc->T1 - 1); + } else { + sc->T0 -= 512 - bit_len; + } + if (bit_len <= 446) { + memset(u.buf + ptr + 1, 0, 55 - ptr); + if (out_size_w32 == 8) + u.buf[55] |= 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf + ptr, 64 - ptr); + } else { + memset(u.buf + ptr + 1, 0, 63 - ptr); + blake32(sc, u.buf + ptr, 64 - ptr); + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + memset(u.buf, 0, 56); + if (out_size_w32 == 8) + u.buf[55] = 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf, 64); + } + out = dst; + for (k = 0; k < out_size_w32; k ++) + sph_enc32be(out + (k << 2), sc->H[k]); +} + +#if SPH_64 + +static const sph_u64 salt_zero_big[4] = { 0, 0, 0, 0 }; + +static void +blake64_init(sph_blake_big_context *sc, + const sph_u64 *iv, const sph_u64 *salt) +{ + memcpy(sc->H, iv, 8 * sizeof(sph_u64)); + memcpy(sc->S, salt, 4 * sizeof(sph_u64)); + sc->T0 = sc->T1 = 0; + sc->ptr = 0; +} + +static void +blake64(sph_blake_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE64 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE64(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((T0 = SPH_T64(T0 + 1024)) < 1024) + T1 = SPH_T64(T1 + 1); + COMPRESS64; + ptr = 0; + } + } + WRITE_STATE64(sc); + sc->ptr = ptr; +} + +static void +blake64_close(sph_blake_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w64) +{ + union { + unsigned char buf[128]; + sph_u64 dummy; + } u; + size_t ptr, k; + unsigned bit_len; + unsigned z; + sph_u64 th, tl; + unsigned char *out; + + ptr = sc->ptr; + bit_len = ((unsigned)ptr << 3) + n; + z = 0x80 >> n; + u.buf[ptr] = ((ub & -z) | z) & 0xFF; + tl = sc->T0 + bit_len; + th = sc->T1; + if (ptr == 0 && n == 0) { + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00); + sc->T1 = SPH_C64(0xFFFFFFFFFFFFFFFF); + } else if (sc->T0 == 0) { + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00) + bit_len; + sc->T1 = SPH_T64(sc->T1 - 1); + } else { + sc->T0 -= 1024 - bit_len; + } + if (bit_len <= 894) { + memset(u.buf + ptr + 1, 0, 111 - ptr); + if (out_size_w64 == 8) + u.buf[111] |= 1; + sph_enc64be_aligned(u.buf + 112, th); + sph_enc64be_aligned(u.buf + 120, tl); + blake64(sc, u.buf + ptr, 128 - ptr); + } else { + memset(u.buf + ptr + 1, 0, 127 - ptr); + blake64(sc, u.buf + ptr, 128 - ptr); + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00); + sc->T1 = SPH_C64(0xFFFFFFFFFFFFFFFF); + memset(u.buf, 0, 112); + if (out_size_w64 == 8) + u.buf[111] = 1; + sph_enc64be_aligned(u.buf + 112, th); + sph_enc64be_aligned(u.buf + 120, tl); + blake64(sc, u.buf, 128); + } + out = dst; + for (k = 0; k < out_size_w64; k ++) + sph_enc64be(out + (k << 3), sc->H[k]); +} + +#endif + +/* see sph_blake.h */ +void +sph_blake224_init(void *cc) +{ + blake32_init(cc, IV224, salt_zero_small); +} + +/* see sph_blake.h */ +void +sph_blake224(void *cc, const void *data, size_t len) +{ + blake32(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake224_close(void *cc, void *dst) +{ + sph_blake224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake32_close(cc, ub, n, dst, 7); + sph_blake224_init(cc); +} + +/* see sph_blake.h */ +void +sph_blake256_init(void *cc) +{ + blake32_init(cc, IV256, salt_zero_small); +} + +/* see sph_blake.h */ +void +sph_blake256(void *cc, const void *data, size_t len) +{ + blake32(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake256_close(void *cc, void *dst) +{ + sph_blake256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake32_close(cc, ub, n, dst, 8); + sph_blake256_init(cc); +} + +#if SPH_64 + +/* see sph_blake.h */ +void +sph_blake384_init(void *cc) +{ + blake64_init(cc, IV384, salt_zero_big); +} + +/* see sph_blake.h */ +void +sph_blake384(void *cc, const void *data, size_t len) +{ + blake64(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake384_close(void *cc, void *dst) +{ + sph_blake384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake64_close(cc, ub, n, dst, 6); + sph_blake384_init(cc); +} + +/* see sph_blake.h */ +void +sph_blake512_init(void *cc) +{ + blake64_init(cc, IV512, salt_zero_big); +} + +/* see sph_blake.h */ +void +sph_blake512(void *cc, const void *data, size_t len) +{ + blake64(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake512_close(void *cc, void *dst) +{ + sph_blake512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake64_close(cc, ub, n, dst, 8); + sph_blake512_init(cc); +} + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/exlib/lyra2z-py/lyra2z-zcoin.c b/exlib/lyra2z-py/lyra2z-zcoin.c new file mode 100644 index 000000000000..0959ff87b6ec --- /dev/null +++ b/exlib/lyra2z-py/lyra2z-zcoin.c @@ -0,0 +1,44 @@ +// +// lyra2z-zcoin.c : windows test harness for Lyra2z hashing +// + +#include "lyra2z-zcoin.h" +#include "Lyra2z.h" +#include + +static const char test[] = { + 0x70, 0x00, 0x00, 0x00, 0x5d, 0x38, 0x5b, 0xa1, + 0x14, 0xd0, 0x79, 0x97, 0x1b, 0x29, 0xa9, 0x41, + 0x8f, 0xd0, 0x54, 0x9e, 0x7d, 0x68, 0xa9, 0x5c, + 0x7f, 0x16, 0x86, 0x21, 0xa3, 0x14, 0x20, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x85, 0x86, 0xd1, + 0x49, 0xfd, 0x07, 0xb2, 0x2f, 0x3a, 0x8a, 0x34, + 0x7c, 0x51, 0x6d, 0xe7, 0x05, 0x2f, 0x03, 0x4d, + 0x2b, 0x76, 0xff, 0x68, 0xe0, 0xd6, 0xec, 0xff, + 0x9b, 0x77, 0xa4, 0x54, 0x89, 0xe3, 0xfd, 0x51, + 0x17, 0x32, 0x01, 0x1d, 0xf0, 0x73, 0x10, 0x00 +}; +static const testlen = sizeof(test); + +#define OUTLEN 32 +static char out[OUTLEN]; + +static void dump(char* d, int len) { + int i = 0; + if (d == NULL || len < 1) { + printf("do me a favor...\n"); + return; + } + for (i = 0; i < len; i++) { + printf("%02x ", (unsigned char)d[i]); + } + printf("\n"); +} + +int main() +{ + lyra2z_hash(out, test); + dump(out, OUTLEN); + return 0; +} + diff --git a/exlib/lyra2z-py/lyra2z-zcoin.h b/exlib/lyra2z-py/lyra2z-zcoin.h new file mode 100644 index 000000000000..503f3e410ca5 --- /dev/null +++ b/exlib/lyra2z-py/lyra2z-zcoin.h @@ -0,0 +1,13 @@ +#pragma once +// +// Windows only stuff +// + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. +#define _WIN32_WINNT _WIN32_WINNT_WIN7 +#include + +#include diff --git a/exlib/lyra2z-py/lyra2z-zcoin.sln b/exlib/lyra2z-py/lyra2z-zcoin.sln new file mode 100644 index 000000000000..ed0bdb0cc3c5 --- /dev/null +++ b/exlib/lyra2z-py/lyra2z-zcoin.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lyra2z-zcoin", "lyra2z-zcoin.vcxproj", "{12DBC121-1B34-45B1-82BC-91F9EC4D1062}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Debug|x64.ActiveCfg = Debug|x64 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Debug|x64.Build.0 = Debug|x64 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Debug|x86.ActiveCfg = Debug|Win32 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Debug|x86.Build.0 = Debug|Win32 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Release|x64.ActiveCfg = Release|x64 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Release|x64.Build.0 = Release|x64 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Release|x86.ActiveCfg = Release|Win32 + {12DBC121-1B34-45B1-82BC-91F9EC4D1062}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/exlib/lyra2z-py/lyra2z.c b/exlib/lyra2z-py/lyra2z.c new file mode 100644 index 000000000000..cdd07b515f96 --- /dev/null +++ b/exlib/lyra2z-py/lyra2z.c @@ -0,0 +1,117 @@ +// +// Hacked from cpuminer-xzc +// + +#ifdef _MSC_VER +# define _mm_malloc _aligned_malloc +#else +# include +# include +#endif + +#include +#include "sph_blake.h" +#include "Lyra2.h" + +static void get_lyra2z_hash(uint64_t* mtx, void *state, const void *input) +{ + sph_blake256_context ctx_blake; + + uint32_t hashA[8], hashB[8]; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + + LYRA2(mtx, hashB, 32, hashA, 32, hashA, 32, 8, 8, 8); + + memcpy(state, hashB, 32); +} + +void lyra2z_hash(void *output, const void *input) +{ + size_t size = (int64_t)((int64_t)16 * 16 * 96); // from cpuminer-xzc + // Windows: _aligned_malloc(size,align) + uint64_t *mtx = _mm_malloc(size, 64); // freed in algo + get_lyra2z_hash(mtx, output, input); +} + + +// cpuminer +// +#if 0 +void lyra2z_hash(uint64_t* wholeMatrix, void *state, const void *input) +{ +#ifdef VERBOSE_HASH_TIMING + struct timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + double start = spec.tv_sec + spec.tv_nsec / 1.0e9; +#endif + + sph_blake256_context ctx_blake; + + uint32_t hashA[8], hashB[8]; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + +// LYRA2(0, hashB, 32, hashA, 32, hashA, 32, 2, 8, 8); + + LYRA2(wholeMatrix, hashB, 32, hashA, 32, hashA, 32, 8, 8, 8); + +#ifdef VERBOSE_HASH_TIMING + if (hash[0] % 32 == 0) { + clock_gettime(CLOCK_REALTIME, &spec); + double end = spec.tv_sec + spec.tv_nsec / 1.0e9; + printf("Hash time: %f ms\n", (end - start) * 1000); + } +#endif + + memcpy(state, hashB, 32); +} + +int scanhash_lyra2z(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + + size_t size = (int64_t)((int64_t)16 * 16 * 96); + uint64_t *wholeMatrix = _mm_malloc(size, 64); + + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x0000ff; + + for (int i = 0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], nonce); + lyra2z_hash(wholeMatrix, hash, endiandata); + // lyra2z_hash(0, hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + _mm_free(wholeMatrix); + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + _mm_free(wholeMatrix); + return 0; +} +#endif // 0 diff --git a/exlib/lyra2z-py/lyra2z.h b/exlib/lyra2z-py/lyra2z.h new file mode 100644 index 000000000000..7b26dd9d9e9e --- /dev/null +++ b/exlib/lyra2z-py/lyra2z.h @@ -0,0 +1,7 @@ + +#ifndef _LYRA2Z_H +# define _LYRA2Z_H + +void lyra2z_hash(void *output, const void *input); + +#endif // _LYRA2Z_H diff --git a/exlib/lyra2z-py/lyra2z_hash.egg-info/PKG-INFO b/exlib/lyra2z-py/lyra2z_hash.egg-info/PKG-INFO new file mode 100644 index 000000000000..9033864dc6df --- /dev/null +++ b/exlib/lyra2z-py/lyra2z_hash.egg-info/PKG-INFO @@ -0,0 +1,11 @@ +Metadata-Version: 1.0 +Name: lyra2z-hash +Version: 0.1.0 +Summary: Bindings for Lyra2Z proof of work used by Zcoin +Home-page: https://github.com/devwarrior777/lyra2z-py +Author: devwarrior +Author-email: devwarrior.zcoin@gmail.com +License: UNKNOWN +Description-Content-Type: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/exlib/lyra2z-py/lyra2z_hash.egg-info/SOURCES.txt b/exlib/lyra2z-py/lyra2z_hash.egg-info/SOURCES.txt new file mode 100644 index 000000000000..69959bfb3f6b --- /dev/null +++ b/exlib/lyra2z-py/lyra2z_hash.egg-info/SOURCES.txt @@ -0,0 +1,11 @@ +Lyra2.c +README.md +Sponge.c +blake.c +lyra2z.c +lyra2zmodule.c +setup.py +lyra2z_hash.egg-info/PKG-INFO +lyra2z_hash.egg-info/SOURCES.txt +lyra2z_hash.egg-info/dependency_links.txt +lyra2z_hash.egg-info/top_level.txt \ No newline at end of file diff --git a/exlib/lyra2z-py/lyra2z_hash.egg-info/dependency_links.txt b/exlib/lyra2z-py/lyra2z_hash.egg-info/dependency_links.txt new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/exlib/lyra2z-py/lyra2z_hash.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/exlib/lyra2z-py/lyra2z_hash.egg-info/top_level.txt b/exlib/lyra2z-py/lyra2z_hash.egg-info/top_level.txt new file mode 100644 index 000000000000..55f3839ca87d --- /dev/null +++ b/exlib/lyra2z-py/lyra2z_hash.egg-info/top_level.txt @@ -0,0 +1 @@ +lyra2z_hash diff --git a/exlib/lyra2z-py/lyra2zmodule.c b/exlib/lyra2z-py/lyra2zmodule.c new file mode 100644 index 000000000000..4bb430a46027 --- /dev/null +++ b/exlib/lyra2z-py/lyra2zmodule.c @@ -0,0 +1,57 @@ +#include + +#include "lyra2z.h" + +static PyObject *lyra2z_getpowhash(PyObject *self, PyObject *args) +{ + char *output; + PyObject *value; +#if PY_MAJOR_VERSION >= 3 + PyBytesObject *input; +#else + PyStringObject *input; +#endif + if (!PyArg_ParseTuple(args, "S", &input)) + return NULL; + Py_INCREF(input); + output = PyMem_Malloc(32); + +#if PY_MAJOR_VERSION >= 3 + lyra2z_hash((char *)PyBytes_AsString((PyObject*) input), output); +#else + lyra2z_hash((char *)PyString_AsString((PyObject*) input), output); +#endif + Py_DECREF(input); +#if PY_MAJOR_VERSION >= 3 + value = Py_BuildValue("y#", output, 32); +#else + value = Py_BuildValue("s#", output, 32); +#endif + PyMem_Free(output); + return value; +} + +static PyMethodDef Lyra2ZMethods[] = { + { "getPoWHash", lyra2z_getpowhash, METH_VARARGS, "Returns the proof of work hash using lyra2z hash" }, + { NULL, NULL, 0, NULL } +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef Lyra2ZModule = { + PyModuleDef_HEAD_INIT, + "lyra2z_hash", + "...", + -1, + Lyra2ZMethods +}; + +PyMODINIT_FUNC PyInit_lyra2z_hash(void) { + return PyModule_Create(&Lyra2ZModule); +} + +#else + +PyMODINIT_FUNC initlyra2z_hash(void) { + (void) Py_InitModule("lyra2z_hash", Lyra2ZMethods); +} +#endif diff --git a/exlib/lyra2z-py/setup.py b/exlib/lyra2z-py/setup.py new file mode 100644 index 000000000000..02b79dcdb185 --- /dev/null +++ b/exlib/lyra2z-py/setup.py @@ -0,0 +1,19 @@ +from setuptools import setup, Extension + +lyra2z_hash_module = Extension('lyra2z_hash', + sources = [ + 'lyra2zmodule.c', + 'lyra2z.c', + 'Sponge.c', + 'Lyra2.c', + 'blake.c'], + include_dirs=['.']) + +setup (name = 'lyra2z_hash', + version = '0.1.0', + author_email = 'devwarrior.zcoin@gmail.com', + author = 'devwarrior', + url = 'https://github.com/devwarrior777/lyra2z-py', + description = 'Bindings for Lyra2Z proof of work used by Zcoin', + ext_modules = [lyra2z_hash_module]) + diff --git a/exlib/lyra2z-py/sph_blake.h b/exlib/lyra2z-py/sph_blake.h new file mode 100644 index 000000000000..d8d794399d00 --- /dev/null +++ b/exlib/lyra2z-py/sph_blake.h @@ -0,0 +1,327 @@ +/* $Id: sph_blake.h 252 2011-06-07 17:55:14Z tp $ */ +/** + * BLAKE interface. BLAKE is a family of functions which differ by their + * output size; this implementation defines BLAKE for output sizes 224, + * 256, 384 and 512 bits. This implementation conforms to the "third + * round" specification. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_blake.h + * @author Thomas Pornin + */ + +#ifndef SPH_BLAKE_H__ +#define SPH_BLAKE_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for BLAKE-224. + */ +#define SPH_SIZE_blake224 224 + +/** + * Output size (in bits) for BLAKE-256. + */ +#define SPH_SIZE_blake256 256 + +#if SPH_64 + +/** + * Output size (in bits) for BLAKE-384. + */ +#define SPH_SIZE_blake384 384 + +/** + * Output size (in bits) for BLAKE-512. + */ +#define SPH_SIZE_blake512 512 + +#endif + +/** + * This structure is a context for BLAKE-224 and BLAKE-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BLAKE computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BLAKE + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[8]; + sph_u32 S[4]; + sph_u32 T0, T1; +#endif +} sph_blake_small_context; + +/** + * This structure is a context for BLAKE-224 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_small_context sph_blake224_context; + +/** + * This structure is a context for BLAKE-256 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_small_context sph_blake256_context; + +#if SPH_64 + +/** + * This structure is a context for BLAKE-384 and BLAKE-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BLAKE computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BLAKE + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[8]; + sph_u64 S[4]; + sph_u64 T0, T1; +#endif +} sph_blake_big_context; + +/** + * This structure is a context for BLAKE-384 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_big_context sph_blake384_context; + +/** + * This structure is a context for BLAKE-512 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_big_context sph_blake512_context; + +#endif + +/** + * Initialize a BLAKE-224 context. This process performs no memory allocation. + * + * @param cc the BLAKE-224 context (pointer to a + * sph_blake224_context) + */ +void sph_blake224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake224(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-224 context + * @param dst the destination buffer + */ +void sph_blake224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BLAKE-256 context. This process performs no memory allocation. + * + * @param cc the BLAKE-256 context (pointer to a + * sph_blake256_context) + */ +void sph_blake256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake256(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-256 context + * @param dst the destination buffer + */ +void sph_blake256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#if SPH_64 + +/** + * Initialize a BLAKE-384 context. This process performs no memory allocation. + * + * @param cc the BLAKE-384 context (pointer to a + * sph_blake384_context) + */ +void sph_blake384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake384(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-384 context + * @param dst the destination buffer + */ +void sph_blake384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BLAKE-512 context. This process performs no memory allocation. + * + * @param cc the BLAKE-512 context (pointer to a + * sph_blake512_context) + */ +void sph_blake512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake512(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-512 context + * @param dst the destination buffer + */ +void sph_blake512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/exlib/lyra2z-py/sph_types.h b/exlib/lyra2z-py/sph_types.h new file mode 100644 index 000000000000..6c8ecf4b676f --- /dev/null +++ b/exlib/lyra2z-py/sph_types.h @@ -0,0 +1,1986 @@ +/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef SPH_TYPES_H__ +#define SPH_TYPES_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +/* ============= BEGIN documentation block for Doxygen ============ */ + +#ifdef DOXYGEN_IGNORE + +/** @mainpage sphlib C code documentation + * + * @section overview Overview + * + * sphlib is a library which contains implementations of + * various cryptographic hash functions. These pages have been generated + * with doxygen and + * document the API for the C implementations. + * + * The API is described in appropriate header files, which are available + * in the "Files" section. Each hash function family has its own header, + * whose name begins with "sph_" and contains the family + * name. For instance, the API for the RIPEMD hash functions is available + * in the header file sph_ripemd.h. + * + * @section principles API structure and conventions + * + * @subsection io Input/output conventions + * + * In all generality, hash functions operate over strings of bits. + * Individual bits are rarely encountered in C programming or actual + * communication protocols; most protocols converge on the ubiquitous + * "octet" which is a group of eight bits. Data is thus expressed as a + * stream of octets. The C programming language contains the notion of a + * "byte", which is a data unit managed under the type "unsigned + * char". The C standard prescribes that a byte should hold at + * least eight bits, but possibly more. Most modern architectures, even + * in the embedded world, feature eight-bit bytes, i.e. map bytes to + * octets. + * + * Nevertheless, for some of the implemented hash functions, an extra + * API has been added, which allows the input of arbitrary sequences of + * bits: when the computation is about to be closed, 1 to 7 extra bits + * can be added. The functions for which this API is implemented include + * the SHA-2 functions and all SHA-3 candidates. + * + * sphlib defines hash function which may hash octet streams, + * i.e. streams of bits where the number of bits is a multiple of eight. + * The data input functions in the sphlib API expect data + * as anonymous pointers ("const void *") with a length + * (of type "size_t") which gives the input data chunk length + * in bytes. A byte is assumed to be an octet; the sph_types.h + * header contains a compile-time test which prevents compilation on + * architectures where this property is not met. + * + * The hash function output is also converted into bytes. All currently + * implemented hash functions have an output width which is a multiple of + * eight, and this is likely to remain true for new designs. + * + * Most hash functions internally convert input data into 32-bit of 64-bit + * words, using either little-endian or big-endian conversion. The hash + * output also often consists of such words, which are encoded into output + * bytes with a similar endianness convention. Some hash functions have + * been only loosely specified on that subject; when necessary, + * sphlib has been tested against published "reference" + * implementations in order to use the same conventions. + * + * @subsection shortname Function short name + * + * Each implemented hash function has a "short name" which is used + * internally to derive the identifiers for the functions and context + * structures which the function uses. For instance, MD5 has the short + * name "md5". Short names are listed in the next section, + * for the implemented hash functions. In subsequent sections, the + * short name will be assumed to be "XXX": replace with the + * actual hash function name to get the C identifier. + * + * Note: some functions within the same family share the same core + * elements, such as update function or context structure. Correspondingly, + * some of the defined types or functions may actually be macros which + * transparently evaluate to another type or function name. + * + * @subsection context Context structure + * + * Each implemented hash fonction has its own context structure, available + * under the type name "sph_XXX_context" for the hash function + * with short name "XXX". This structure holds all needed + * state for a running hash computation. + * + * The contents of these structures are meant to be opaque, and private + * to the implementation. However, these contents are specified in the + * header files so that application code which uses sphlib + * may access the size of those structures. + * + * The caller is responsible for allocating the context structure, + * whether by dynamic allocation (malloc() or equivalent), + * static allocation (a global permanent variable), as an automatic + * variable ("on the stack"), or by any other mean which ensures proper + * structure alignment. sphlib code performs no dynamic + * allocation by itself. + * + * The context must be initialized before use, using the + * sph_XXX_init() function. This function sets the context + * state to proper initial values for hashing. + * + * Since all state data is contained within the context structure, + * sphlib is thread-safe and reentrant: several hash + * computations may be performed in parallel, provided that they do not + * operate on the same context. Moreover, a running computation can be + * cloned by copying the context (with a simple memcpy()): + * the context and its clone are then independant and may be updated + * with new data and/or closed without interfering with each other. + * Similarly, a context structure can be moved in memory at will: + * context structures contain no pointer, in particular no pointer to + * themselves. + * + * @subsection dataio Data input + * + * Hashed data is input with the sph_XXX() fonction, which + * takes as parameters a pointer to the context, a pointer to the data + * to hash, and the number of data bytes to hash. The context is updated + * with the new data. + * + * Data can be input in one or several calls, with arbitrary input lengths. + * However, it is best, performance wise, to input data by relatively big + * chunks (say a few kilobytes), because this allows sphlib to + * optimize things and avoid internal copying. + * + * When all data has been input, the context can be closed with + * sph_XXX_close(). The hash output is computed and written + * into the provided buffer. The caller must take care to provide a + * buffer of appropriate length; e.g., when using SHA-1, the output is + * a 20-byte word, therefore the output buffer must be at least 20-byte + * long. + * + * For some hash functions, the sph_XXX_addbits_and_close() + * function can be used instead of sph_XXX_close(). This + * function can take a few extra bits to be added at + * the end of the input message. This allows hashing messages with a + * bit length which is not a multiple of 8. The extra bits are provided + * as an unsigned integer value, and a bit count. The bit count must be + * between 0 and 7, inclusive. The extra bits are provided as bits 7 to + * 0 (bits of numerical value 128, 64, 32... downto 0), in that order. + * For instance, to add three bits of value 1, 1 and 0, the unsigned + * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count + * will be 3. + * + * The SPH_SIZE_XXX macro is defined for each hash function; + * it evaluates to the function output size, expressed in bits. For instance, + * SPH_SIZE_sha1 evaluates to 160. + * + * When closed, the context is automatically reinitialized and can be + * immediately used for another computation. It is not necessary to call + * sph_XXX_init() after a close. Note that + * sph_XXX_init() can still be called to "reset" a context, + * i.e. forget previously input data, and get back to the initial state. + * + * @subsection alignment Data alignment + * + * "Alignment" is a property of data, which is said to be "properly + * aligned" when its emplacement in memory is such that the data can + * be optimally read by full words. This depends on the type of access; + * basically, some hash functions will read data by 32-bit or 64-bit + * words. sphlib does not mandate such alignment for input + * data, but using aligned data can substantially improve performance. + * + * As a rule, it is best to input data by chunks whose length (in bytes) + * is a multiple of eight, and which begins at "generally aligned" + * addresses, such as the base address returned by a call to + * malloc(). + * + * @section functions Implemented functions + * + * We give here the list of implemented functions. They are grouped by + * family; to each family corresponds a specific header file. Each + * individual function has its associated "short name". Please refer to + * the documentation for that header file to get details on the hash + * function denomination and provenance. + * + * Note: the functions marked with a '(64)' in the list below are + * available only if the C compiler provides an integer type of length + * 64 bits or more. Such a type is mandatory in the latest C standard + * (ISO 9899:1999, aka "C99") and is present in several older compilers + * as well, so chances are that such a type is available. + * + * - HAVAL family: file sph_haval.h + * - HAVAL-128/3 (128-bit, 3 passes): short name: haval128_3 + * - HAVAL-128/4 (128-bit, 4 passes): short name: haval128_4 + * - HAVAL-128/5 (128-bit, 5 passes): short name: haval128_5 + * - HAVAL-160/3 (160-bit, 3 passes): short name: haval160_3 + * - HAVAL-160/4 (160-bit, 4 passes): short name: haval160_4 + * - HAVAL-160/5 (160-bit, 5 passes): short name: haval160_5 + * - HAVAL-192/3 (192-bit, 3 passes): short name: haval192_3 + * - HAVAL-192/4 (192-bit, 4 passes): short name: haval192_4 + * - HAVAL-192/5 (192-bit, 5 passes): short name: haval192_5 + * - HAVAL-224/3 (224-bit, 3 passes): short name: haval224_3 + * - HAVAL-224/4 (224-bit, 4 passes): short name: haval224_4 + * - HAVAL-224/5 (224-bit, 5 passes): short name: haval224_5 + * - HAVAL-256/3 (256-bit, 3 passes): short name: haval256_3 + * - HAVAL-256/4 (256-bit, 4 passes): short name: haval256_4 + * - HAVAL-256/5 (256-bit, 5 passes): short name: haval256_5 + * - MD2: file sph_md2.h, short name: md2 + * - MD4: file sph_md4.h, short name: md4 + * - MD5: file sph_md5.h, short name: md5 + * - PANAMA: file sph_panama.h, short name: panama + * - RadioGatun family: file sph_radiogatun.h + * - RadioGatun[32]: short name: radiogatun32 + * - RadioGatun[64]: short name: radiogatun64 (64) + * - RIPEMD family: file sph_ripemd.h + * - RIPEMD: short name: ripemd + * - RIPEMD-128: short name: ripemd128 + * - RIPEMD-160: short name: ripemd160 + * - SHA-0: file sph_sha0.h, short name: sha0 + * - SHA-1: file sph_sha1.h, short name: sha1 + * - SHA-2 family, 32-bit hashes: file sph_sha2.h + * - SHA-224: short name: sha224 + * - SHA-256: short name: sha256 + * - SHA-384: short name: sha384 (64) + * - SHA-512: short name: sha512 (64) + * - Tiger family: file sph_tiger.h + * - Tiger: short name: tiger (64) + * - Tiger2: short name: tiger2 (64) + * - WHIRLPOOL family: file sph_whirlpool.h + * - WHIRLPOOL-0: short name: whirlpool0 (64) + * - WHIRLPOOL-1: short name: whirlpool1 (64) + * - WHIRLPOOL: short name: whirlpool (64) + * + * The fourteen second-round SHA-3 candidates are also implemented; + * when applicable, the implementations follow the "final" specifications + * as published for the third round of the SHA-3 competition (BLAKE, + * Groestl, JH, Keccak and Skein have been tweaked for third round). + * + * - BLAKE family: file sph_blake.h + * - BLAKE-224: short name: blake224 + * - BLAKE-256: short name: blake256 + * - BLAKE-384: short name: blake384 + * - BLAKE-512: short name: blake512 + * - BMW (Blue Midnight Wish) family: file sph_bmw.h + * - BMW-224: short name: bmw224 + * - BMW-256: short name: bmw256 + * - BMW-384: short name: bmw384 (64) + * - BMW-512: short name: bmw512 (64) + * - CubeHash family: file sph_cubehash.h (specified as + * CubeHash16/32 in the CubeHash specification) + * - CubeHash-224: short name: cubehash224 + * - CubeHash-256: short name: cubehash256 + * - CubeHash-384: short name: cubehash384 + * - CubeHash-512: short name: cubehash512 + * - ECHO family: file sph_echo.h + * - ECHO-224: short name: echo224 + * - ECHO-256: short name: echo256 + * - ECHO-384: short name: echo384 + * - ECHO-512: short name: echo512 + * - Fugue family: file sph_fugue.h + * - Fugue-224: short name: fugue224 + * - Fugue-256: short name: fugue256 + * - Fugue-384: short name: fugue384 + * - Fugue-512: short name: fugue512 + * - Groestl family: file sph_groestl.h + * - Groestl-224: short name: groestl224 + * - Groestl-256: short name: groestl256 + * - Groestl-384: short name: groestl384 + * - Groestl-512: short name: groestl512 + * - Hamsi family: file sph_hamsi.h + * - Hamsi-224: short name: hamsi224 + * - Hamsi-256: short name: hamsi256 + * - Hamsi-384: short name: hamsi384 + * - Hamsi-512: short name: hamsi512 + * - JH family: file sph_jh.h + * - JH-224: short name: jh224 + * - JH-256: short name: jh256 + * - JH-384: short name: jh384 + * - JH-512: short name: jh512 + * - Keccak family: file sph_keccak.h + * - Keccak-224: short name: keccak224 + * - Keccak-256: short name: keccak256 + * - Keccak-384: short name: keccak384 + * - Keccak-512: short name: keccak512 + * - Luffa family: file sph_luffa.h + * - Luffa-224: short name: luffa224 + * - Luffa-256: short name: luffa256 + * - Luffa-384: short name: luffa384 + * - Luffa-512: short name: luffa512 + * - Shabal family: file sph_shabal.h + * - Shabal-192: short name: shabal192 + * - Shabal-224: short name: shabal224 + * - Shabal-256: short name: shabal256 + * - Shabal-384: short name: shabal384 + * - Shabal-512: short name: shabal512 + * - SHAvite-3 family: file sph_shavite.h + * - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): + * short name: shabal224 + * - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): + * short name: shabal256 + * - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): + * short name: shabal384 + * - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): + * short name: shabal512 + * - SIMD family: file sph_simd.h + * - SIMD-224: short name: simd224 + * - SIMD-256: short name: simd256 + * - SIMD-384: short name: simd384 + * - SIMD-512: short name: simd512 + * - Skein family: file sph_skein.h + * - Skein-224 (nominally specified as Skein-512-224): short name: + * skein224 (64) + * - Skein-256 (nominally specified as Skein-512-256): short name: + * skein256 (64) + * - Skein-384 (nominally specified as Skein-512-384): short name: + * skein384 (64) + * - Skein-512 (nominally specified as Skein-512-512): short name: + * skein512 (64) + * + * For the second-round SHA-3 candidates, the functions are as specified + * for round 2, i.e. with the "tweaks" that some candidates added + * between round 1 and round 2. Also, some of the submitted packages for + * round 2 contained errors, in the specification, reference code, or + * both. sphlib implements the corrected versions. + */ + +/** @hideinitializer + * Unsigned integer type whose length is at least 32 bits; on most + * architectures, it will have a width of exactly 32 bits. Unsigned C + * types implement arithmetics modulo a power of 2; use the + * SPH_T32() macro to ensure that the value is truncated + * to exactly 32 bits. Unless otherwise specified, all macros and + * functions which accept sph_u32 values assume that these + * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures + * where sph_u32 is larger than that. + */ +typedef __arch_dependant__ sph_u32; + +/** @hideinitializer + * Signed integer type corresponding to sph_u32; it has + * width 32 bits or more. + */ +typedef __arch_dependant__ sph_s32; + +/** @hideinitializer + * Unsigned integer type whose length is at least 64 bits; on most + * architectures which feature such a type, it will have a width of + * exactly 64 bits. C99-compliant platform will have this type; it + * is also defined when the GNU compiler (gcc) is used, and on + * platforms where unsigned long is large enough. If this + * type is not available, then some hash functions which depends on + * a 64-bit type will not be available (most notably SHA-384, SHA-512, + * Tiger and WHIRLPOOL). + */ +typedef __arch_dependant__ sph_u64; + +/** @hideinitializer + * Signed integer type corresponding to sph_u64; it has + * width 64 bits or more. + */ +typedef __arch_dependant__ sph_s64; + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u32. Depending on + * how this type is defined, a suffix such as UL may + * be appended to the argument. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C32(x) + +/** + * Truncate a 32-bit value to exactly 32 bits. On most systems, this is + * a no-op, recognized as such by the compiler. + * + * @param x the value to truncate (of type sph_u32) + */ +#define SPH_T32(x) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTL32(x, n) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTR32(x, n) + +/** + * This macro is defined on systems for which a 64-bit type has been + * detected, and is used for sph_u64. + */ +#define SPH_64 + +/** + * This macro is defined on systems for the "native" integer size is + * 64 bits (64-bit values fit in one register). + */ +#define SPH_64_TRUE + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u64. Depending on + * how this type is defined, a suffix such as ULL may + * be appended to the argument. This macro is defined only if a + * 64-bit type was detected and used for sph_u64. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C64(x) + +/** + * Truncate a 64-bit value to exactly 64 bits. On most systems, this is + * a no-op, recognized as such by the compiler. This macro is defined only + * if a 64-bit type was detected and used for sph_u64. + * + * @param x the value to truncate (of type sph_u64) + */ +#define SPH_T64(x) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTL64(x, n) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTR64(x, n) + +/** + * This macro evaluates to inline or an equivalent construction, + * if available on the compilation platform, or to nothing otherwise. This + * is used to declare inline functions, for which the compiler should + * endeavour to include the code directly in the caller. Inline functions + * are typically defined in header files as replacement for macros. + */ +#define SPH_INLINE + +/** + * This macro is defined if the platform has been detected as using + * little-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_LITTLE_ENDIAN + +/** + * This macro is defined if the platform has been detected as using + * big-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_BIG_ENDIAN + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in little-endian + * convention. This is the case for little-endian platforms, and also + * for the big-endian platforms which have special little-endian access + * opcodes (e.g. Ultrasparc). + */ +#define SPH_LITTLE_FAST + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in big-endian + * convention. This is the case for little-endian platforms, and also + * for the little-endian platforms which have special big-endian access + * opcodes. + */ +#define SPH_BIG_FAST + +/** + * On some platforms, this macro is defined to an unsigned integer type + * into which pointer values may be cast. The resulting value can then + * be tested for being a multiple of 2, 4 or 8, indicating an aligned + * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. + */ +#define SPH_UPTR + +/** + * When defined, this macro indicates that unaligned memory accesses + * are possible with only a minor penalty, and thus should be prefered + * over strategies which first copy data to an aligned buffer. + */ +#define SPH_UNALIGNED + +/** + * Byte-swap a 32-bit word (i.e. 0x12345678 becomes + * 0x78563412). This is an inline function which resorts + * to inline assembly on some platforms, for better performance. + * + * @param x the 32-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u32 sph_bswap32(sph_u32 x); + +/** + * Byte-swap a 64-bit word. This is an inline function which resorts + * to inline assembly on some platforms, for better performance. This + * function is defined only if a suitable 64-bit type was found for + * sph_u64 + * + * @param x the 64-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u64 sph_bswap64(sph_u64 x); + +/** + * Decode a 16-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16le(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16le(void *dst, unsigned val); + +/** + * Decode a 16-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16be(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16be(void *dst, unsigned val); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32le() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32le() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le_aligned(void *dst, sph_u32 val); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32be() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32be() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be_aligned(void *dst, sph_u32 val); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64le() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64le() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le_aligned(void *dst, sph_u64 val); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64be() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64be() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be_aligned(void *dst, sph_u64 val); + +#endif + +/* ============== END documentation block for Doxygen ============= */ + +#ifndef DOXYGEN_IGNORE + +/* + * We want to define the types "sph_u32" and "sph_u64" which hold + * unsigned values of at least, respectively, 32 and 64 bits. These + * tests should select appropriate types for most platforms. The + * macro "SPH_64" is defined if the 64-bit is supported. + */ + +#undef SPH_64 +#undef SPH_64_TRUE + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +/* + * On C99 implementations, we can use to get an exact 64-bit + * type, if any, or otherwise use a wider type (which must exist, for + * C99 conformance). + */ + +#include + +#ifdef UINT32_MAX +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +#else +typedef uint_fast32_t sph_u32; +typedef int_fast32_t sph_s32; +#endif +#if !SPH_NO_64 +#ifdef UINT64_MAX +typedef uint64_t sph_u64; +typedef int64_t sph_s64; +#else +typedef uint_fast64_t sph_u64; +typedef int_fast64_t sph_s64; +#endif +#endif + +#define SPH_C32(x) ((sph_u32)(x)) +#if !SPH_NO_64 +#define SPH_C64(x) ((sph_u64)(x)) +#define SPH_64 1 +#endif + +#else + +/* + * On non-C99 systems, we use "unsigned int" if it is wide enough, + * "unsigned long" otherwise. This supports all "reasonable" architectures. + * We have to be cautious: pre-C99 preprocessors handle constants + * differently in '#if' expressions. Hence the shifts to test UINT_MAX. + */ + +#if ((UINT_MAX >> 11) >> 11) >= 0x3FF + +typedef unsigned int sph_u32; +typedef int sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## U)) + +#else + +typedef unsigned long sph_u32; +typedef long sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## UL)) + +#endif + +#if !SPH_NO_64 + +/* + * We want a 64-bit type. We use "unsigned long" if it is wide enough (as + * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), + * "unsigned long long" otherwise, if available. We use ULLONG_MAX to + * test whether "unsigned long long" is available; we also know that + * gcc features this type, even if the libc header do not know it. + */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +typedef unsigned long sph_u64; +typedef long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## UL)) + +#define SPH_64 1 + +#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ + +typedef unsigned long long sph_u64; +typedef long long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## ULL)) + +#define SPH_64 1 + +#else + +/* + * No 64-bit type... + */ + +#endif + +#endif + +#endif + +/* + * If the "unsigned long" type has length 64 bits or more, then this is + * a "true" 64-bit architectures. This is also true with Visual C on + * amd64, even though the "long" type is limited to 32 bits. + */ +#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) +#define SPH_64_TRUE 1 +#endif + +/* + * Implementation note: some processors have specific opcodes to perform + * a rotation. Recent versions of gcc recognize the expression above and + * use the relevant opcodes, when appropriate. + */ + +#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#ifdef _MSC_VER +#define SPH_ROTL32(x, n) _rotl(x, n) +#define SPH_ROTR32(x, n) _rotr(x, n) +#else +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) +#endif + +#if SPH_64 + +#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#ifdef _MSC_VER +#define SPH_ROTL64(x, n) _rotl64(x, n) +#define SPH_ROTR64(x, n) _rotr64(x, n) +#else +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) +#endif + +#endif + +#ifndef DOXYGEN_IGNORE +/* + * Define SPH_INLINE to be an "inline" qualifier, if available. We define + * some small macro-like functions which benefit greatly from being inlined. + */ +#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ +#define SPH_INLINE inline +#elif defined _MSC_VER +#define SPH_INLINE __inline +#else +#define SPH_INLINE +#endif +#endif + +/* + * We define some macros which qualify the architecture. These macros + * may be explicit set externally (e.g. as compiler parameters). The + * code below sets those macros if they are not already defined. + * + * Most macros are boolean, thus evaluate to either zero or non-zero. + * The SPH_UPTR macro is special, in that it evaluates to a C type, + * or is not defined. + * + * SPH_UPTR if defined: unsigned type to cast pointers into + * + * SPH_UNALIGNED non-zero if unaligned accesses are efficient + * SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian + * SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian + * SPH_LITTLE_FAST non-zero if little-endian decoding is fast + * SPH_BIG_FAST non-zero if big-endian decoding is fast + * + * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit + * values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN + * _must_ be non-zero in those situations. The 32-bit and 64-bit types + * _must_ also have an exact width. + * + * SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode + * SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode + * SPH_SPARCV9_GCC UltraSPARC-compatible with gcc + * SPH_I386_GCC x86-compatible (32-bit) with gcc + * SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C + * SPH_AMD64_GCC x86-compatible (64-bit) with gcc + * SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C + * SPH_PPC32_GCC PowerPC, 32-bit, with gcc + * SPH_PPC64_GCC PowerPC, 64-bit, with gcc + * + * TODO: enhance automatic detection, for more architectures and compilers. + * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with + * some very fast functions (e.g. MD4) when using unaligned input data. + * The CPU-specific-with-GCC macros are useful only for inline assembly, + * normally restrained to this header file. + */ + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#ifdef __GNUC__ +#define SPH_DETECT_I386_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_I386_MSVC 1 +#endif + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_AMD64_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_AMD64_MSVC 1 +#endif + +/* + * 64-bit Sparc architecture (implies v9). + */ +#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ + || defined __sparcv9 + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_SPARCV9_GCC_64 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * 32-bit Sparc. + */ +#elif (defined __sparc__ || defined __sparc) \ + && !(defined __sparcv9 || defined __arch64__) + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#if defined __GNUC__ && defined __sparc_v9__ +#define SPH_DETECT_SPARCV9_GCC_32 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, little-endian. + */ +#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, big-endian. + */ +#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ + +#define SPH_DETECT_BIG_ENDIAN 1 + +/* + * PowerPC. + */ +#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ + || defined _ARCH_PPC + +/* + * Note: we do not declare cross-endian access to be "fast": even if + * using inline assembly, implementation should still assume that + * keeping the decoded word in a temporary is faster than decoding + * it again. + */ +#if defined __GNUC__ +#if SPH_64_TRUE +#define SPH_DETECT_PPC64_GCC 1 +#else +#define SPH_DETECT_PPC32_GCC 1 +#endif +#endif + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif + +/* + * Itanium, 64-bit. + */ +#elif defined __ia64 || defined __ia64__ \ + || defined __itanium__ || defined _M_IA64 + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#else +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif +#if defined __LP64__ || defined _LP64 +#define SPH_DETECT_UPTR sph_u64 +#else +#define SPH_DETECT_UPTR sph_u32 +#endif + +#endif + +#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 +#define SPH_DETECT_SPARCV9_GCC 1 +#endif + +#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED +#define SPH_UNALIGNED SPH_DETECT_UNALIGNED +#endif +#if defined SPH_DETECT_UPTR && !defined SPH_UPTR +#define SPH_UPTR SPH_DETECT_UPTR +#endif +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif +#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST +#endif +#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST +#define SPH_BIG_FAST SPH_DETECT_BIG_FAST +#endif +#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 +#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 +#endif +#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 +#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 +#endif +#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC +#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC +#endif +#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC +#define SPH_I386_GCC SPH_DETECT_I386_GCC +#endif +#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC +#define SPH_I386_MSVC SPH_DETECT_I386_MSVC +#endif +#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC +#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC +#endif +#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC +#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC +#endif +#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC +#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC +#endif +#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC +#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC +#endif + +#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST 1 +#endif +#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST +#define SPH_BIG_FAST 1 +#endif + +#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) +#error SPH_UPTR defined, but endianness is not known. +#endif + +#if SPH_I386_GCC && !SPH_NO_ASM + +/* + * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + +#elif SPH_AMD64_GCC && !SPH_NO_ASM + +/* + * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * and 64-bit values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; +} + +#endif + +/* + * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough + * to generate proper opcodes for endianness swapping with the pure C + * implementation below. + * + +#elif SPH_I386_MSVC && !SPH_NO_ASM + +static __inline sph_u32 __declspec(naked) __fastcall +sph_bswap32(sph_u32 x) +{ + __asm { + bswap ecx + mov eax,ecx + ret + } +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + + * + * [end of disabled code] + */ + +#else + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +#if SPH_64 + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +#endif + +#endif + +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + +/* + * On UltraSPARC systems, native ordering is big-endian, but it is + * possible to perform little-endian read accesses by specifying the + * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use + * the opcode "lda [%reg]0x88,%dst", where %reg is the register which + * contains the source address and %dst is the destination register, + * or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register + * to get the address space name. The latter format is better since it + * combines an addition and the actual access in a single opcode; but + * it requires the setting (and subsequent resetting) of %asi, which is + * slow. Some operations (i.e. MD5 compression function) combine many + * successive little-endian read accesses, which may share the same + * %asi setting. The macros below contain the appropriate inline + * assembly. + */ + +#define SPH_SPARCV9_SET_ASI \ + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_RESET_ASI \ + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) + +#endif + +static SPH_INLINE void +sph_enc16be(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; +} + +static SPH_INLINE unsigned +sph_dec16be(const void *src) +{ + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); +} + +static SPH_INLINE void +sph_enc16le(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; +} + +static SPH_INLINE unsigned +sph_dec16le(const void *src) +{ + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32be(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32be_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } +#endif +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32 *)src; +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32le(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32le_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * On PowerPC, this turns out not to be worth the effort: the inline + * assembly makes GCC optimizer uncomfortable, which tends to nullify + * the decoding gains. + * + * For most hash functions, using this inline assembly trick changes + * hashing speed by less than 5% and often _reduces_ it. The biggest + * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is + * less then 10%. The speed gain on CubeHash is probably due to the + * chronic shortage of registers that CubeHash endures; for the other + * functions, the generic code appears to be efficient enough already. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return *(const sph_u32 *)src; +#endif + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u32 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +#if SPH_64 + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64be(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64be_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } +#endif +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64 *)src; +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64le(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64le_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u64 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +#endif + +#endif /* Doxygen excluded block */ + +#endif diff --git a/exlib/lyra2z-py/test.py b/exlib/lyra2z-py/test.py new file mode 100644 index 000000000000..3d27ebeb727e --- /dev/null +++ b/exlib/lyra2z-py/test.py @@ -0,0 +1,12 @@ +import lyra2z_hash +import weakref +import binascii +import StringIO + +from binascii import unhexlify, hexlify + +teststart = '700000005d385ba114d079971b29a9418fd0549e7d68a95c7f168621a314201000000000578586d149fd07b22f3a8a347c516de7052f034d2b76ff68e0d6ecff9b77a45489e3fd511732011df0731000'; +testbin = unhexlify(teststart) +hash_bin = lyra2z_hash.getPoWHash(testbin) + +print(hexlify(hash_bin)) diff --git a/gui/kivy/Makefile b/gui/kivy/Makefile index e616f9d1a1ef..34bab6eeb483 100644 --- a/gui/kivy/Makefile +++ b/gui/kivy/Makefile @@ -10,7 +10,7 @@ prepare: # running pre build setup @cp tools/buildozer.spec ../../buildozer.spec # copy electrum to main.py - @cp ../../electrum ../../main.py + @cp ../../electrum-xzc ../../main.py @-if [ ! -d "../../.buildozer" ];then \ cd ../..; buildozer android debug;\ cp -f gui/kivy/tools/blacklist.txt .buildozer/android/platform/python-for-android/src/blacklist.txt;\ diff --git a/gui/kivy/i18n.py b/gui/kivy/i18n.py index e0be39082c8a..e1c09df4ac1a 100644 --- a/gui/kivy/i18n.py +++ b/gui/kivy/i18n.py @@ -35,7 +35,7 @@ def bind(label): @staticmethod def switch_lang(lang): # get the right locales directory, and instanciate a gettext - from electrum.i18n import LOCALE_DIR + from electrum_xzc.i18n import LOCALE_DIR locales = gettext.translation('electrum', LOCALE_DIR, languages=[lang], fallback=True) _.lang = locales.gettext for label in _.observers: diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv index 853ddd94e792..212f073e99a8 100644 --- a/gui/kivy/main.kv +++ b/gui/kivy/main.kv @@ -1,7 +1,7 @@ #:import Clock kivy.clock.Clock #:import Window kivy.core.window.Window #:import Factory kivy.factory.Factory -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ ########################### diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py index 020388fadcd1..8c3ca3e3071c 100644 --- a/gui/kivy/main_window.py +++ b/gui/kivy/main_window.py @@ -7,15 +7,15 @@ from decimal import Decimal import threading -import electrum -from electrum.bitcoin import TYPE_ADDRESS -from electrum import WalletStorage, Wallet -from electrum_gui.kivy.i18n import _ -from electrum.paymentrequest import InvoiceStore -from electrum.util import profiler, InvalidPassword -from electrum.plugins import run_hook -from electrum.util import format_satoshis, format_satoshis_plain -from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED +import electrum_xzc as electrum +from electrum_xzc.bitcoin import TYPE_ADDRESS +from electrum_xzc import WalletStorage, Wallet +from electrum_xzc_gui.kivy.i18n import _ +from electrum_xzc.paymentrequest import InvoiceStore +from electrum_xzc.util import profiler, InvalidPassword +from electrum_xzc.plugins import run_hook +from electrum_xzc.util import format_satoshis, format_satoshis_plain +from electrum_xzc.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from kivy.app import App from kivy.core.window import Window @@ -30,10 +30,10 @@ from kivy.lang import Builder ## lazy imports for factory so that widgets can be used in kv -#Factory.register('InstallWizard', module='electrum_gui.kivy.uix.dialogs.installwizard') -#Factory.register('InfoBubble', module='electrum_gui.kivy.uix.dialogs') -#Factory.register('OutputList', module='electrum_gui.kivy.uix.dialogs') -#Factory.register('OutputItem', module='electrum_gui.kivy.uix.dialogs') +#Factory.register('InstallWizard', module='electrum_xzc_gui.kivy.uix.dialogs.installwizard') +#Factory.register('InfoBubble', module='electrum_xzc_gui.kivy.uix.dialogs') +#Factory.register('OutputList', module='electrum_xzc_gui.kivy.uix.dialogs') +#Factory.register('OutputItem', module='electrum_xzc_gui.kivy.uix.dialogs') from .uix.dialogs.installwizard import InstallWizard from .uix.dialogs import InfoBubble @@ -48,14 +48,14 @@ # register widget cache for keeping memory down timeout to forever to cache # the data -Cache.register('electrum_widgets', timeout=0) +Cache.register('electrum_xzc_widgets', timeout=0) from kivy.uix.screenmanager import Screen from kivy.uix.tabbedpanel import TabbedPanel from kivy.uix.label import Label from kivy.core.clipboard import Clipboard -Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens') +Factory.register('TabbedCarousel', module='electrum_xzc_gui.kivy.uix.screens') # Register fonts without this you won't be able to use bold/italic... # inside markup. @@ -67,7 +67,7 @@ 'gui/kivy/data/fonts/Roboto-Bold.ttf') -from electrum.util import base_units +from electrum_xzc.util import base_units class ElectrumWindow(App): @@ -95,7 +95,7 @@ def choose_server_dialog(self, popup): from .uix.dialogs.choice_dialog import ChoiceDialog protocol = 's' def cb2(host): - from electrum.bitcoin import NetworkConstants + from electrum_xzc.bitcoin import NetworkConstants pp = servers.get(host, NetworkConstants.DEFAULT_PORTS) port = pp.get(protocol, '') popup.ids.host.text = host @@ -132,7 +132,7 @@ def set_URI(self, uri): self.send_screen.set_URI(uri) def on_new_intent(self, intent): - if intent.getScheme() != 'bitcoin': + if intent.getScheme() != 'zcoin': return uri = intent.getDataString() self.set_URI(uri) @@ -154,7 +154,7 @@ def on_history(self, d): self._trigger_update_history() def _get_bu(self): - return self.electrum_config.get('base_unit', 'mBTC') + return self.electrum_config.get('base_unit', 'XZC') def _set_bu(self, value): assert value in base_units.keys() @@ -241,7 +241,7 @@ def __init__(self, **kwargs): App.__init__(self)#, **kwargs) - title = _('Electrum App') + title = _('Electrum-XZC App') self.electrum_config = config = kwargs.get('config', None) self.language = config.get('language', 'en') self.network = network = kwargs.get('network', None) @@ -295,17 +295,17 @@ def on_pr(self, pr): self.send_screen.do_clear() def on_qr(self, data): - from electrum.bitcoin import base_decode, is_address + from electrum_xzc.bitcoin import base_decode, is_address data = data.strip() if is_address(data): self.set_URI(data) return - if data.startswith('bitcoin:'): + if data.startswith('zcoin:'): self.set_URI(data) return # try to decode transaction - from electrum.transaction import Transaction - from electrum.util import bh2u + from electrum_xzc.transaction import Transaction + from electrum_xzc.util import bh2u try: text = bh2u(base_decode(data, None, base=43)) tx = Transaction(text) @@ -342,7 +342,7 @@ def show_request(self, addr): self.receive_screen.screen.address = addr def show_pr_details(self, req, status, is_invoice): - from electrum.util import format_time + from electrum_xzc.util import format_time requestor = req.get('requestor') exp = req.get('exp') memo = req.get('memo') @@ -364,7 +364,7 @@ def show_pr_details(self, req, status, is_invoice): popup.open() def show_addr_details(self, req, status): - from electrum.util import format_time + from electrum_xzc.util import format_time fund = req.get('fund') isaddr = 'y' popup = Builder.load_file('gui/kivy/uix/ui_screens/invoice.kv') @@ -563,13 +563,13 @@ def init_ui(self): #setup lazy imports for mainscreen Factory.register('AnimatedPopup', - module='electrum_gui.kivy.uix.dialogs') + module='electrum_xzc_gui.kivy.uix.dialogs') Factory.register('QRCodeWidget', - module='electrum_gui.kivy.uix.qrcodewidget') + module='electrum_xzc_gui.kivy.uix.qrcodewidget') # preload widgets. Remove this if you want to load the widgets on demand - #Cache.append('electrum_widgets', 'AnimatedPopup', Factory.AnimatedPopup()) - #Cache.append('electrum_widgets', 'QRCodeWidget', Factory.QRCodeWidget()) + #Cache.append('electrum_xzc_widgets', 'AnimatedPopup', Factory.AnimatedPopup()) + #Cache.append('electrum_xzc_widgets', 'QRCodeWidget', Factory.QRCodeWidget()) # load and focus the ui self.root.manager = self.root.ids['manager'] @@ -581,7 +581,7 @@ def init_ui(self): self.receive_screen = None self.requests_screen = None self.address_screen = None - self.icon = "icons/electrum.png" + self.icon = "icons/electrum-xzc.png" self.tabs = self.root.ids['tabs'] def update_interfaces(self, dt): @@ -631,7 +631,7 @@ def update_status(self, *dt): if not self.wallet.up_to_date or server_height == 0: status = _("Synchronizing...") elif server_lag > 1: - status = _("Server lagging ({} blocks)").format(server_lag) + status = _("Server lagging (%d blocks)"%server_lag) else: c, u, x = self.wallet.get_balance() text = self.format_amount(c+x+u) @@ -670,8 +670,8 @@ def notify(self, message): from plyer import notification icon = (os.path.dirname(os.path.realpath(__file__)) + '/../../' + self.icon) - notification.notify('Electrum', message, - app_icon=icon, app_name='Electrum') + notification.notify('Electrum-XZC', message, + app_icon=icon, app_name='Electrum-XZC') except ImportError: Logger.Error('Notification: needs plyer; `sudo pip install plyer`') @@ -846,7 +846,7 @@ def delete_wallet(self): def _delete_wallet(self, b): if b: basename = os.path.basename(self.wallet.storage.path) - self.protected(_("Enter your PIN code to confirm deletion of {}").format(basename), self.__delete_wallet, ()) + self.protected(_("Enter your PIN code to confirm deletion of %s") % basename, self.__delete_wallet, ()) def __delete_wallet(self, pw): wallet_path = self.get_wallet_path() diff --git a/gui/kivy/nfc_scanner/__init__.py b/gui/kivy/nfc_scanner/__init__.py index fd3d263a3fd4..e2b5deeb6a13 100644 --- a/gui/kivy/nfc_scanner/__init__.py +++ b/gui/kivy/nfc_scanner/__init__.py @@ -41,4 +41,4 @@ def nfc_disable_exchange(self): NFCScanner = core_select_lib('nfc_manager', ( # keep the dummy implementtation as the last one to make it the fallback provider.NFCScanner = core_select_lib('nfc_scanner', ( ('android', 'scanner_android', 'ScannerAndroid'), - ('dummy', 'scanner_dummy', 'ScannerDummy')), True, 'electrum_gui.kivy') + ('dummy', 'scanner_dummy', 'ScannerDummy')), True, 'electrum_xzc_gui.kivy') diff --git a/gui/kivy/nfc_scanner/scanner_android.py b/gui/kivy/nfc_scanner/scanner_android.py index b8f860293238..db89dcd0930d 100644 --- a/gui/kivy/nfc_scanner/scanner_android.py +++ b/gui/kivy/nfc_scanner/scanner_android.py @@ -10,7 +10,7 @@ raise ImportError import threading -from electrum_gui.kivy.nfc_scanner import NFCBase +from electrum_xzc_gui.kivy.nfc_scanner import NFCBase from jnius import autoclass, cast from android.runnable import run_on_ui_thread from android import activity @@ -165,20 +165,20 @@ def nfc_enable(self): def create_AAR(self): '''Create the record responsible for linking our application to the tag. ''' - return NdefRecord.createApplicationRecord(JString("org.electrum.kivy")) + return NdefRecord.createApplicationRecord(JString("org.electrum_xzc.kivy")) def create_TNF_EXTERNAL(self, data): '''Create our actual payload record. ''' if BUILDVERSION >= 14: - domain = "org.electrum" + domain = "org.electrum_xzc" stype = "externalType" extRecord = NdefRecord.createExternal(domain, stype, data) else: # Creating the NdefRecord manually: extRecord = NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, - "org.electrum:externalType", + "org.electrum_xzc:externalType", '', data) return extRecord @@ -213,7 +213,7 @@ def _nfc_enable_ndef_exchange(self, data): # Create record ndef_record = NdefRecord( NdefRecord.TNF_MIME_MEDIA, - 'org.electrum.kivy', '', data) + 'org.electrum_xzc.kivy', '', data) # Create message ndef_message = NdefMessage([ndef_record]) diff --git a/gui/kivy/nfc_scanner/scanner_dummy.py b/gui/kivy/nfc_scanner/scanner_dummy.py index 1ad2c17a3b24..e1cfadb29aed 100644 --- a/gui/kivy/nfc_scanner/scanner_dummy.py +++ b/gui/kivy/nfc_scanner/scanner_dummy.py @@ -1,6 +1,6 @@ ''' Dummy NFC Provider to be used on desktops in case no other provider is found ''' -from electrum_gui.kivy.nfc_scanner import NFCBase +from electrum_xzc_gui.kivy.nfc_scanner import NFCBase from kivy.clock import Clock from kivy.logger import Logger diff --git a/gui/kivy/tools/bitcoin_intent.xml b/gui/kivy/tools/bitcoin_intent.xml index f433f72c1ef8..b0e66c27628e 100644 --- a/gui/kivy/tools/bitcoin_intent.xml +++ b/gui/kivy/tools/bitcoin_intent.xml @@ -3,5 +3,5 @@ - + diff --git a/gui/kivy/tools/buildozer.spec b/gui/kivy/tools/buildozer.spec index b3679889db6c..957a804fe0f2 100644 --- a/gui/kivy/tools/buildozer.spec +++ b/gui/kivy/tools/buildozer.spec @@ -1,13 +1,13 @@ [app] # (str) Title of your application -title = Electrum +title = Electrum-XZC # (str) Package name -package.name = Electrum +package.name = Electrum_XZC # (str) Package domain (needed for android/ios packaging) -package.domain = org.electrum +package.domain = org.electrum_xzc # (str) Source code where the main.py live source.dir = . diff --git a/gui/kivy/uix/context_menu.py b/gui/kivy/uix/context_menu.py index dee0212af45d..fc4b3f3caac8 100644 --- a/gui/kivy/uix/context_menu.py +++ b/gui/kivy/uix/context_menu.py @@ -8,7 +8,7 @@ from kivy.factory import Factory from kivy.clock import Clock -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ Builder.load_string(''' diff --git a/gui/kivy/uix/dialogs/__init__.py b/gui/kivy/uix/dialogs/__init__.py index c5269f380f1c..eb8b3f97f54e 100644 --- a/gui/kivy/uix/dialogs/__init__.py +++ b/gui/kivy/uix/dialogs/__init__.py @@ -4,7 +4,7 @@ from kivy.properties import NumericProperty, StringProperty, BooleanProperty from kivy.core.window import Window -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ diff --git a/gui/kivy/uix/dialogs/bump_fee_dialog.py b/gui/kivy/uix/dialogs/bump_fee_dialog.py index 1a6dc6228ef9..9f9a7a5e3f78 100644 --- a/gui/kivy/uix/dialogs/bump_fee_dialog.py +++ b/gui/kivy/uix/dialogs/bump_fee_dialog.py @@ -3,8 +3,8 @@ from kivy.properties import ObjectProperty from kivy.lang import Builder -from electrum.util import fee_levels -from electrum_gui.kivy.i18n import _ +from electrum_xzc.util import fee_levels +from electrum_xzc_gui.kivy.i18n import _ Builder.load_string(''' @@ -73,7 +73,7 @@ def __init__(self, app, fee, size, callback): self.callback = callback self.config = app.electrum_config self.fee_step = self.config.max_fee_rate() / 10 - self.dynfees = self.config.is_dynfee() and self.app.network + self.dynfees = self.config.get('dynamic_fees', True) and self.app.network self.ids.old_fee.value = self.app.format_amount_and_units(self.init_fee) self.update_slider() self.update_text() diff --git a/gui/kivy/uix/dialogs/fee_dialog.py b/gui/kivy/uix/dialogs/fee_dialog.py index 1c61c6a21f83..97f3b54686b3 100644 --- a/gui/kivy/uix/dialogs/fee_dialog.py +++ b/gui/kivy/uix/dialogs/fee_dialog.py @@ -3,8 +3,8 @@ from kivy.properties import ObjectProperty from kivy.lang import Builder -from electrum.util import fee_levels -from electrum_gui.kivy.i18n import _ +from electrum_xzc.util import fee_levels +from electrum_xzc_gui.kivy.i18n import _ Builder.load_string(''' @@ -18,17 +18,7 @@ orientation: 'horizontal' size_hint: 1, 0.5 Label: - text: (_('Target') if dynfees.active else _('Fixed rate')) + ':' - Label: - id: fee_target - text: '' - BoxLayout: - orientation: 'horizontal' - size_hint: 1, 0.5 - Label: - text: (_('Current rate') if dynfees.active else _('Estimate')) + ':' - Label: - id: fee_estimate + id: fee_per_kb text: '' Slider: id: slider @@ -42,15 +32,7 @@ text: _('Dynamic Fees') CheckBox: id: dynfees - on_active: root.on_dynfees(self.active) - BoxLayout: - orientation: 'horizontal' - size_hint: 1, 0.5 - Label: - text: _('Use mempool') - CheckBox: - id: mempool - on_active: root.on_mempool(self.active) + on_active: root.on_checkbox(self.active) Widget: size_hint: 1, 1 BoxLayout: @@ -78,44 +60,45 @@ def __init__(self, app, config, callback): self.config = config self.fee_rate = self.config.fee_per_kb() self.callback = callback - self.mempool = self.config.use_mempool_fees() - self.dynfees = self.config.is_dynfee() - self.ids.mempool.active = self.mempool + self.dynfees = self.config.get('dynamic_fees', True) self.ids.dynfees.active = self.dynfees self.update_slider() self.update_text() def update_text(self): value = int(self.ids.slider.value) - target, estimate = self.get_fee_text(value) - self.ids.fee_target.text = target - self.ids.fee_estimate.text = estimate + self.ids.fee_per_kb.text = self.get_fee_text(value) def update_slider(self): slider = self.ids.slider - maxp, pos, fee_rate = self.config.get_fee_slider(self.dynfees, self.mempool) - slider.range = (0, maxp) - slider.step = 1 - slider.value = pos + if self.dynfees: + slider.range = (0, 4) + slider.step = 1 + slider.value = self.config.get('fee_level', 2) + else: + slider.range = (0, 9) + slider.step = 1 + slider.value = self.config.static_fee_index(self.fee_rate) - def get_fee_text(self, pos): - dyn = self.dynfees - mempool = self.mempool - if dyn: - fee_rate = self.config.depth_to_fee(pos) if mempool else self.config.eta_to_fee(pos) + def get_fee_text(self, value): + if self.ids.dynfees.active: + tooltip = fee_levels[value] + if self.config.has_fee_estimates(): + dynfee = self.config.dynfee(value) + tooltip += '\n' + (self.app.format_amount_and_units(dynfee)) + '/kB' else: - fee_rate = self.config.static_fee(pos) - return self.config.get_fee_text(pos, dyn, mempool, fee_rate) + fee_rate = self.config.static_fee(value) + tooltip = self.app.format_amount_and_units(fee_rate) + '/kB' + if self.config.has_fee_estimates(): + i = self.config.reverse_dynfee(fee_rate) + tooltip += '\n' + (_('low fee') if i < 0 else 'Within %d blocks'%i) + return tooltip def on_ok(self): value = int(self.ids.slider.value) self.config.set_key('dynamic_fees', self.dynfees, False) - self.config.set_key('mempool_fees', self.mempool, False) if self.dynfees: - if self.mempool: - self.config.set_key('depth_level', value, True) - else: - self.config.set_key('fee_level', value, True) + self.config.set_key('fee_level', value, True) else: self.config.set_key('fee_per_kb', self.config.static_fee(value), True) self.callback() @@ -123,12 +106,7 @@ def on_ok(self): def on_slider(self, value): self.update_text() - def on_dynfees(self, b): + def on_checkbox(self, b): self.dynfees = b self.update_slider() self.update_text() - - def on_mempool(self, b): - self.mempool = b - self.update_slider() - self.update_text() diff --git a/gui/kivy/uix/dialogs/fx_dialog.py b/gui/kivy/uix/dialogs/fx_dialog.py index 5184679206c1..62af43f5e45e 100644 --- a/gui/kivy/uix/dialogs/fx_dialog.py +++ b/gui/kivy/uix/dialogs/fx_dialog.py @@ -66,7 +66,7 @@ from kivy.uix.widget import Widget from kivy.clock import Clock -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ from functools import partial class FxDialog(Factory.Popup): diff --git a/gui/kivy/uix/dialogs/installwizard.py b/gui/kivy/uix/dialogs/installwizard.py index 651810907cdc..981ceefcc562 100644 --- a/gui/kivy/uix/dialogs/installwizard.py +++ b/gui/kivy/uix/dialogs/installwizard.py @@ -14,7 +14,7 @@ from kivy.clock import Clock from kivy.utils import platform -from electrum.base_wizard import BaseWizard +from electrum_xzc.base_wizard import BaseWizard from . import EventsDialog @@ -28,7 +28,7 @@ Builder.load_string(''' #:import Window kivy.core.window.Window -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ @@ -135,7 +135,7 @@ height: self.minimum_height Label: color: root.text_color - text: _('From {} cosigners').format(n.value) + text: _('From %d cosigners')%n.value Slider: id: n range: 2, 5 @@ -143,7 +143,7 @@ value: 2 Label: color: root.text_color - text: _('Require {} signatures').format(m.value) + text: _('Require %d signatures')%m.value Slider: id: m range: 1, n.value @@ -559,8 +559,8 @@ class RestoreSeedDialog(WizardDialog): def __init__(self, wizard, **kwargs): super(RestoreSeedDialog, self).__init__(wizard, **kwargs) self._test = kwargs['test'] - from electrum.mnemonic import Mnemonic - from electrum.old_mnemonic import words as old_wordlist + from electrum_xzc.mnemonic import Mnemonic + from electrum_xzc.old_mnemonic import words as old_wordlist self.words = set(Mnemonic('en').wordlist).union(set(old_wordlist)) self.ids.text_input_seed.text = test_seed if is_test else '' self.message = _('Please type your seed phrase using the virtual keyboard.') @@ -807,7 +807,7 @@ def password_dialog(self, message, callback): popup.init(message, callback) popup.open() - def request_password(self, run_next, force_disable_encrypt_cb=False): + def request_password(self, run_next): def callback(pin): if pin: self.run('confirm_password', pin, run_next) diff --git a/gui/kivy/uix/dialogs/nfc_transaction.py b/gui/kivy/uix/dialogs/nfc_transaction.py index cb10315e9054..d2003ab19d0f 100644 --- a/gui/kivy/uix/dialogs/nfc_transaction.py +++ b/gui/kivy/uix/dialogs/nfc_transaction.py @@ -8,7 +8,7 @@ def __init__(self, **kwargs): # Delayed Init global NFCSCanner if NFCSCanner is None: - from electrum_gui.kivy.nfc_scanner import NFCScanner + from electrum_xzc_gui.kivy.nfc_scanner import NFCScanner self.scanner = NFCSCanner super(NFCTransactionDialog, self).__init__(**kwargs) @@ -29,4 +29,4 @@ def _start(*l): anim.bind(on_complete=_cmp) _start() return - Animation.cancel_all(sctr) \ No newline at end of file + Animation.cancel_all(sctr) diff --git a/gui/kivy/uix/dialogs/qr_scanner.py b/gui/kivy/uix/dialogs/qr_scanner.py index eeb6061e2ee9..c7aa73ad800a 100644 --- a/gui/kivy/uix/dialogs/qr_scanner.py +++ b/gui/kivy/uix/dialogs/qr_scanner.py @@ -2,7 +2,7 @@ from kivy.factory import Factory from kivy.lang import Builder -Factory.register('QRScanner', module='electrum_gui.kivy.qr_scanner') +Factory.register('QRScanner', module='electrum_xzc_gui.kivy.qr_scanner') class QrScannerDialog(Factory.AnimatedPopup): diff --git a/gui/kivy/uix/dialogs/question.py b/gui/kivy/uix/dialogs/question.py index 3b5b36be643b..dbbef01e50aa 100644 --- a/gui/kivy/uix/dialogs/question.py +++ b/gui/kivy/uix/dialogs/question.py @@ -6,7 +6,7 @@ from kivy.uix.label import Label from kivy.uix.widget import Widget -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ Builder.load_string(''' diff --git a/gui/kivy/uix/dialogs/settings.py b/gui/kivy/uix/dialogs/settings.py index e73f33650466..624e591f0f0e 100644 --- a/gui/kivy/uix/dialogs/settings.py +++ b/gui/kivy/uix/dialogs/settings.py @@ -3,18 +3,18 @@ from kivy.properties import ObjectProperty from kivy.lang import Builder -from electrum.util import base_units -from electrum.i18n import languages -from electrum_gui.kivy.i18n import _ -from electrum.plugins import run_hook -from electrum import coinchooser -from electrum.util import fee_levels +from electrum_xzc.util import base_units +from electrum_xzc.i18n import languages +from electrum_xzc_gui.kivy.i18n import _ +from electrum_xzc.plugins import run_hook +from electrum_xzc import coinchooser +from electrum_xzc.util import fee_levels from .choice_dialog import ChoiceDialog Builder.load_string(''' #:import partial functools.partial -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ id: settings @@ -46,13 +46,13 @@ SettingsItem: bu: app.base_unit title: _('Denomination') + ': ' + self.bu - description: _("Base unit for Bitcoin amounts.") + description: _("Base unit for Zcoin amounts.") action: partial(root.unit_dialog, self) CardSeparator SettingsItem: status: root.fee_status() title: _('Fees') + ': ' + self.status - description: _("Fees paid to the Bitcoin miners.") + description: _("Fees paid to the Zcoin miners.") action: partial(root.fee_dialog, self) CardSeparator SettingsItem: @@ -204,7 +204,10 @@ def callback(status): d.open() def fee_status(self): - return self.config.get_fee_status() + if self.config.get('dynamic_fees', True): + return fee_levels[self.config.get('fee_level', 2)] + else: + return self.app.format_amount_and_units(self.config.fee_per_kb()) + '/kB' def fee_dialog(self, label, dt): if self._fee_dialog is None: diff --git a/gui/kivy/uix/dialogs/tx_dialog.py b/gui/kivy/uix/dialogs/tx_dialog.py index 5339b0d39c01..18d8c31e96b8 100644 --- a/gui/kivy/uix/dialogs/tx_dialog.py +++ b/gui/kivy/uix/dialogs/tx_dialog.py @@ -5,9 +5,9 @@ from kivy.clock import Clock from kivy.uix.label import Label -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ from datetime import datetime -from electrum.util import InvalidPassword +from electrum_xzc.util import InvalidPassword Builder.load_string(''' @@ -112,7 +112,7 @@ def update(self): if timestamp: self.date_str = datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] elif exp_n: - self.date_str = _('Within {} blocks').format(exp_n) if exp_n > 0 else _('unknown (low fee)') + self.date_str = _('Within %d blocks') % exp_n if exp_n > 0 else _('unknown (low fee)') else: self.date_str = '' @@ -171,7 +171,7 @@ def do_broadcast(self): self.app.broadcast(self.tx) def show_qr(self): - from electrum.bitcoin import base_encode, bfh + from electrum_xzc.bitcoin import base_encode, bfh text = bfh(str(self.tx)) text = base_encode(text, base=43) self.app.qr_dialog(_("Raw Transaction"), text) diff --git a/gui/kivy/uix/dialogs/wallets.py b/gui/kivy/uix/dialogs/wallets.py index d7b0469bf551..6e4dfec78325 100644 --- a/gui/kivy/uix/dialogs/wallets.py +++ b/gui/kivy/uix/dialogs/wallets.py @@ -5,7 +5,7 @@ from kivy.properties import ObjectProperty from kivy.lang import Builder -from electrum.util import base_units +from electrum_xzc.util import base_units from ...i18n import _ from .label_dialog import LabelDialog diff --git a/gui/kivy/uix/menus.py b/gui/kivy/uix/menus.py index 6b6efa9a739e..f8c98ac748b7 100644 --- a/gui/kivy/uix/menus.py +++ b/gui/kivy/uix/menus.py @@ -7,7 +7,7 @@ from kivy.properties import ListProperty from kivy.uix.widget import Widget -from electrum_gui.i18n import _ +from electrum_xzc_gui.i18n import _ class ContextMenuItem(Widget): '''abstract class diff --git a/gui/kivy/uix/screens.py b/gui/kivy/uix/screens.py index 0133f789e027..0c71e7ff5f90 100644 --- a/gui/kivy/uix/screens.py +++ b/gui/kivy/uix/screens.py @@ -17,15 +17,15 @@ from kivy.factory import Factory from kivy.utils import platform -from electrum.util import profiler, parse_URI, format_time, InvalidPassword, NotEnoughFunds -from electrum import bitcoin -from electrum.util import timestamp_to_datetime -from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED +from electrum_xzc.util import profiler, parse_URI, format_time, InvalidPassword, NotEnoughFunds +from electrum_xzc import bitcoin +from electrum_xzc.util import timestamp_to_datetime +from electrum_xzc.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from .context_menu import ContextMenu -from electrum_gui.kivy.i18n import _ +from electrum_xzc_gui.kivy.i18n import _ class EmptyLabel(Factory.Label): pass @@ -89,6 +89,7 @@ def show_menu(self, obj): # note: this list needs to be kept in sync with another in qt TX_ICONS = [ + "close", "close", "close", "unconfirmed", @@ -177,11 +178,11 @@ class SendScreen(CScreen): payment_request = None def set_URI(self, text): - import electrum + import electrum_xzc as electrum try: uri = electrum.util.parse_URI(text, self.app.on_pr) except: - self.app.show_info(_("Not a Bitcoin URI")) + self.app.show_info(_("Not a Zcoin URI")) return amount = uri.get('amount') self.screen.address = uri.get('address', '') @@ -219,7 +220,7 @@ def do_save(self): # it sould be already saved return # save address as invoice - from electrum.paymentrequest import make_unsigned_request, PaymentRequest + from electrum_xzc.paymentrequest import make_unsigned_request, PaymentRequest req = {'address':self.screen.address, 'memo':self.screen.message} amount = self.app.get_amount(self.screen.amount) if self.screen.amount else 0 req['amount'] = amount @@ -251,10 +252,10 @@ def do_send(self): else: address = str(self.screen.address) if not address: - self.app.show_error(_('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request')) + self.app.show_error(_('Recipient not specified.') + ' ' + _('Please scan a Zcoin address or a payment request')) return if not bitcoin.is_address(address): - self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + address) + self.app.show_error(_('Invalid Zcoin Address') + ':\n' + address) return try: amount = self.app.get_amount(self.screen.amount) @@ -291,7 +292,7 @@ def _do_send(self, amount, message, outputs, rbf): _("Amount to be sent") + ": " + self.app.format_amount_and_units(amount), _("Mining fee") + ": " + self.app.format_amount_and_units(fee), ] - if fee >= config.get('confirm_fee', 100000): + if fee >= config.get('confirm_fee', 1000000): msg.append(_('Warning')+ ': ' + _("The fee for this transaction seems unusually high.")) msg.append(_("Enter your PIN code to proceed")) self.app.protected('\n'.join(msg), self.send_tx, (tx, message)) @@ -355,7 +356,7 @@ def on_address(self, addr): Clock.schedule_once(lambda dt: self.update_qr()) def get_URI(self): - from electrum.util import create_URI + from electrum_xzc.util import create_URI amount = self.screen.amount if amount: a, u = self.screen.amount.split() @@ -371,7 +372,7 @@ def update_qr(self): def do_share(self): uri = self.get_URI() - self.app.do_share(uri, _("Share Bitcoin Request")) + self.app.do_share(uri, _("Share Zcoin Request")) def do_copy(self): uri = self.get_URI() @@ -522,12 +523,7 @@ def get_card(self, addr, balance, is_used, label): def update(self): self.menu_actions = [('Receive', self.do_show), ('Details', self.do_view)] wallet = self.app.wallet - if self.screen.show_change == 0: - _list = wallet.get_receiving_addresses() - elif self.screen.show_change == 1: - _list = wallet.get_change_addresses() - else: - _list = wallet.get_addresses() + _list = wallet.get_change_addresses() if self.screen.show_change else wallet.get_receiving_addresses() search = self.screen.message container = self.screen.ids.search_container container.clear_widgets() diff --git a/gui/kivy/uix/ui_screens/about.kv b/gui/kivy/uix/ui_screens/about.kv index e542b557eb0d..c70ca0936f84 100644 --- a/gui/kivy/uix/ui_screens/about.kv +++ b/gui/kivy/uix/ui_screens/about.kv @@ -1,7 +1,7 @@ -#:import VERSION electrum.version.ELECTRUM_VERSION +#:import VERSION electrum_xzc.version.ELECTRUM_VERSION Popup: - title: _("About Electrum") + title: _("About Electrum-XZC") BoxLayout: orientation: 'vertical' spacing: '10dp' @@ -26,10 +26,10 @@ Popup: size_hint_x: 0.4 TopLabel: markup: True - text: '[color=6666ff][ref=x]https://electrum.org[/ref][/color]' + text: '[color=6666ff][ref=x]https://electrum-xzc.org[/ref][/color]' on_ref_press: import webbrowser - webbrowser.open("https://electrum.org") + webbrowser.open("https://electrum-xzc.org") size_hint_x: 0.6 TopLabel: text: _('Developers') diff --git a/gui/kivy/uix/ui_screens/address.kv b/gui/kivy/uix/ui_screens/address.kv index d0247a3429e4..c0178ec4922b 100644 --- a/gui/kivy/uix/ui_screens/address.kv +++ b/gui/kivy/uix/ui_screens/address.kv @@ -1,4 +1,4 @@ -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ #:import Decimal decimal.Decimal #:set btc_symbol chr(171) #:set mbtc_symbol chr(187) @@ -50,7 +50,7 @@ AddressScreen: name: 'address' message: '' pr_status: 'Pending' - show_change: 0 + show_change: False show_used: 0 on_message: self.parent.update() @@ -70,9 +70,9 @@ AddressScreen: spacing: '5dp' AddressButton: id: search - text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change] + text: _('Change') if root.show_change else _('Receiving') on_release: - root.show_change = (root.show_change + 1) % 3 + root.show_change = not root.show_change Clock.schedule_once(lambda dt: app.address_screen.update()) AddressFilter: opacity: 1 diff --git a/gui/kivy/uix/ui_screens/history.kv b/gui/kivy/uix/ui_screens/history.kv index ad06c5eafb52..bec1857eb8fd 100644 --- a/gui/kivy/uix/ui_screens/history.kv +++ b/gui/kivy/uix/ui_screens/history.kv @@ -1,4 +1,4 @@ -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ #:import Factory kivy.factory.Factory #:set font_light 'gui/kivy/data/fonts/Roboto-Condensed.ttf' #:set btc_symbol chr(171) diff --git a/gui/kivy/uix/ui_screens/network.kv b/gui/kivy/uix/ui_screens/network.kv index f499618a8d51..71e18ab4950a 100644 --- a/gui/kivy/uix/ui_screens/network.kv +++ b/gui/kivy/uix/ui_screens/network.kv @@ -11,7 +11,7 @@ Popup: height: self.minimum_height padding: '10dp' SettingsItem: - value: _("{} connections.").format(app.num_nodes) if app.num_nodes else _("Not connected") + value: _("%d connections.")% app.num_nodes if app.num_nodes else _("Not connected") title: _("Status") + ': ' + self.value description: _("Connections with Electrum servers") action: lambda x: None @@ -46,7 +46,7 @@ Popup: CardSeparator SettingsItem: - title: _('Fork detected at block {}').format(app.blockchain_checkpoint) if app.num_chains>1 else _('No fork detected') + title: _('Fork detected at block %d')%app.blockchain_checkpoint if app.num_chains>1 else _('No fork detected') fork_description: (_('You are following branch') if app.auto_connect else _("Your server is on branch")) + ' ' + app.blockchain_name description: self.fork_description if app.num_chains>1 else _('Connected nodes are on the same chain') action: app.choose_blockchain_dialog diff --git a/gui/kivy/uix/ui_screens/receive.kv b/gui/kivy/uix/ui_screens/receive.kv index c58b77ec72ba..c19fb600adf8 100644 --- a/gui/kivy/uix/ui_screens/receive.kv +++ b/gui/kivy/uix/ui_screens/receive.kv @@ -1,4 +1,4 @@ -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ #:import Decimal decimal.Decimal #:set btc_symbol chr(171) #:set mbtc_symbol chr(187) @@ -68,7 +68,7 @@ ReceiveScreen: pos_hint: {'center_y': .5} BlueButton: id: address_label - text: s.address if s.address else _('Bitcoin Address') + text: s.address if s.address else _('Zcoin Address') shorten: True disabled: True CardSeparator: diff --git a/gui/kivy/uix/ui_screens/send.kv b/gui/kivy/uix/ui_screens/send.kv index 8aa70c0709cb..f2a45517e031 100644 --- a/gui/kivy/uix/ui_screens/send.kv +++ b/gui/kivy/uix/ui_screens/send.kv @@ -1,4 +1,4 @@ -#:import _ electrum_gui.kivy.i18n._ +#:import _ electrum_xzc_gui.kivy.i18n._ #:import Decimal decimal.Decimal #:set btc_symbol chr(171) #:set mbtc_symbol chr(187) diff --git a/gui/kivy/uix/ui_screens/status.kv b/gui/kivy/uix/ui_screens/status.kv index aeb6309c81c0..f9e9801983d2 100644 --- a/gui/kivy/uix/ui_screens/status.kv +++ b/gui/kivy/uix/ui_screens/status.kv @@ -1,5 +1,5 @@ Popup: - title: "Electrum" + title: "Electrum-XZC" confirmed: 0 unconfirmed: 0 unmatured: 0 diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py index 0879208f94ff..bb154a4aea81 100644 --- a/gui/qt/__init__.py +++ b/gui/qt/__init__.py @@ -25,7 +25,6 @@ import signal import sys -import traceback try: @@ -38,14 +37,14 @@ from PyQt5.QtCore import * import PyQt5.QtCore as QtCore -from electrum.i18n import _, set_language -from electrum.plugins import run_hook -from electrum import WalletStorage -# from electrum.synchronizer import Synchronizer -# from electrum.verifier import SPV -# from electrum.util import DebugMem -from electrum.util import UserCancelled, print_error -# from electrum.wallet import Abstract_Wallet +from electrum_xzc.i18n import _, set_language +from electrum_xzc.plugins import run_hook +from electrum_xzc import WalletStorage +# from electrum_xzc.synchronizer import Synchronizer +# from electrum_xzc.verifier import SPV +# from electrum_xzc.util import DebugMem +from electrum_xzc.util import UserCancelled, print_error +# from electrum_xzc.wallet import Abstract_Wallet from .installwizard import InstallWizard, GoBack @@ -95,8 +94,6 @@ def __init__(self, config, daemon, plugins): QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"): QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts) - if hasattr(QGuiApplication, 'setDesktopFileName'): - QGuiApplication.setDesktopFileName('electrum.desktop') self.config = config self.daemon = daemon self.plugins = plugins @@ -110,7 +107,7 @@ def __init__(self, config, daemon, plugins): # init tray self.dark_icon = self.config.get("dark_icon", False) self.tray = QSystemTrayIcon(self.tray_icon(), None) - self.tray.setToolTip('Electrum') + self.tray.setToolTip('Electrum-XZC') self.tray.activated.connect(self.tray_activated) self.build_tray_menu() self.tray.show() @@ -132,7 +129,7 @@ def build_tray_menu(self): submenu.addAction(_("Close"), window.close) m.addAction(_("Dark/Light"), self.toggle_tray_icon) m.addSeparator() - m.addAction(_("Exit Electrum"), self.close) + m.addAction(_("Exit Electrum-XZC"), self.close) def tray_icon(self): if self.dark_icon: @@ -193,10 +190,8 @@ def start_new_window(self, path, uri): else: try: wallet = self.daemon.load_wallet(path, None) - except BaseException as e: - traceback.print_exc(file=sys.stdout) - d = QMessageBox(QMessageBox.Warning, _('Error'), - _('Cannot load wallet:') + '\n' + str(e)) + except BaseException as e: + d = QMessageBox(QMessageBox.Warning, _('Error'), 'Cannot load wallet:\n' + str(e)) d.exec_() return if not wallet: @@ -213,14 +208,7 @@ def start_new_window(self, path, uri): return wallet.start_threads(self.daemon.network) self.daemon.add_wallet(wallet) - try: - w = self.create_window_for_wallet(wallet) - except BaseException as e: - traceback.print_exc(file=sys.stdout) - d = QMessageBox(QMessageBox.Warning, _('Error'), - _('Cannot create window for wallet:') + '\n' + str(e)) - d.exec_() - return + w = self.create_window_for_wallet(wallet) if uri: w.pay_to_URI(uri) w.bring_to_top() @@ -253,7 +241,8 @@ def main(self): return except GoBack: return - except BaseException as e: + except: + import traceback traceback.print_exc(file=sys.stdout) return self.timer.start() diff --git a/gui/qt/address_dialog.py b/gui/qt/address_dialog.py index 9afd50adcbe2..2d9c67b804f2 100644 --- a/gui/qt/address_dialog.py +++ b/gui/qt/address_dialog.py @@ -23,7 +23,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from electrum.i18n import _ +from electrum_xzc.i18n import _ from PyQt5.QtCore import * from PyQt5.QtGui import * diff --git a/gui/qt/address_list.py b/gui/qt/address_list.py index 8377e6bf0c65..eed640fd8260 100644 --- a/gui/qt/address_list.py +++ b/gui/qt/address_list.py @@ -25,10 +25,10 @@ import webbrowser from .util import * -from electrum.i18n import _ -from electrum.util import block_explorer_URL -from electrum.plugins import run_hook -from electrum.bitcoin import is_address +from electrum_xzc.i18n import _ +from electrum_xzc.util import block_explorer_URL +from electrum_xzc.plugins import run_hook +from electrum_xzc.bitcoin import is_address class AddressList(MyTreeWidget): @@ -38,11 +38,11 @@ def __init__(self, parent=None): MyTreeWidget.__init__(self, parent, self.create_menu, [], 1) self.refresh_headers() self.setSelectionMode(QAbstractItemView.ExtendedSelection) - self.show_change = 0 + self.show_change = False self.show_used = 0 self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) - for t in [_('Receiving'), _('Change'), _('All')]: + for t in [_('Receiving'), _('Change')]: self.change_button.addItem(t) self.used_button = QComboBox(self) self.used_button.currentIndexChanged.connect(self.toggle_used) @@ -60,10 +60,11 @@ def refresh_headers(self): headers.extend([_('Tx')]) self.update_headers(headers) - def toggle_change(self, state): - if state == self.show_change: + def toggle_change(self, show): + show = bool(show) + if show == self.show_change: return - self.show_change = state + self.show_change = show self.update() def toggle_used(self, state): @@ -76,12 +77,7 @@ def on_update(self): self.wallet = self.parent.wallet item = self.currentItem() current_address = item.data(0, Qt.UserRole) if item else None - if self.show_change == 0: - addr_list = self.wallet.get_receiving_addresses() - elif self.show_change == 1: - addr_list = self.wallet.get_change_addresses() - else: - addr_list = self.wallet.get_addresses() + addr_list = self.wallet.get_change_addresses() if self.show_change else self.wallet.get_receiving_addresses() self.clear() for address in addr_list: num = len(self.wallet.history.get(address,[])) @@ -110,14 +106,14 @@ def on_update(self): address_item.setData(0, Qt.UserRole+1, True) # label can be edited if self.wallet.is_frozen(address): address_item.setBackground(0, ColorScheme.BLUE.as_color(True)) - if self.wallet.is_beyond_limit(address): + if self.wallet.is_beyond_limit(address, self.show_change): address_item.setBackground(0, ColorScheme.RED.as_color(True)) self.addChild(address_item) if address == current_address: self.setCurrentItem(address_item) def create_menu(self, position): - from electrum.wallet import Multisig_Wallet + from electrum_xzc.wallet import Multisig_Wallet is_multisig = isinstance(self.wallet, Multisig_Wallet) can_delete = self.wallet.can_delete_address() selected = self.selectedItems() @@ -139,10 +135,10 @@ def create_menu(self, position): if not multi_select: column_title = self.headerItem().text(col) copy_text = item.text(col) - menu.addAction(_("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(copy_text)) + menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(copy_text)) menu.addAction(_('Details'), lambda: self.parent.show_address(addr)) if col in self.editable_columns: - menu.addAction(_("Edit {}").format(column_title), lambda: self.editItem(item, col)) + menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, col)) menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr)) if self.wallet.can_export(): menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr)) diff --git a/gui/qt/amountedit.py b/gui/qt/amountedit.py index 551353289368..204f7721c13c 100644 --- a/gui/qt/amountedit.py +++ b/gui/qt/amountedit.py @@ -5,7 +5,7 @@ from PyQt5.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame) from decimal import Decimal -from electrum.util import format_satoshis_plain +from electrum_xzc.util import format_satoshis_plain class MyLineEdit(QLineEdit): @@ -82,9 +82,9 @@ def __init__(self, decimal_point, is_int = False, parent=None): def _base_unit(self): p = self.decimal_point() if p == 8: - return 'BTC' + return 'XZC' if p == 5: - return 'mBTC' + return 'mXZC' if p == 2: return 'bits' raise Exception('Unknown base unit') @@ -106,7 +106,12 @@ def setAmount(self, amount): class FeerateEdit(BTCAmountEdit): def _base_unit(self): - return 'sat/byte' + p = self.decimal_point() + if p == 2: + return 'mXZC/kB' + if p == 0: + return 'sat/byte' + raise Exception('Unknown base unit') def get_amount(self): sat_per_byte_amount = BTCAmountEdit.get_amount(self) diff --git a/gui/qt/console.py b/gui/qt/console.py index bde05a3dfa2d..af7384b30110 100644 --- a/gui/qt/console.py +++ b/gui/qt/console.py @@ -6,7 +6,7 @@ from PyQt5 import QtCore from PyQt5 import QtGui from PyQt5 import QtWidgets -from electrum import util +from electrum_xzc import util if platform.system() == 'Windows': @@ -203,8 +203,7 @@ def write(self, text): self.skip = not self.skip if type(self.namespace.get(command)) == type(lambda:None): - self.appendPlainText("'{}' is a function. Type '{}()' to use it in the Python console." - .format(command, command)) + self.appendPlainText("'%s' is a function. Type '%s()' to use it in the Python console."%(command, command)) self.newPrompt() return diff --git a/gui/qt/contact_list.py b/gui/qt/contact_list.py index a1794459355f..954794345a48 100644 --- a/gui/qt/contact_list.py +++ b/gui/qt/contact_list.py @@ -24,10 +24,10 @@ # SOFTWARE. import webbrowser -from electrum.i18n import _ -from electrum.bitcoin import is_address -from electrum.util import block_explorer_URL, FileImportFailed -from electrum.plugins import run_hook +from electrum_xzc.i18n import _ +from electrum_xzc.bitcoin import is_address +from electrum_xzc.util import block_explorer_URL +from electrum_xzc.plugins import run_hook from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import ( @@ -57,10 +57,7 @@ def import_contacts(self): filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder) if not filename: return - try: - self.parent.contacts.import_file(filename) - except FileImportFailed as e: - self.parent.show_message(str(e)) + self.parent.contacts.import_file(filename) self.on_update() def create_menu(self, position): @@ -75,10 +72,10 @@ def create_menu(self, position): column = self.currentColumn() column_title = self.headerItem().text(column) column_data = '\n'.join([item.text(column) for item in selected]) - menu.addAction(_("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) + menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data)) if column in self.editable_columns: item = self.currentItem() - menu.addAction(_("Edit {}").format(column_title), lambda: self.editItem(item, column)) + menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column)) menu.addAction(_("Pay to"), lambda: self.parent.payto_contacts(keys)) menu.addAction(_("Delete"), lambda: self.parent.delete_contacts(keys)) URLs = [block_explorer_URL(self.config, 'addr', key) for key in filter(is_address, keys)] diff --git a/gui/qt/exception_window.py b/gui/qt/exception_window.py index a15bbe25a540..c3bcb8688871 100644 --- a/gui/qt/exception_window.py +++ b/gui/qt/exception_window.py @@ -32,9 +32,9 @@ from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import * -from electrum.i18n import _ +from electrum_xzc.i18n import _ import sys -from electrum import ELECTRUM_VERSION, bitcoin +from electrum_xzc import ELECTRUM_VERSION issue_template = """

Traceback

@@ -49,7 +49,7 @@
   
  • Locale: {locale}
  • """ -report_server = "https://crashhub.electrum.org/crash" +report_server = "https://crashhub.electrum-xzc.org/crash" class Exception_Window(QWidget): @@ -59,7 +59,7 @@ def __init__(self, main_window, exctype, value, tb): self.exc_args = (exctype, value, tb) self.main_window = main_window QWidget.__init__(self) - self.setWindowTitle('Electrum - ' + _('An Error Occured')) + self.setWindowTitle('Electrum-XZC - ' + _('An Error Occured')) self.setMinimumSize(600, 300) main_box = QVBoxLayout() @@ -105,10 +105,6 @@ def __init__(self, main_window, exctype, value, tb): self.show() def send_report(self): - if bitcoin.NetworkConstants.GENESIS[-4:] not in ["4943", "e26f"] and ".electrum.org" in report_server: - # Gah! Some kind of altcoin wants to send us crash reports. - self.main_window.show_critical("Please report this issue manually.") - return report = self.get_traceback_info() report.update(self.get_additional_info()) report = json.dumps(report) diff --git a/gui/qt/fee_slider.py b/gui/qt/fee_slider.py index 04911d878219..8645eb9067f8 100644 --- a/gui/qt/fee_slider.py +++ b/gui/qt/fee_slider.py @@ -1,4 +1,6 @@ -from electrum.i18n import _ + +from electrum_xzc.i18n import _ + from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import QSlider, QToolTip @@ -20,30 +22,37 @@ def __init__(self, window, config, callback): def moved(self, pos): with self.lock: - if self.dyn: - fee_rate = self.config.depth_to_fee(pos) if self.config.use_mempool_fees() else self.config.eta_to_fee(pos) - else: - fee_rate = self.config.static_fee(pos) + fee_rate = self.config.dynfee(pos) if self.dyn else self.config.static_fee(pos) tooltip = self.get_tooltip(pos, fee_rate) QToolTip.showText(QCursor.pos(), tooltip, self) self.setToolTip(tooltip) self.callback(self.dyn, pos, fee_rate) def get_tooltip(self, pos, fee_rate): - mempool = self.config.use_mempool_fees() - target, estimate = self.config.get_fee_text(pos, self.dyn, mempool, fee_rate) + from electrum_xzc.util import fee_levels + rate_str = self.window.format_fee_rate(fee_rate) if fee_rate else _('unknown') if self.dyn: - return _('Target') + ': ' + target + '\n' + _('Current rate') + ': ' + estimate + tooltip = fee_levels[pos] + '\n' + rate_str else: - return _('Fixed rate') + ': ' + target + '\n' + _('Estimate') + ': ' + estimate + tooltip = 'Fixed rate: ' + rate_str + if self.config.has_fee_estimates(): + i = self.config.reverse_dynfee(fee_rate) + tooltip += '\n' + (_('Low fee') if i < 0 else 'Within %d blocks'%i) + return tooltip def update(self): with self.lock: self.dyn = self.config.is_dynfee() - mempool = self.config.use_mempool_fees() - maxp, pos, fee_rate = self.config.get_fee_slider(self.dyn, mempool) - self.setRange(0, maxp) - self.setValue(pos) + if self.dyn: + pos = self.config.get('fee_level', 2) + fee_rate = self.config.dynfee(pos) + self.setRange(0, 4) + self.setValue(pos) + else: + fee_rate = self.config.fee_per_kb() + pos = self.config.static_fee_index(fee_rate) + self.setRange(0, 9) + self.setValue(pos) tooltip = self.get_tooltip(pos, fee_rate) self.setToolTip(tooltip) diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py index fcd4deb47cb7..68c34d89af87 100644 --- a/gui/qt/history_list.py +++ b/gui/qt/history_list.py @@ -25,15 +25,16 @@ import webbrowser -from electrum.wallet import UnrelatedTransactionException, TX_HEIGHT_LOCAL +from electrum_xzc.wallet import UnrelatedTransactionException from .util import * -from electrum.i18n import _ -from electrum.util import block_explorer_URL -from electrum.util import timestamp_to_datetime, profiler +from electrum_xzc.i18n import _ +from electrum_xzc.util import block_explorer_URL +from electrum_xzc.util import timestamp_to_datetime, profiler # note: this list needs to be kept in sync with another in kivy TX_ICONS = [ + "warning.png", "warning.png", "warning.png", "unconfirmed.png", @@ -58,15 +59,10 @@ def __init__(self, parent=None): self.setColumnHidden(1, True) def refresh_headers(self): - headers = ['', '', _('Date'), _('Description'), _('Amount'), _('Balance')] + headers = ['', '', _('Date'), _('Description') , _('Amount'), _('Balance')] fx = self.parent.fx if fx and fx.show_history(): - headers.extend(['%s '%fx.ccy + _('Value')]) - headers.extend(['%s '%fx.ccy + _('Acquisition price')]) - headers.extend(['%s '%fx.ccy + _('Capital Gains')]) - self.editable_columns |= {6} - else: - self.editable_columns -= {6} + headers.extend(['%s '%fx.ccy + _('Amount'), '%s '%fx.ccy + _('Balance')]) self.update_headers(headers) def get_domain(self): @@ -91,23 +87,11 @@ def on_update(self): balance_str = self.parent.format_amount(balance, whitespaces=True) label = self.wallet.get_label(tx_hash) entry = ['', tx_hash, status_str, label, v_str, balance_str] - fiat_value = None - if value is not None and fx and fx.show_history(): + if fx and fx.show_history(): date = timestamp_to_datetime(time.time() if conf <= 0 else timestamp) - fiat_value = self.wallet.get_fiat_value(tx_hash, fx.ccy) - if not fiat_value: - fiat_value = fx.historical_value(value, date) - fiat_default = True - else: - fiat_default = False - value_str = fx.format_fiat(fiat_value) - entry.append(value_str) - # fixme: should use is_mine - if value < 0: - ap, lp = self.wallet.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy) - cg = None if lp is None or ap is None else lp - ap - entry.append(fx.format_fiat(ap)) - entry.append(fx.format_fiat(cg)) + for amount in [value, balance]: + text = fx.historical_value_str(amount, date) + entry.append(text) item = QTreeWidgetItem(entry) item.setIcon(0, icon) item.setToolTip(0, str(conf) + " confirmation" + ("s" if conf != 1 else "")) @@ -121,27 +105,12 @@ def on_update(self): if value and value < 0: item.setForeground(3, QBrush(QColor("#BC1E1E"))) item.setForeground(4, QBrush(QColor("#BC1E1E"))) - if fiat_value and not fiat_default: - item.setForeground(6, QBrush(QColor("#1E1EFF"))) if tx_hash: item.setData(0, Qt.UserRole, tx_hash) self.insertTopLevelItem(0, item) if current_tx == tx_hash: self.setCurrentItem(item) - def on_edited(self, item, column, prior): - '''Called only when the text actually changes''' - key = item.data(0, Qt.UserRole) - text = item.text(column) - # fixme - if column == 3: - self.parent.wallet.set_label(key, text) - self.update_labels() - self.parent.update_completions() - elif column == 6: - self.parent.wallet.set_fiat_value(key, self.parent.fx.ccy, text) - self.on_update() - def on_doubleclick(self, item, column): if self.permit_edit(item, column): super(HistoryList, self).on_doubleclick(item, column) @@ -193,12 +162,12 @@ def create_menu(self, position): menu = QMenu() - if height == TX_HEIGHT_LOCAL: + if height == -2: menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash)) - menu.addAction(_("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) - for c in self.editable_columns: - menu.addAction(_("Edit {}").format(self.headerItem().text(c)), lambda: self.editItem(item, c)) + menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data)) + if column in self.editable_columns: + menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column)) menu.addAction(_("Details"), lambda: self.parent.show_transaction(tx)) @@ -232,8 +201,14 @@ def remove_local_tx(self, delete_tx): for tx in to_delete: self.wallet.remove_transaction(tx) self.wallet.save_transactions(write=True) - # need to update at least: history_list, utxo_list, address_list - self.parent.need_update.set() + root = self.invisibleRootItem() + child_count = root.childCount() + _offset = 0 + for i in range(child_count): + item = root.child(i - _offset) + if item.data(0, Qt.UserRole) in to_delete: + root.removeChild(item) + _offset += 1 def onFileAdded(self, fn): with open(fn) as f: @@ -244,5 +219,4 @@ def onFileAdded(self, fn): self.parent.show_error(e) else: self.wallet.save_transactions(write=True) - # need to update at least: history_list, utxo_list, address_list - self.parent.need_update.set() + self.on_update() diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py index d23631aca1a2..ff6768af5eaf 100644 --- a/gui/qt/installwizard.py +++ b/gui/qt/installwizard.py @@ -8,15 +8,15 @@ from PyQt5.QtGui import * from PyQt5.QtWidgets import * -from electrum import Wallet, WalletStorage -from electrum.util import UserCancelled, InvalidPassword -from electrum.base_wizard import BaseWizard, HWD_SETUP_DECRYPT_WALLET -from electrum.i18n import _ +from electrum_xzc import Wallet, WalletStorage +from electrum_xzc.util import UserCancelled, InvalidPassword +from electrum_xzc.base_wizard import BaseWizard +from electrum_xzc.i18n import _ from .seed_dialog import SeedLayout, KeysLayout from .network_dialog import NetworkChoiceLayout from .util import * -from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW +from .password_dialog import PasswordLayout, PW_NEW class GoBack(Exception): @@ -24,15 +24,11 @@ class GoBack(Exception): MSG_GENERATING_WAIT = _("Electrum is generating your addresses, please wait...") MSG_ENTER_ANYTHING = _("Please enter a seed phrase, a master key, a list of " - "Bitcoin addresses, or a list of private keys") + "Zcoin addresses, or a list of private keys") MSG_ENTER_SEED_OR_MPK = _("Please enter a seed phrase or a master key (xpub or xprv):") -MSG_COSIGNER = _("Please enter the master public key of cosigner #{}:") +MSG_COSIGNER = _("Please enter the master public key of cosigner #%d:") MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\ + _("Leave this field empty if you want to disable encryption.") -MSG_HW_STORAGE_ENCRYPTION = _("Set wallet file encryption.") + '\n'\ - + _("Your wallet file does not contain secrets, mostly just metadata. ") \ - + _("It also contains your master public key that allows watching your addresses.") + '\n\n'\ - + _("Note: If you enable this setting, you will need your hardware device to open your wallet.") MSG_RESTORE_PASSPHRASE = \ _("Please enter your seed derivation passphrase. " "Note: this is NOT your encryption password. " @@ -106,7 +102,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): def __init__(self, config, app, plugins, storage): BaseWizard.__init__(self, config, storage) QDialog.__init__(self, None) - self.setWindowTitle('Electrum - ' + _('Install Wizard')) + self.setWindowTitle('Electrum-XZC - ' + _('Install Wizard')) self.app = app self.config = config # Set for base base class @@ -151,7 +147,7 @@ def __init__(self, config, app, plugins, storage): hbox.setStretchFactor(scroll, 1) outer_vbox.addLayout(hbox) outer_vbox.addLayout(Buttons(self.back_button, self.next_button)) - self.set_icon(':icons/electrum.png') + self.set_icon(':icons/electrum-xzc.png') self.show() self.raise_() self.refresh_gui() # Need for QT on MacOSX. Lame. @@ -178,7 +174,7 @@ def run_and_get_wallet(self): hbox2.addWidget(self.pw_e) hbox2.addStretch() vbox.addLayout(hbox2) - self.set_layout(vbox, title=_('Electrum wallet')) + self.set_layout(vbox, title=_('Electrum-XZC wallet')) wallet_folder = os.path.dirname(self.storage.path) @@ -200,18 +196,12 @@ def on_filename(filename): msg =_("This file does not exist.") + '\n' \ + _("Press 'Next' to create this wallet, or choose another file.") pw = False + elif self.storage.file_exists() and self.storage.is_encrypted(): + msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.') + pw = True else: - if self.storage.is_encrypted_with_user_pw(): - msg = _("This file is encrypted with a password.") + '\n' \ - + _('Enter your password or choose another file.') - pw = True - elif self.storage.is_encrypted_with_hw_device(): - msg = _("This file is encrypted using a hardware device.") + '\n' \ - + _("Press 'Next' to choose device to decrypt.") - pw = False - else: - msg = _("Press 'Next' to open this wallet.") - pw = False + msg = _("Press 'Next' to open this wallet.") + pw = False else: msg = _('Cannot read file') pw = False @@ -237,46 +227,23 @@ def on_filename(filename): if not self.storage.file_exists(): break if self.storage.file_exists() and self.storage.is_encrypted(): - if self.storage.is_encrypted_with_user_pw(): - password = self.pw_e.text() - try: - self.storage.decrypt(password) - break - except InvalidPassword as e: - QMessageBox.information(None, _('Error'), str(e)) - continue - except BaseException as e: - traceback.print_exc(file=sys.stdout) - QMessageBox.information(None, _('Error'), str(e)) - return - elif self.storage.is_encrypted_with_hw_device(): - try: - self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET) - except InvalidPassword as e: - # FIXME if we get here because of mistyped passphrase - # then that passphrase gets "cached" - QMessageBox.information( - None, _('Error'), - _('Failed to decrypt using this hardware device.') + '\n' + - _('If you use a passphrase, make sure it is correct.')) - self.stack = [] - return self.run_and_get_wallet() - except BaseException as e: - traceback.print_exc(file=sys.stdout) - QMessageBox.information(None, _('Error'), str(e)) - return - if self.storage.is_past_initial_decryption(): - break - else: - return - else: - raise Exception('Unexpected encryption version') + password = self.pw_e.text() + try: + self.storage.decrypt(password) + break + except InvalidPassword as e: + QMessageBox.information(None, _('Error'), str(e)) + continue + except BaseException as e: + traceback.print_exc(file=sys.stdout) + QMessageBox.information(None, _('Error'), str(e)) + return path = self.storage.path if self.storage.requires_split(): self.hide() - msg = _("The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n" - "Do you want to split your wallet into multiple files?").format(path) + msg = _("The wallet '%s' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n" + "Do you want to split your wallet into multiple files?"%path) if not self.question(msg): return file_list = '\n'.join(self.storage.split_accounts()) @@ -294,10 +261,10 @@ def on_filename(filename): action = self.storage.get_action() if action and action != 'new': self.hide() - msg = _("The file '{}' contains an incompletely created wallet.\n" - "Do you want to complete its creation now?").format(path) + msg = _("The file '%s' contains an incompletely created wallet.\n" + "Do you want to complete its creation now?") % path if not self.question(msg): - if self.question(_("Do you want to delete '{}'?").format(path)): + if self.question(_("Do you want to delete '%s'?") % path): os.remove(path) self.show_warning(_('The file was removed')) return @@ -419,25 +386,17 @@ def show_seed_dialog(self, run_next, seed_text): self.exec_layout(slayout) return slayout.is_ext - def pw_layout(self, msg, kind, force_disable_encrypt_cb): - playout = PasswordLayout(None, msg, kind, self.next_button, - force_disable_encrypt_cb=force_disable_encrypt_cb) + def pw_layout(self, msg, kind): + playout = PasswordLayout(None, msg, kind, self.next_button) playout.encrypt_cb.setChecked(True) self.exec_layout(playout.layout()) return playout.new_password(), playout.encrypt_cb.isChecked() @wizard_dialog - def request_password(self, run_next, force_disable_encrypt_cb=False): + def request_password(self, run_next): """Request the user enter a new password and confirm it. Return the password or None for no password.""" - return self.pw_layout(MSG_ENTER_PASSWORD, PW_NEW, force_disable_encrypt_cb) - - @wizard_dialog - def request_storage_encryption(self, run_next): - playout = PasswordLayoutForHW(None, MSG_HW_STORAGE_ENCRYPTION, PW_NEW, self.next_button) - playout.encrypt_cb.setChecked(True) - self.exec_layout(playout.layout()) - return playout.encrypt_cb.isChecked() + return self.pw_layout(MSG_ENTER_PASSWORD, PW_NEW) def show_restore(self, wallet, network): # FIXME: these messages are shown after the install wizard is diff --git a/gui/qt/invoice_list.py b/gui/qt/invoice_list.py index a4a8374f7ed2..c701aa40f5c8 100644 --- a/gui/qt/invoice_list.py +++ b/gui/qt/invoice_list.py @@ -24,8 +24,8 @@ # SOFTWARE. from .util import * -from electrum.i18n import _ -from electrum.util import format_time, FileImportFailed +from electrum_xzc.i18n import _ +from electrum_xzc.util import format_time class InvoiceList(MyTreeWidget): @@ -61,10 +61,7 @@ def import_invoices(self): filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder) if not filename: return - try: - self.parent.invoices.import_file(filename) - except FileImportFailed as e: - self.parent.show_message(str(e)) + self.parent.invoices.import_file(filename) self.on_update() def create_menu(self, position): @@ -79,7 +76,7 @@ def create_menu(self, position): pr = self.parent.invoices.get(key) status = self.parent.invoices.get_status(key) if column_data: - menu.addAction(_("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) + menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data)) menu.addAction(_("Details"), lambda: self.parent.show_invoice(key)) if status == PR_UNPAID: menu.addAction(_("Pay Now"), lambda: self.parent.do_pay_invoice(key)) diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py index df86e3e893b8..ab05858a2853 100644 --- a/gui/qt/main_window.py +++ b/gui/qt/main_window.py @@ -39,21 +39,21 @@ from .exception_window import Exception_Hook from PyQt5.QtWidgets import * -from electrum.util import bh2u, bfh - -from electrum import keystore, simple_config -from electrum.bitcoin import COIN, is_address, TYPE_ADDRESS, NetworkConstants -from electrum.plugins import run_hook -from electrum.i18n import _ -from electrum.util import (format_time, format_satoshis, PrintError, - format_satoshis_plain, NotEnoughFunds, - UserCancelled, NoDynamicFeeEstimates) -from electrum import Transaction -from electrum import util, bitcoin, commands, coinchooser -from electrum import paymentrequest -from electrum.wallet import Multisig_Wallet +from electrum_xzc.util import bh2u, bfh + +from electrum_xzc import keystore, simple_config +from electrum_xzc.bitcoin import COIN, is_address, TYPE_ADDRESS, NetworkConstants +from electrum_xzc.plugins import run_hook +from electrum_xzc.i18n import _ +from electrum_xzc.util import (format_time, format_satoshis, PrintError, + format_satoshis_plain, NotEnoughFunds, + UserCancelled, NoDynamicFeeEstimates) +from electrum_xzc import Transaction +from electrum_xzc import util, bitcoin, commands, coinchooser +from electrum_xzc import paymentrequest +from electrum_xzc.wallet import Multisig_Wallet try: - from electrum.plot import plot_history + from electrum_xzc.plot import plot_history except: plot_history = None @@ -65,7 +65,7 @@ from .util import * -from electrum.util import profiler +from electrum_xzc.util import profiler class StatusBarButton(QPushButton): def __init__(self, icon, tooltip, func): @@ -86,7 +86,7 @@ def keyPressEvent(self, e): self.func() -from electrum.paymentrequest import PR_PAID +from electrum_xzc.paymentrequest import PR_PAID class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): @@ -130,7 +130,8 @@ def __init__(self, gui_object, wallet): self.create_status_bar() self.need_update = threading.Event() - self.decimal_point = config.get('decimal_point', 5) + self.decimal_point = config.get('decimal_point', 8) + self.fee_unit = config.get('fee_unit', 0) self.num_zeros = int(config.get('num_zeros',0)) self.completions = QStringListModel() @@ -165,7 +166,7 @@ def add_optional_tab(tabs, tab, icon, description, name): if self.config.get("is_maximized"): self.showMaximized() - self.setWindowIcon(QIcon(":icons/electrum.png")) + self.setWindowIcon(QIcon(":icons/electrum-xzc.png")) self.init_menubar() wrtabs = weakref.proxy(tabs) @@ -292,6 +293,7 @@ def on_network(self, event, *args): self.need_update.set() self.gui_object.network_updated_signal_obj.network_updated_signal \ .emit(event, args) + elif event == 'new_transaction': self.tx_notifications.append(args[0]) self.notify_transactions_signal.emit() @@ -313,12 +315,6 @@ def on_network_qt(self, event, args=None): if self.config.is_dynfee(): self.fee_slider.update() self.do_update_fee() - elif event == 'fee_histogram': - if self.config.is_dynfee(): - self.fee_slider.update() - self.do_update_fee() - # todo: update only unconfirmed tx - self.history_list.update() else: self.print_error("unexpected network_qt signal:", event, args) @@ -378,7 +374,7 @@ def init_geometry(self): self.setGeometry(100, 100, 840, 400) def watching_only_changed(self): - name = "Electrum Testnet" if NetworkConstants.TESTNET else "Electrum" + name = "Electrum-XZC Testnet" if NetworkConstants.TESTNET else "Electrum-XZC" title = '%s %s - %s' % (name, self.wallet.electrum_version, self.wallet.basename()) extra = [self.wallet.storage.get('wallet_type', '?')] @@ -387,7 +383,7 @@ def watching_only_changed(self): extra.append(_('watching only')) title += ' [%s]'% ', '.join(extra) self.setWindowTitle(title) - self.password_menu.setEnabled(self.wallet.may_have_password()) + self.password_menu.setEnabled(self.wallet.can_change_password()) self.import_privkey_menu.setVisible(self.wallet.can_import_privkey()) self.import_address_menu.setVisible(self.wallet.can_import_address()) self.export_menu.setEnabled(self.wallet.can_export()) @@ -396,8 +392,8 @@ def warn_if_watching_only(self): if self.wallet.is_watching_only(): msg = ' '.join([ _("This wallet is watching-only."), - _("This means you will not be able to spend Bitcoins with it."), - _("Make sure you own the seed phrase or the private keys, before you request Bitcoins to be sent to this wallet.") + _("This means you will not be able to spend zcoins with it."), + _("Make sure you own the seed phrase or the private keys, before you request zcoins to be sent to this wallet.") ]) self.show_warning(msg, title=_('Information')) @@ -531,7 +527,7 @@ def add_toggle_action(view_menu, tab): help_menu = menubar.addMenu(_("&Help")) help_menu.addAction(_("&About"), self.show_about) - help_menu.addAction(_("&Official website"), lambda: webbrowser.open("http://electrum.org")) + help_menu.addAction(_("&Official website"), lambda: webbrowser.open("http://electrum-xzc.org")) help_menu.addSeparator() help_menu.addAction(_("&Documentation"), lambda: webbrowser.open("http://docs.electrum.org/")).setShortcut(QKeySequence.HelpContents) help_menu.addAction(_("&Report Bug"), self.show_report_bug) @@ -544,24 +540,24 @@ def donate_to_server(self): d = self.network.get_donation_address() if d: host = self.network.get_parameters()[0] - self.pay_to_URI('bitcoin:%s?message=donation for %s'%(d, host)) + self.pay_to_URI('zcoin:%s?message=donation for %s'%(d, host)) else: self.show_error(_('No donation address for this server')) def show_about(self): - QMessageBox.about(self, "Electrum", + QMessageBox.about(self, "Electrum-XZC", _("Version")+" %s" % (self.wallet.electrum_version) + "\n\n" + - _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Bitcoin system." + "\n\n" + + _("Electrum's focus is speed, with low resource usage and simplifying Zcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Zcoin system." + "\n\n" + _("Uses icons from the Icons8 icon pack (icons8.com)."))) def show_report_bug(self): msg = ' '.join([ _("Please report any bugs as issues on github:
    "), - "https://github.com/spesmilo/electrum/issues

    ", + "https://github.com/sn-ntu/electrum-xzc/issues

    ", _("Before reporting a bug, upgrade to the most recent version of Electrum (latest release or git HEAD), and include the version number in your report."), _("Try to explain not only what the bug is, but how it occurs.") ]) - self.show_message(msg, title="Electrum - " + _("Reporting Bugs")) + self.show_message(msg, title="Electrum-XZC - " + _("Reporting Bugs")) def notify_transactions(self): if not self.network or not self.network.is_connected(): @@ -591,9 +587,9 @@ def notify(self, message): if self.tray: try: # this requires Qt 5.9 - self.tray.showMessage("Electrum", message, QIcon(":icons/electrum_dark_icon"), 20000) + self.tray.showMessage("Electrum-XZC", message, QIcon(":icons/electrum_dark_icon"), 20000) except TypeError: - self.tray.showMessage("Electrum", message, QSystemTrayIcon.Information, 20000) + self.tray.showMessage("Electrum-XZC", message, QSystemTrayIcon.Information, 20000) @@ -640,7 +636,10 @@ def format_amount_and_units(self, amount): return text def format_fee_rate(self, fee_rate): - return format_satoshis(fee_rate/1000, False, self.num_zeros, 0, False) + ' sat/byte' + if self.fee_unit == 0: + return format_satoshis(fee_rate/1000, False, self.num_zeros, 0, False) + ' sat/byte' + else: + return self.format_amount(fee_rate) + ' ' + self.base_unit() + '/kB' def get_decimal_point(self): return self.decimal_point @@ -650,9 +649,9 @@ def base_unit(self): if self.decimal_point == 2: return 'bits' if self.decimal_point == 5: - return 'mBTC' + return 'mXZC' if self.decimal_point == 8: - return 'BTC' + return 'XZC' raise Exception('Unknown base unit') def connect_fields(self, window, btc_e, fiat_e, fee_e): @@ -776,7 +775,7 @@ def create_receive_tab(self): self.receive_address_e = ButtonsLineEdit() self.receive_address_e.addCopyButton(self.app) self.receive_address_e.setReadOnly(True) - msg = _('Bitcoin address where the payment should be received. Note that each payment request uses a different Bitcoin address.') + msg = _('Zcoin address where the payment should be received. Note that each payment request uses a different Zcoin address.') self.receive_address_label = HelpLabel(_('Receiving address'), msg) self.receive_address_e.textChanged.connect(self.update_receive_qr) self.receive_address_e.setFocusPolicy(Qt.NoFocus) @@ -806,8 +805,8 @@ def create_receive_tab(self): msg = ' '.join([ _('Expiration date of your request.'), _('This information is seen by the recipient if you send them a signed payment request.'), - _('Expired requests have to be deleted manually from your list, in order to free the corresponding Bitcoin addresses.'), - _('The bitcoin address never expires and will always be part of this electrum wallet.'), + _('Expired requests have to be deleted manually from your list, in order to free the corresponding Zcoin addresses.'), + _('The Zcoin address never expires and will always be part of this Electrum wallet.'), ]) grid.addWidget(HelpLabel(_('Request expires'), msg), 3, 0) grid.addWidget(self.expires_combo, 3, 1) @@ -889,15 +888,14 @@ def sign_payment_request(self, addr): if alias_addr: if self.wallet.is_mine(alias_addr): msg = _('This payment request will be signed.') + '\n' + _('Please enter your password') - password = None - if self.wallet.has_keystore_encryption(): - password = self.password_dialog(msg) - if not password: + password = self.password_dialog(msg) + if password: + try: + self.wallet.sign_payment_request(addr, alias, alias_addr, password) + except Exception as e: + self.show_error(str(e)) return - try: - self.wallet.sign_payment_request(addr, alias, alias_addr, password) - except Exception as e: - self.show_error(str(e)) + else: return else: return @@ -1012,10 +1010,6 @@ def update_receive_qr(self): if self.qr_window and self.qr_window.isVisible(): self.qr_window.set_content(addr, amount, message, uri) - def set_feerounding_text(self, num_satoshis_added): - self.feerounding_text = (_('Additional {} satoshis are going to be added.') - .format(num_satoshis_added)) - def create_send_tab(self): # A 4-column grid layout. All the stretch is in the last column. # The exchange rate plugin adds a fiat widget in column 2 @@ -1027,7 +1021,7 @@ def create_send_tab(self): self.amount_e = BTCAmountEdit(self.get_decimal_point) self.payto_e = PayToEdit(self) msg = _('Recipient of the funds.') + '\n\n'\ - + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)') + + _('You may enter a Zcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Zcoin address)') payto_label = HelpLabel(_('Pay to'), msg) grid.addWidget(payto_label, 1, 0) grid.addWidget(self.payto_e, 1, 1, 1, -1) @@ -1074,17 +1068,14 @@ def create_send_tab(self): hbox.addStretch(1) grid.addLayout(hbox, 4, 4) - msg = _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + msg = _('Zcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\ + _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.') self.fee_e_label = HelpLabel(_('Fee'), msg) def fee_cb(dyn, pos, fee_rate): if dyn: - if self.config.use_mempool_fees(): - self.config.set_key('depth_level', pos, False) - else: - self.config.set_key('fee_level', pos, False) + self.config.set_key('fee_level', pos, False) else: self.config.set_key('fee_per_kb', fee_rate, False) @@ -1124,7 +1115,7 @@ def setAmount(self, byte_size): self.size_e.setFixedWidth(140) self.size_e.setStyleSheet(ColorScheme.DEFAULT.as_stylesheet()) - self.feerate_e = FeerateEdit(lambda: 0) + self.feerate_e = FeerateEdit(lambda: 2 if self.fee_unit else 0) self.feerate_e.setAmount(self.config.fee_per_byte()) self.feerate_e.textEdited.connect(partial(on_fee_or_feerate, self.feerate_e, False)) self.feerate_e.editingFinished.connect(partial(on_fee_or_feerate, self.feerate_e, True)) @@ -1134,10 +1125,8 @@ def setAmount(self, byte_size): self.fee_e.editingFinished.connect(partial(on_fee_or_feerate, self.fee_e, True)) def feerounding_onclick(): - text = (self.feerounding_text + '\n\n' + - _('To somewhat protect your privacy, Electrum tries to create change with similar precision to other outputs.') + ' ' + - _('At most 100 satoshis might be lost due to this rounding.') + ' ' + - _("You can disable this setting in '{}'.").format(_('Preferences')) + '\n' + + text = (_('To somewhat protect your privacy, Electrum tries to create change with similar precision to other outputs.') + ' ' + + _('At most 100 satoshis might be lost due to this rounding.') + '\n' + _('Also, dust is not kept as change, but added to the fee.')) QMessageBox.information(self, 'Fee rounding', text) @@ -1266,6 +1255,9 @@ def do_update_fee(self): '''Recalculate the fee. If the fee was manually input, retain it, but still build the TX to see if there are enough funds. ''' + if not self.config.get('offline') and self.config.is_dynfee() and not self.config.has_fee_estimates(): + self.statusBar().showMessage(_('Waiting for fee estimates...')) + return False freeze_fee = self.is_send_fee_frozen() freeze_feerate = self.is_send_feerate_frozen() amount = '!' if self.is_max else self.amount_e.get_amount() @@ -1336,9 +1328,12 @@ def do_update_fee(self): # show/hide fee rounding icon feerounding = (fee - displayed_fee) if fee else 0 - self.set_feerounding_text(feerounding) - self.feerounding_icon.setToolTip(self.feerounding_text) - self.feerounding_icon.setVisible(bool(feerounding)) + if feerounding: + self.feerounding_icon.setToolTip( + _('additional {} satoshis will be added').format(feerounding)) + self.feerounding_icon.setVisible(True) + else: + self.feerounding_icon.setVisible(False) if self.is_max: amount = tx.output_value() @@ -1388,7 +1383,7 @@ def protected(func): def request_password(self, *args, **kwargs): parent = self.top_level_window() password = None - while self.wallet.has_keystore_encryption(): + while self.wallet.has_password(): password = self.password_dialog(parent=parent) if password is None: # User cancelled password input @@ -1453,10 +1448,10 @@ def read_send_tab(self): for _type, addr, amount in outputs: if addr is None: - self.show_error(_('Bitcoin Address is None')) + self.show_error(_('Zcoin Address is None')) return if _type == TYPE_ADDRESS and not bitcoin.is_address(addr): - self.show_error(_('Invalid Bitcoin Address')) + self.show_error(_('Invalid Zcoin Address')) return if amount is None: self.show_error(_('Invalid Amount')) @@ -1523,7 +1518,7 @@ def do_send(self, preview = False): if fee > confirm_rate * tx.estimated_size() / 1000: msg.append(_('Warning') + ': ' + _("The fee for this transaction seems unusually high.")) - if self.wallet.has_keystore_encryption(): + if self.wallet.has_password(): msg.append("") msg.append(_("Enter your password to proceed")) password = self.password_dialog('\n'.join(msg)) @@ -1673,7 +1668,7 @@ def pay_to_URI(self, URI): try: out = util.parse_URI(URI, self.on_pr) except BaseException as e: - self.show_error(_('Invalid bitcoin URI:') + '\n' + str(e)) + self.show_error(_('Invalid zcoin URI:') + '\n' + str(e)) return self.show_send_tab() r = out.get('r') @@ -1926,37 +1921,17 @@ def update_lock_icon(self): def update_buttons_on_seed(self): self.seed_button.setVisible(self.wallet.has_seed()) - self.password_button.setVisible(self.wallet.may_have_password()) + self.password_button.setVisible(self.wallet.can_change_password()) self.send_button.setVisible(not self.wallet.is_watching_only()) def change_password_dialog(self): - from electrum.storage import STO_EV_XPUB_PW - if self.wallet.get_available_storage_encryption_version() == STO_EV_XPUB_PW: - from .password_dialog import ChangePasswordDialogForHW - d = ChangePasswordDialogForHW(self, self.wallet) - ok, encrypt_file = d.run() - if not ok: - return - - try: - hw_dev_pw = self.wallet.keystore.get_password_for_storage_encryption() - except UserCancelled: - return - except BaseException as e: - traceback.print_exc(file=sys.stderr) - self.show_error(str(e)) - return - old_password = hw_dev_pw if self.wallet.has_password() else None - new_password = hw_dev_pw if encrypt_file else None - else: - from .password_dialog import ChangePasswordDialogForSW - d = ChangePasswordDialogForSW(self, self.wallet) - ok, old_password, new_password, encrypt_file = d.run() - + from .password_dialog import ChangePasswordDialog + d = ChangePasswordDialog(self, self.wallet) + ok, password, new_password, encrypt_file = d.run() if not ok: return try: - self.wallet.update_password(old_password, new_password, encrypt_file) + self.wallet.update_password(password, new_password, encrypt_file) except BaseException as e: self.show_error(str(e)) return @@ -1964,7 +1939,7 @@ def change_password_dialog(self): traceback.print_exc(file=sys.stdout) self.show_error(_('Failed to update password')) return - msg = _('Password was updated successfully') if self.wallet.has_password() else _('Password is disabled, this wallet is not protected') + msg = _('Password was updated successfully') if new_password else _('Password is disabled, this wallet is not protected') self.show_message(msg, title=_("Success")) self.update_lock_icon() @@ -2118,10 +2093,7 @@ def do_sign(self, address, message, signature, password): address = address.text().strip() message = message.toPlainText().strip() if not bitcoin.is_address(address): - self.show_message(_('Invalid Bitcoin address.')) - return - if self.wallet.is_watching_only(): - self.show_message(_('This is a watching-only wallet.')) + self.show_message(_('Invalid Zcoin address.')) return if not self.wallet.is_mine(address): self.show_message(_('Address not in wallet.')) @@ -2141,7 +2113,7 @@ def do_verify(self, address, message, signature): address = address.text().strip() message = message.toPlainText().strip().encode('utf-8') if not bitcoin.is_address(address): - self.show_message(_('Invalid Bitcoin address.')) + self.show_message(_('Invalid Zcoin address.')) return try: # This can throw on invalid base64 @@ -2193,9 +2165,6 @@ def sign_verify_message(self, address=''): @protected def do_decrypt(self, message_e, pubkey_e, encrypted_e, password): - if self.wallet.is_watching_only(): - self.show_message(_('This is a watching-only wallet.')) - return cyphertext = encrypted_e.toPlainText() task = partial(self.wallet.decrypt_message, pubkey_e.text(), cyphertext, password) self.wallet.thread.add(task, on_success=lambda text: message_e.setText(text.decode('utf-8'))) @@ -2256,7 +2225,7 @@ def password_dialog(self, msg=None, parent=None): return d.run() def tx_from_text(self, txt): - from electrum.transaction import tx_from_str + from electrum_xzc.transaction import tx_from_str try: tx = tx_from_str(txt) return Transaction(tx) @@ -2265,7 +2234,7 @@ def tx_from_text(self, txt): return def read_tx_from_qrcode(self): - from electrum import qrscanner + from electrum_xzc import qrscanner try: data = qrscanner.scan_barcode(self.config.get_video_device()) except BaseException as e: @@ -2274,7 +2243,7 @@ def read_tx_from_qrcode(self): if not data: return # if the user scanned a bitcoin URI - if str(data).startswith("bitcoin:"): + if str(data).startswith("zcoin:"): self.pay_to_URI(data) return # else if the user scanned an offline signed tx @@ -2297,7 +2266,7 @@ def read_tx_from_file(self): return self.tx_from_text(file_content) def do_process_from_text(self): - from electrum.transaction import SerializationError + from electrum_xzc.transaction import SerializationError text = text_dialog(self, _('Input raw transaction'), _("Transaction:"), _("Load transaction")) if not text: return @@ -2309,7 +2278,7 @@ def do_process_from_text(self): self.show_critical(_("Electrum was unable to deserialize the transaction:") + "\n" + str(e)) def do_process_from_file(self): - from electrum.transaction import SerializationError + from electrum_xzc.transaction import SerializationError try: tx = self.read_tx_from_file() if tx: @@ -2318,7 +2287,7 @@ def do_process_from_file(self): self.show_critical(_("Electrum was unable to deserialize the transaction:") + "\n" + str(e)) def do_process_from_txid(self): - from electrum import transaction + from electrum_xzc import transaction txid, ok = QInputDialog.getText(self, _('Lookup transaction'), _('Transaction ID') + ':') if ok and txid: txid = str(txid).strip() @@ -2353,7 +2322,7 @@ def export_privkeys_dialog(self, password): e.setReadOnly(True) vbox.addWidget(e) - defaultname = 'electrum-private-keys.csv' + defaultname = 'electrum-xzc-private-keys.csv' select_msg = _('Select file to export your private keys to') hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg) vbox.addLayout(hbox) @@ -2450,7 +2419,7 @@ def do_import_labels(self): def do_export_labels(self): labels = self.wallet.labels try: - fileName = self.getSaveFileName(_("Select file to save your labels"), 'electrum_labels.json', "*.json") + fileName = self.getSaveFileName(_("Select file to save your labels"), 'electrum-xzc_labels.json', "*.json") if fileName: with open(fileName, 'w+') as f: json.dump(labels, f, indent=4, sort_keys=True) @@ -2462,7 +2431,7 @@ def export_history_dialog(self): d = WindowModalDialog(self, _('Export History')) d.setMinimumSize(400, 200) vbox = QVBoxLayout(d) - defaultname = os.path.expanduser('~/electrum-history.csv') + defaultname = os.path.expanduser('~/electrum-xzc-history.csv') select_msg = _('Select file to export your wallet transactions to') hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg) vbox.addLayout(hbox) @@ -2494,13 +2463,32 @@ def plot_history_dialog(self): plt.show() def do_export_history(self, wallet, fileName, is_csv): - history = wallet.export_history(fx=self.fx) + history = wallet.get_history() lines = [] for item in history: + tx_hash, height, confirmations, timestamp, value, balance = item + if height>0: + if timestamp is not None: + time_string = format_time(timestamp) + else: + time_string = _("unverified") + else: + time_string = _("unconfirmed") + + if value is not None: + value_string = format_satoshis(value, True) + else: + value_string = '--' + + if tx_hash: + label = wallet.get_label(tx_hash) + else: + label = "" + if is_csv: - lines.append([item['txid'], item.get('label', ''), item['confirmations'], item['value'], item['date']]) + lines.append([tx_hash, label, confirmations, value_string, time_string]) else: - lines.append(item) + lines.append({'txid':tx_hash, 'date':"%16s"%time_string, 'label':label, 'value':value_string}) with open(fileName, "w+") as f: if is_csv: @@ -2510,7 +2498,7 @@ def do_export_history(self, wallet, fileName, is_csv): transaction.writerow(line) else: import json - f.write(json.dumps(lines, indent=4)) + f.write(json.dumps(lines, indent = 4)) def sweep_key_dialog(self): d = WindowModalDialog(self, title=_('Sweep private keys')) @@ -2553,7 +2541,7 @@ def get_pk(): address_e.textChanged.connect(on_address) if not d.exec_(): return - from electrum.wallet import sweep_preparations + from electrum_xzc.wallet import sweep_preparations try: self.do_clear() coins, keypairs = sweep_preparations(get_pk(), self.network) @@ -2626,7 +2614,7 @@ def settings_dialog(self): lang_help = _('Select which language is used in the GUI (after restart).') lang_label = HelpLabel(_('Language') + ':', lang_help) lang_combo = QComboBox() - from electrum.i18n import languages + from electrum_xzc.i18n import languages lang_combo.addItems(list(languages.values())) try: index = languages.keys().index(self.config.get("language",'')) @@ -2661,21 +2649,6 @@ def on_nz(): nz.valueChanged.connect(on_nz) gui_widgets.append((nz_label, nz)) - msg = '\n'.join([ - _('Time based: fee rate is based on average confirmation time estimates'), - _('Mempool based: fee rate is targetting a depth in the memory pool') - ] - ) - fee_type_label = HelpLabel(_('Fee estimation') + ':', msg) - fee_type_combo = QComboBox() - fee_type_combo.addItems([_('Time based'), _('Mempool based')]) - fee_type_combo.setCurrentIndex(1 if self.config.use_mempool_fees() else 0) - def on_fee_type(x): - self.config.set_key('mempool_fees', x==1) - self.fee_slider.update() - fee_type_combo.currentIndexChanged.connect(on_fee_type) - fee_widgets.append((fee_type_label, fee_type_combo)) - def on_dynfee(x): self.config.set_key('dynamic_fees', x == Qt.Checked) self.fee_slider.update() @@ -2705,6 +2678,18 @@ def on_use_rbf(x): use_rbf_cb.stateChanged.connect(on_use_rbf) fee_widgets.append((use_rbf_cb, None)) + self.fee_unit = self.config.get('fee_unit', 0) + fee_unit_label = HelpLabel(_('Fee Unit') + ':', '') + fee_unit_combo = QComboBox() + fee_unit_combo.addItems([_('sat/byte'), _('mXZC/kB')]) + fee_unit_combo.setCurrentIndex(self.fee_unit) + def on_fee_unit(x): + self.fee_unit = x + self.config.set_key('fee_unit', x) + self.fee_slider.update() + fee_unit_combo.currentIndexChanged.connect(on_fee_unit) + fee_widgets.append((fee_unit_label, fee_unit_combo)) + msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\ + _('The following alias providers are available:') + '\n'\ + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\ @@ -2755,9 +2740,9 @@ def on_alias_edit(): SSL_id_e.setReadOnly(True) id_widgets.append((SSL_id_label, SSL_id_e)) - units = ['BTC', 'mBTC', 'bits'] + units = ['XZC', 'mXZC', 'bits'] msg = _('Base unit of your wallet.')\ - + '\n1BTC=1000mBTC.\n' \ + + '\n1XZC=1000mXZC.\n' \ + _(' These settings affects the fields in the Send tab')+' ' unit_label = HelpLabel(_('Base unit') + ':', msg) unit_combo = QComboBox() @@ -2769,9 +2754,9 @@ def on_unit(x, nz): return edits = self.amount_e, self.fee_e, self.receive_amount_e amounts = [edit.get_amount() for edit in edits] - if unit_result == 'BTC': + if unit_result == 'XZC': self.decimal_point = 8 - elif unit_result == 'mBTC': + elif unit_result == 'mXZC': self.decimal_point = 5 elif unit_result == 'bits': self.decimal_point = 2 @@ -2800,7 +2785,7 @@ def on_be(x): block_ex_combo.currentIndexChanged.connect(on_be) gui_widgets.append((block_ex_label, block_ex_combo)) - from electrum import qrscanner + from electrum_xzc import qrscanner system_cameras = qrscanner._find_system_cameras() qr_combo = QComboBox() qr_combo.addItem("Default","default") @@ -2875,18 +2860,6 @@ def on_unconf(x): unconf_cb.stateChanged.connect(on_unconf) tx_widgets.append((unconf_cb, None)) - def on_outrounding(x): - self.config.set_key('coin_chooser_output_rounding', bool(x)) - enable_outrounding = self.config.get('coin_chooser_output_rounding', False) - outrounding_cb = QCheckBox(_('Enable output value rounding')) - outrounding_cb.setToolTip( - _('Set the value of the change output so that it has similar precision to the other outputs.') + '\n' + - _('This might improve your privacy somewhat.') + '\n' + - _('If enabled, at most 100 satoshis might be lost due to this, per transaction.')) - outrounding_cb.setChecked(enable_outrounding) - outrounding_cb.stateChanged.connect(on_outrounding) - tx_widgets.append((outrounding_cb, None)) - # Fiat Currency hist_checkbox = QCheckBox() fiat_address_checkbox = QCheckBox() diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py index f1c578e36c29..f0e5f02877fd 100644 --- a/gui/qt/network_dialog.py +++ b/gui/qt/network_dialog.py @@ -30,10 +30,10 @@ from PyQt5.QtWidgets import * import PyQt5.QtCore as QtCore -from electrum.i18n import _ -from electrum.bitcoin import NetworkConstants -from electrum.util import print_error -from electrum.network import serialize_server, deserialize_server +from electrum_xzc.i18n import _ +from electrum_xzc.bitcoin import NetworkConstants +from electrum_xzc.util import print_error +from electrum_xzc.network import serialize_server, deserialize_server from .util import * diff --git a/gui/qt/password_dialog.py b/gui/qt/password_dialog.py index e0da43021c8e..5784307b283b 100644 --- a/gui/qt/password_dialog.py +++ b/gui/qt/password_dialog.py @@ -26,12 +26,12 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import * from PyQt5.QtWidgets import * -from electrum.i18n import _ +from electrum_xzc.i18n import _ from .util import * import re import math -from electrum.plugins import run_hook +from electrum_xzc.plugins import run_hook def check_password_strength(password): @@ -57,7 +57,7 @@ class PasswordLayout(object): titles = [_("Enter Password"), _("Change Password"), _("Enter Passphrase")] - def __init__(self, wallet, msg, kind, OK_button, force_disable_encrypt_cb=False): + def __init__(self, wallet, msg, kind, OK_button): self.wallet = wallet self.pw = QLineEdit() @@ -126,8 +126,7 @@ def __init__(self, wallet, msg, kind, OK_button, force_disable_encrypt_cb=False) def enable_OK(): ok = self.new_pw.text() == self.conf_pw.text() OK_button.setEnabled(ok) - self.encrypt_cb.setEnabled(ok and bool(self.new_pw.text()) - and not force_disable_encrypt_cb) + self.encrypt_cb.setEnabled(ok and bool(self.new_pw.text())) self.new_pw.textChanged.connect(enable_OK) self.conf_pw.textChanged.connect(enable_OK) @@ -164,96 +163,28 @@ def new_password(self): return pw -class PasswordLayoutForHW(object): - - def __init__(self, wallet, msg, kind, OK_button): - self.wallet = wallet - - self.kind = kind - self.OK_button = OK_button - - vbox = QVBoxLayout() - label = QLabel(msg + "\n") - label.setWordWrap(True) - - grid = QGridLayout() - grid.setSpacing(8) - grid.setColumnMinimumWidth(0, 150) - grid.setColumnMinimumWidth(1, 100) - grid.setColumnStretch(1,1) - - logo_grid = QGridLayout() - logo_grid.setSpacing(8) - logo_grid.setColumnMinimumWidth(0, 70) - logo_grid.setColumnStretch(1,1) - - logo = QLabel() - logo.setAlignment(Qt.AlignCenter) - - logo_grid.addWidget(logo, 0, 0) - logo_grid.addWidget(label, 0, 1, 1, 2) - vbox.addLayout(logo_grid) - - if wallet and wallet.has_storage_encryption(): - lockfile = ":icons/lock.png" - else: - lockfile = ":icons/unlock.png" - logo.setPixmap(QPixmap(lockfile).scaledToWidth(36)) - - vbox.addLayout(grid) - - self.encrypt_cb = QCheckBox(_('Encrypt wallet file')) - grid.addWidget(self.encrypt_cb, 1, 0, 1, 2) - - self.vbox = vbox - - def title(self): - return _("Toggle Encryption") - - def layout(self): - return self.vbox - - -class ChangePasswordDialogBase(WindowModalDialog): +class ChangePasswordDialog(WindowModalDialog): def __init__(self, parent, wallet): WindowModalDialog.__init__(self, parent) - is_encrypted = wallet.has_storage_encryption() - OK_button = OkButton(self) - - self.create_password_layout(wallet, is_encrypted, OK_button) - - self.setWindowTitle(self.playout.title()) - vbox = QVBoxLayout(self) - vbox.addLayout(self.playout.layout()) - vbox.addStretch(1) - vbox.addLayout(Buttons(CancelButton(self), OK_button)) - self.playout.encrypt_cb.setChecked(is_encrypted) - - def create_password_layout(self, wallet, is_encrypted, OK_button): - raise NotImplementedError() - - -class ChangePasswordDialogForSW(ChangePasswordDialogBase): - - def __init__(self, parent, wallet): - ChangePasswordDialogBase.__init__(self, parent, wallet) - if not wallet.has_password(): - self.playout.encrypt_cb.setChecked(True) - - def create_password_layout(self, wallet, is_encrypted, OK_button): + is_encrypted = wallet.storage.is_encrypted() if not wallet.has_password(): msg = _('Your wallet is not protected.') msg += ' ' + _('Use this dialog to add a password to your wallet.') else: if not is_encrypted: - msg = _('Your bitcoins are password protected. However, your wallet file is not encrypted.') + msg = _('Your zcoins are password protected. However, your wallet file is not encrypted.') else: msg = _('Your wallet is password protected and encrypted.') msg += ' ' + _('Use this dialog to change your password.') - self.playout = PasswordLayout( - wallet, msg, PW_CHANGE, OK_button, - force_disable_encrypt_cb=not wallet.can_have_keystore_encryption()) + OK_button = OkButton(self) + self.playout = PasswordLayout(wallet, msg, PW_CHANGE, OK_button) + self.setWindowTitle(self.playout.title()) + vbox = QVBoxLayout(self) + vbox.addLayout(self.playout.layout()) + vbox.addStretch(1) + vbox.addLayout(Buttons(CancelButton(self), OK_button)) + self.playout.encrypt_cb.setChecked(is_encrypted or not wallet.has_password()) def run(self): if not self.exec_(): @@ -261,26 +192,6 @@ def run(self): return True, self.playout.old_password(), self.playout.new_password(), self.playout.encrypt_cb.isChecked() -class ChangePasswordDialogForHW(ChangePasswordDialogBase): - - def __init__(self, parent, wallet): - ChangePasswordDialogBase.__init__(self, parent, wallet) - - def create_password_layout(self, wallet, is_encrypted, OK_button): - if not is_encrypted: - msg = _('Your wallet file is NOT encrypted.') - else: - msg = _('Your wallet file is encrypted.') - msg += '\n' + _('Note: If you enable this setting, you will need your hardware device to open your wallet.') - msg += '\n' + _('Use this dialog to toggle encryption.') - self.playout = PasswordLayoutForHW(wallet, msg, PW_CHANGE, OK_button) - - def run(self): - if not self.exec_(): - return False, None - return True, self.playout.encrypt_cb.isChecked() - - class PasswordDialog(WindowModalDialog): def __init__(self, parent=None, msg=None): diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py index d13d80390145..31d7d9ab7695 100644 --- a/gui/qt/paytoedit.py +++ b/gui/qt/paytoedit.py @@ -30,7 +30,7 @@ import re from decimal import Decimal -from electrum import bitcoin +from electrum_xzc import bitcoin from . import util @@ -88,7 +88,7 @@ def parse_output(self, x): return bitcoin.TYPE_SCRIPT, script def parse_script(self, x): - from electrum.transaction import opcodes, push_script + from electrum_xzc.transaction import opcodes, push_script script = '' for word in x.split(): if word[0:3] == 'OP_': @@ -122,7 +122,7 @@ def check_text(self): self.payto_address = None if len(lines) == 1: data = lines[0] - if data.startswith("bitcoin:"): + if data.startswith("zcoin:"): self.scan_f(data) return try: @@ -260,7 +260,7 @@ def keyPressEvent(self, e): def qr_input(self): data = super(PayToEdit,self).qr_input() - if data.startswith("bitcoin:"): + if data.startswith("zcoin:"): self.scan_f(data) # TODO: update fee diff --git a/gui/qt/qrcodewidget.py b/gui/qt/qrcodewidget.py index dc444d6a5fd3..453a329e0d60 100644 --- a/gui/qt/qrcodewidget.py +++ b/gui/qt/qrcodewidget.py @@ -8,8 +8,8 @@ import os import qrcode -import electrum -from electrum.i18n import _ +import electrum_xzc +from electrum_xzc.i18n import _ from .util import WindowModalDialog @@ -102,7 +102,7 @@ def __init__(self, data, parent=None, title = "", show_text=False): hbox = QHBoxLayout() hbox.addStretch(1) - config = electrum.get_config() + config = electrum_xzc.get_config() if config: filename = os.path.join(config.path, "qrcode.png") diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py index aef68f0539ae..78cdce118a4f 100644 --- a/gui/qt/qrtextedit.py +++ b/gui/qt/qrtextedit.py @@ -1,6 +1,6 @@ -from electrum.i18n import _ -from electrum.plugins import run_hook +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import run_hook from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import QFileDialog @@ -51,7 +51,7 @@ def file_input(self): self.setText(data) def qr_input(self): - from electrum import qrscanner, get_config + from electrum_xzc import qrscanner, get_config try: data = qrscanner.scan_barcode(get_config().get_video_device()) except BaseException as e: diff --git a/gui/qt/qrwindow.py b/gui/qt/qrwindow.py index 163c462cc208..ac39e5f5c5a4 100644 --- a/gui/qt/qrwindow.py +++ b/gui/qt/qrwindow.py @@ -29,8 +29,8 @@ from PyQt5.QtGui import * from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QWidget -from electrum_gui.qt.qrcodewidget import QRCodeWidget -from electrum.i18n import _ +from electrum_xzc_gui.qt.qrcodewidget import QRCodeWidget +from electrum_xzc.i18n import _ if platform.system() == 'Windows': MONOSPACE_FONT = 'Lucida Console' @@ -46,7 +46,7 @@ class QR_Window(QWidget): def __init__(self, win): QWidget.__init__(self) self.win = win - self.setWindowTitle('Electrum - '+_('Payment Request')) + self.setWindowTitle('Electrum-XZC - '+_('Payment Request')) self.setMinimumSize(800, 250) self.address = '' self.label = '' diff --git a/gui/qt/request_list.py b/gui/qt/request_list.py index 59b084ff9583..4e2ae27c1a31 100644 --- a/gui/qt/request_list.py +++ b/gui/qt/request_list.py @@ -23,10 +23,10 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from electrum.i18n import _ -from electrum.util import format_time, age -from electrum.plugins import run_hook -from electrum.paymentrequest import PR_UNKNOWN +from electrum_xzc.i18n import _ +from electrum_xzc.util import format_time, age +from electrum_xzc.plugins import run_hook +from electrum_xzc.paymentrequest import PR_UNKNOWN from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import QTreeWidgetItem, QMenu @@ -115,7 +115,7 @@ def create_menu(self, position): column_title = self.headerItem().text(column) column_data = item.text(column) menu = QMenu(self) - menu.addAction(_("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) + menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data)) menu.addAction(_("Copy URI"), lambda: self.parent.view_and_paste('URI', '', self.parent.get_request_URI(addr))) menu.addAction(_("Save as BIP70 file"), lambda: self.parent.export_payment_request(addr)) menu.addAction(_("Delete"), lambda: self.parent.delete_payment_request(addr)) diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py index 09e20cef8935..fba21c827686 100644 --- a/gui/qt/seed_dialog.py +++ b/gui/qt/seed_dialog.py @@ -26,7 +26,7 @@ from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * -from electrum.i18n import _ +from electrum_xzc.i18n import _ from .util import * from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit @@ -136,14 +136,14 @@ def get_seed(self): return ' '.join(text.split()) def on_edit(self): - from electrum.bitcoin import seed_type + from electrum_xzc.bitcoin import seed_type s = self.get_seed() b = self.is_seed(s) if not self.is_bip39: t = seed_type(s) label = _('Seed Type') + ': ' + t if t else '' else: - from electrum.keystore import bip39_is_checksum_valid + from electrum_xzc.keystore import bip39_is_checksum_valid is_checksum, is_wordlist = bip39_is_checksum_valid(s) status = ('checksum: ' + ('ok' if is_checksum else 'failed')) if is_wordlist else 'unknown wordlist' label = 'BIP39' + ' (%s)'%status @@ -172,7 +172,7 @@ def on_edit(self): class SeedDialog(WindowModalDialog): def __init__(self, parent, seed, passphrase): - WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed'))) + WindowModalDialog.__init__(self, parent, ('Electrum-XZC - ' + _('Seed'))) self.setMinimumWidth(400) vbox = QVBoxLayout(self) title = _("Your wallet generation seed is:") diff --git a/gui/qt/transaction_dialog.py b/gui/qt/transaction_dialog.py index 5097af28a047..e584f3c978bb 100644 --- a/gui/qt/transaction_dialog.py +++ b/gui/qt/transaction_dialog.py @@ -30,12 +30,12 @@ from PyQt5.QtGui import * from PyQt5.QtWidgets import * -from electrum.bitcoin import base_encode -from electrum.i18n import _ -from electrum.plugins import run_hook +from electrum_xzc.bitcoin import base_encode +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import run_hook -from electrum.util import bfh -from electrum.wallet import UnrelatedTransactionException +from electrum_xzc.util import bfh +from electrum_xzc.wallet import UnrelatedTransactionException from .util import * @@ -179,13 +179,10 @@ def sign_done(success): self.main_window.sign_tx(self.tx, sign_done) def save(self): - if not self.wallet.add_transaction(self.tx.txid(), self.tx): - self.show_error(_("Transaction could not be saved. It conflicts with current history.")) - return + self.wallet.add_transaction(self.tx.txid(), self.tx) self.wallet.save_transactions(write=True) - # need to update at least: history_list, utxo_list, address_list - self.main_window.need_update.set() + self.main_window.history_list.update() self.save_button.setDisabled(True) self.show_message(_("Transaction saved successfully")) @@ -221,11 +218,11 @@ def update(self): if timestamp: time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] - self.date_label.setText(_("Date: {}").format(time_str)) + self.date_label.setText(_("Date: %s")%time_str) self.date_label.show() elif exp_n: - text = '%.2f MB'%(exp_n/1000000) - self.date_label.setText(_('Position in mempool') + ': ' + text + ' ' + _('from tip')) + text = '%d blocks'%(exp_n) if exp_n > 0 else _('unknown (low fee)') + self.date_label.setText(_('Expected confirmation time') + ': ' + text) self.date_label.show() else: self.date_label.hide() diff --git a/gui/qt/util.py b/gui/qt/util.py index c0bdf62e8300..aba16e0e7907 100644 --- a/gui/qt/util.py +++ b/gui/qt/util.py @@ -6,7 +6,7 @@ from collections import namedtuple from functools import partial -from electrum.i18n import _ +from electrum_xzc.i18n import _ from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * @@ -21,7 +21,7 @@ dialogs = [] -from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED +from electrum_xzc.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED pr_icons = { PR_UNPAID:":icons/unpaid.png", @@ -389,9 +389,7 @@ def __init__(self, parent, create_menu, headers, stretch_column=None, self.editor = None self.pending_update = False if editable_columns is None: - editable_columns = {stretch_column} - else: - editable_columns = set(editable_columns) + editable_columns = [stretch_column] self.editable_columns = editable_columns self.setItemDelegate(ElectrumItemDelegate(self)) self.itemDoubleClicked.connect(self.on_doubleclick) @@ -480,12 +478,8 @@ def update(self): self.pending_update = True else: self.setUpdatesEnabled(False) - scroll_pos = self.verticalScrollBar().value() self.on_update() self.setUpdatesEnabled(True) - # To paint the list before resetting the scroll position - self.parent.app.processEvents() - self.verticalScrollBar().setValue(scroll_pos) if self.current_filter: self.filter(self.current_filter) diff --git a/gui/qt/utxo_list.py b/gui/qt/utxo_list.py index 40f9fa208e22..168e9edc01b3 100644 --- a/gui/qt/utxo_list.py +++ b/gui/qt/utxo_list.py @@ -23,7 +23,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from .util import * -from electrum.i18n import _ +from electrum_xzc.i18n import _ class UTXOList(MyTreeWidget): diff --git a/gui/stdio.py b/gui/stdio.py index 4b0daa156b5b..f86d91db1f20 100644 --- a/gui/stdio.py +++ b/gui/stdio.py @@ -1,9 +1,9 @@ from decimal import Decimal _ = lambda x:x #from i18n import _ -from electrum import WalletStorage, Wallet -from electrum.util import format_satoshis, set_verbosity -from electrum.bitcoin import is_address, COIN, TYPE_ADDRESS +from electrum_xzc import WalletStorage, Wallet +from electrum_xzc.util import format_satoshis, set_verbosity +from electrum_xzc.bitcoin import is_address, COIN, TYPE_ADDRESS import getpass, datetime # minimal fdisk like gui for console usage @@ -16,7 +16,7 @@ def __init__(self, config, daemon, plugins): self.network = daemon.network storage = WalletStorage(config.get_wallet_path()) if not storage.file_exists: - print("Wallet not found. try 'electrum create'") + print("Wallet not found. try 'electrum-xzc create'") exit() if storage.is_encrypted(): password = getpass.getpass('Password:', stream=None) @@ -163,7 +163,7 @@ def main(self): def do_send(self): if not is_address(self.str_recipient): - print(_('Invalid Bitcoin address')) + print(_('Invalid Zcoin address')) return try: amount = int(Decimal(self.str_amount) * COIN) @@ -208,12 +208,12 @@ def do_send(self): print(_('Error')) def network_dialog(self): - print("use 'electrum setconfig server/proxy' to change your network settings") + print("use 'electrum-xzc setconfig server/proxy' to change your network settings") return True def settings_dialog(self): - print("use 'electrum setconfig' to change your settings") + print("use 'electrum-xzc setconfig' to change your settings") return True def password_dialog(self): diff --git a/gui/text.py b/gui/text.py index 9ecf91affaaa..01b173c4b3d7 100644 --- a/gui/text.py +++ b/gui/text.py @@ -3,10 +3,10 @@ from decimal import Decimal import getpass -import electrum -from electrum.util import format_satoshis, set_verbosity -from electrum.bitcoin import is_address, COIN, TYPE_ADDRESS -from electrum import Wallet, WalletStorage +import electrum_xzc as electrum +from electrum_xzc.util import format_satoshis, set_verbosity +from electrum_xzc.bitcoin import is_address, COIN, TYPE_ADDRESS +from electrum_xzc import Wallet, WalletStorage _ = lambda x:x @@ -20,7 +20,7 @@ def __init__(self, config, daemon, plugins): self.network = daemon.network storage = WalletStorage(config.get_wallet_path()) if not storage.file_exists(): - print("Wallet not found. try 'electrum create'") + print("Wallet not found. try 'electrum-xzc create'") exit() if storage.is_encrypted(): password = getpass.getpass('Password:', stream=None) @@ -320,7 +320,7 @@ def do_clear(self): def do_send(self): if not is_address(self.str_recipient): - self.show_message(_('Invalid Bitcoin address')) + self.show_message(_('Invalid Zcoin address')) return try: amount = int(Decimal(self.str_amount) * COIN) diff --git a/icons.qrc b/icons.qrc index 195e9af9dd7f..ab55d88927aa 100644 --- a/icons.qrc +++ b/icons.qrc @@ -1,6 +1,6 @@ - icons/electrum.png + icons/electrum-xzc.png icons/clock1.png icons/clock2.png icons/clock3.png diff --git a/icons/electrum-xzc.png b/icons/electrum-xzc.png new file mode 100644 index 000000000000..333a7bd7fbbd Binary files /dev/null and b/icons/electrum-xzc.png differ diff --git a/icons/electrum.ico b/icons/electrum.ico index 618bc99e2aae..269bd7bb4bdf 100644 Binary files a/icons/electrum.ico and b/icons/electrum.ico differ diff --git a/icons/electrum_dark_icon.png b/icons/electrum_dark_icon.png index 6fee7de9f74c..94d1b34127f6 100644 Binary files a/icons/electrum_dark_icon.png and b/icons/electrum_dark_icon.png differ diff --git a/icons/electrum_launcher.png b/icons/electrum_launcher.png index 37af81ca9f9b..85339b0974ad 100644 Binary files a/icons/electrum_launcher.png and b/icons/electrum_launcher.png differ diff --git a/icons/electrum_light_icon.png b/icons/electrum_light_icon.png index da52cb3c17b0..8db10687592f 100644 Binary files a/icons/electrum_light_icon.png and b/icons/electrum_light_icon.png differ diff --git a/icons/electrum_presplash.png b/icons/electrum_presplash.png index 8d7b414db8b0..291d640de1e4 100644 Binary files a/icons/electrum_presplash.png and b/icons/electrum_presplash.png differ diff --git a/lib/base_wizard.py b/lib/base_wizard.py index ab18b7617a60..209f0e6aa070 100644 --- a/lib/base_wizard.py +++ b/lib/base_wizard.py @@ -24,19 +24,12 @@ # SOFTWARE. import os -import sys -import traceback - from . import bitcoin from . import keystore from .keystore import bip44_derivation from .wallet import Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types -from .storage import STO_EV_USER_PW, STO_EV_XPUB_PW, get_derivation_used_for_hw_device_encryption from .i18n import _ -from .util import UserCancelled -# hardware device setup purpose -HWD_SETUP_NEW_WALLET, HWD_SETUP_DECRYPT_WALLET = range(0, 2) class ScriptTypeNotSupported(Exception): pass @@ -91,7 +84,7 @@ def new(self): ('standard', _("Standard wallet")), ('2fa', _("Wallet with two-factor authentication")), ('multisig', _("Multi-signature wallet")), - ('imported', _("Import Bitcoin addresses or private keys")), + ('imported', _("Import Zcoin addresses or private keys")), ] choices = [pair for pair in wallet_kinds if pair[0] in wallet_types] self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type) @@ -148,28 +141,23 @@ def choose_keystore(self): def import_addresses_or_keys(self): v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x) - title = _("Import Bitcoin Addresses") - message = _("Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.") + title = _("Import Zcoin Addresses") + message = _("Enter a list of Zcoin addresses (this will create a watching-only wallet), or a list of private keys.") self.add_xpub_dialog(title=title, message=message, run_next=self.on_import, is_valid=v, allow_multi=True) def on_import(self, text): - # create a temporary wallet and exploit that modifications - # will be reflected on self.storage if keystore.is_address_list(text): - w = Imported_Wallet(self.storage) + self.wallet = Imported_Wallet(self.storage) for x in text.split(): - w.import_address(x) + self.wallet.import_address(x) elif keystore.is_private_key_list(text): k = keystore.Imported_KeyStore({}) self.storage.put('keystore', k.dump()) - w = Imported_Wallet(self.storage) + self.wallet = Imported_Wallet(self.storage) for x in text.split(): - w.import_private_key(x, None) - self.keystores.append(w.keystore) - else: - return self.terminate() - return self.run('create_wallet') + self.wallet.import_private_key(x, None) + self.terminate() def restore_from_key(self): if self.wallet_type == 'standard': @@ -188,7 +176,7 @@ def on_restore_from_key(self, text): k = keystore.from_master_key(text) self.on_keystore(k) - def choose_hw_device(self, purpose=HWD_SETUP_NEW_WALLET): + def choose_hw_device(self): title = _('Hardware Keystore') # check available plugins support = self.plugins.get_hardware_support() @@ -197,7 +185,7 @@ def choose_hw_device(self, purpose=HWD_SETUP_NEW_WALLET): _('No hardware wallet support found on your system.'), _('Please install the relevant libraries (eg python-trezor for Trezor).'), ]) - self.confirm_dialog(title=title, message=msg, run_next= lambda x: self.choose_hw_device(purpose)) + self.confirm_dialog(title=title, message=msg, run_next= lambda x: self.choose_hw_device()) return # scan devices devices = [] @@ -217,51 +205,34 @@ def choose_hw_device(self, purpose=HWD_SETUP_NEW_WALLET): _('If your device is not detected on Windows, go to "Settings", "Devices", "Connected devices", and do "Remove device". Then, plug your device again.') + ' ', _('On Linux, you might have to add a new permission to your udev rules.'), ]) - self.confirm_dialog(title=title, message=msg, run_next= lambda x: self.choose_hw_device(purpose)) + self.confirm_dialog(title=title, message=msg, run_next= lambda x: self.choose_hw_device()) return # select device self.devices = devices choices = [] for name, info in devices: state = _("initialized") if info.initialized else _("wiped") - label = info.label or _("An unnamed {}").format(name) + label = info.label or _("An unnamed %s")%name descr = "%s [%s, %s]" % (label, name, state) choices.append(((name, info), descr)) msg = _('Select a device') + ':' - self.choice_dialog(title=title, message=msg, choices=choices, run_next= lambda *args: self.on_device(*args, purpose=purpose)) + self.choice_dialog(title=title, message=msg, choices=choices, run_next=self.on_device) - def on_device(self, name, device_info, *, purpose): + def on_device(self, name, device_info): self.plugin = self.plugins.get_plugin(name) try: - self.plugin.setup_device(device_info, self, purpose) - except OSError as e: - self.show_error(_('We encountered an error while connecting to your device:') - + '\n' + str(e) + '\n' - + _('To try to fix this, we will now re-pair with your device.') + '\n' - + _('Please try again.')) - devmgr = self.plugins.device_manager - devmgr.unpair_id(device_info.device.id_) - self.choose_hw_device(purpose) - return + self.plugin.setup_device(device_info, self) except BaseException as e: self.show_error(str(e)) - self.choose_hw_device(purpose) + self.choose_hw_device() return - if purpose == HWD_SETUP_NEW_WALLET: - if self.wallet_type=='multisig': - # There is no general standard for HD multisig. - # This is partially compatible with BIP45; assumes index=0 - self.on_hw_derivation(name, device_info, "m/45'/0") - else: - f = lambda x: self.run('on_hw_derivation', name, device_info, str(x)) - self.derivation_dialog(f) - elif purpose == HWD_SETUP_DECRYPT_WALLET: - derivation = get_derivation_used_for_hw_device_encryption() - xpub = self.plugin.get_xpub(device_info.device.id_, derivation, 'standard', self) - password = keystore.Xpub.get_pubkey_from_xpub(xpub, ()) - self.storage.decrypt(password) + if self.wallet_type=='multisig': + # There is no general standard for HD multisig. + # This is partially compatible with BIP45; assumes index=0 + self.on_hw_derivation(name, device_info, "m/45'/0") else: - raise Exception('unknown purpose: %s' % purpose) + f = lambda x: self.run('on_hw_derivation', name, device_info, str(x)) + self.derivation_dialog(f) def derivation_dialog(self, f): default = bip44_derivation(0, bip43_purpose=44) @@ -394,45 +365,13 @@ def on_keystore(self, k): self.run('create_wallet') def create_wallet(self): - encrypt_keystore = any(k.may_have_password() for k in self.keystores) - # note: the following condition ("if") is duplicated logic from - # wallet.get_available_storage_encryption_version() - if self.wallet_type == 'standard' and isinstance(self.keystores[0], keystore.Hardware_KeyStore): - # offer encrypting with a pw derived from the hw device - k = self.keystores[0] - try: - k.handler = self.plugin.create_handler(self) - password = k.get_password_for_storage_encryption() - except UserCancelled: - devmgr = self.plugins.device_manager - devmgr.unpair_xpub(k.xpub) - self.choose_hw_device() - return - except BaseException as e: - traceback.print_exc(file=sys.stderr) - self.show_error(str(e)) - return - self.request_storage_encryption( - run_next=lambda encrypt_storage: self.on_password( - password, - encrypt_storage=encrypt_storage, - storage_enc_version=STO_EV_XPUB_PW, - encrypt_keystore=False)) + if any(k.may_have_password() for k in self.keystores): + self.request_password(run_next=self.on_password) else: - # prompt the user to set an arbitrary password - self.request_password( - run_next=lambda password, encrypt_storage: self.on_password( - password, - encrypt_storage=encrypt_storage, - storage_enc_version=STO_EV_USER_PW, - encrypt_keystore=encrypt_keystore), - force_disable_encrypt_cb=not encrypt_keystore) - - def on_password(self, password, *, encrypt_storage, - storage_enc_version=STO_EV_USER_PW, encrypt_keystore): - self.storage.set_keystore_encryption(bool(password) and encrypt_keystore) - if encrypt_storage: - self.storage.set_password(password, enc_version=storage_enc_version) + self.on_password(None, False) + + def on_password(self, password, encrypt): + self.storage.set_password(password, encrypt) for k in self.keystores: if k.may_have_password(): k.update_password(None, password) @@ -448,13 +387,6 @@ def on_password(self, password, *, encrypt_storage, self.storage.write() self.wallet = Multisig_Wallet(self.storage) self.run('create_addresses') - elif self.wallet_type == 'imported': - if len(self.keystores) > 0: - keys = self.keystores[0].dump() - self.storage.put('keystore', keys) - self.wallet = Imported_Wallet(self.storage) - self.wallet.storage.write() - self.terminate() def show_xpub_and_add_cosigners(self, xpub): self.show_xpub_dialog(xpub=xpub, run_next=lambda x: self.run('choose_keystore')) @@ -469,7 +401,7 @@ def choose_seed_type(self): _("The type of addresses used by your wallet will depend on your seed."), _("Segwit wallets use bech32 addresses, defined in BIP173."), _("Please note that websites and other wallets may not support these addresses yet."), - _("Thus, you might want to keep using a non-segwit wallet in order to be able to receive bitcoins during the transition period.") + _("Thus, you might want to keep using a non-segwit wallet in order to be able to receive zcoins during the transition period.") ]) choices = [ ('create_standard_seed', _('Standard')), diff --git a/lib/bitcoin.py b/lib/bitcoin.py index 84339755986f..a944b728013e 100644 --- a/lib/bitcoin.py +++ b/lib/bitcoin.py @@ -68,6 +68,21 @@ def read_json(filename, default): 'p2wsh': 0x2aa7ed3 } +# class Zcoin(Coin): +# NAME = "Zcoin" +# SHORTNAME = "XZC" +# NET = "mainnet" +# P2PKH_VERBYTE = bytes.fromhex("52") +# P2SH_VERBYTES = [bytes.fromhex("07")] +# WIF_BYTE = bytes.fromhex("d2") +# GENESIS_HASH = ('4381deb85b1b2c9843c222944b616d99' +# '7516dcbd6a964e1eaf0def0830695233') +# TX_COUNT = 1 +# TX_COUNT_HEIGHT = 1 +# TX_PER_BLOCK = 1 +# IRC_PREFIX = None +# RPC_PORT = 8888 +# REORG_LIMIT = 5000 class NetworkConstants: @@ -75,10 +90,10 @@ class NetworkConstants: def set_mainnet(cls): cls.TESTNET = False cls.WIF_PREFIX = 0x80 - cls.ADDRTYPE_P2PKH = 0 - cls.ADDRTYPE_P2SH = 5 - cls.SEGWIT_HRP = "bc" - cls.GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" + cls.ADDRTYPE_P2PKH = 82 # 0x52 + cls.ADDRTYPE_P2SH = 7 # 0x07 + cls.SEGWIT_HRP = "xzc" + cls.GENESIS = "4381deb85b1b2c9843c222944b616d997516dcbd6a964e1eaf0def0830695233" cls.DEFAULT_PORTS = {'t': '50001', 's': '50002'} cls.DEFAULT_SERVERS = read_json('servers.json', {}) cls.CHECKPOINTS = read_json('checkpoints.json', []) @@ -86,11 +101,11 @@ def set_mainnet(cls): @classmethod def set_testnet(cls): cls.TESTNET = True - cls.WIF_PREFIX = 0xef + cls.WIF_PREFIX = 0xbf cls.ADDRTYPE_P2PKH = 111 - cls.ADDRTYPE_P2SH = 196 - cls.SEGWIT_HRP = "tb" - cls.GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + cls.ADDRTYPE_P2SH = 58 + cls.SEGWIT_HRP = "txzc" + cls.GENESIS = "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0" cls.DEFAULT_PORTS = {'t':'51001', 's':'51002'} cls.DEFAULT_SERVERS = read_json('servers_testnet.json', {}) cls.CHECKPOINTS = read_json('checkpoints_testnet.json', []) @@ -100,9 +115,9 @@ def set_testnet(cls): ################################## transactions -FEE_STEP = 10000 -MAX_FEE_RATE = 300000 - +FEE_STEP = 100000 +MAX_FEE_RATE = 1000000 +FEE_TARGETS = [25, 10, 5, 2] COINBASE_MATURITY = 100 COIN = 100000000 @@ -512,10 +527,10 @@ def DecodeBase58Check(psz): # extended key export format for segwit SCRIPT_TYPES = { - 'p2pkh':0, + 'p2pkh':82, 'p2wpkh':1, 'p2wpkh-p2sh':2, - 'p2sh':5, + 'p2sh':7, 'p2wsh':6, 'p2wsh-p2sh':7 } @@ -619,7 +634,7 @@ def minikey_to_private_key(text): def msg_magic(message): length = bfh(var_int(len(message))) - return b"\x18Bitcoin Signed Message:\n" + length + message + return b"\x19Zcoin Signed Message:\n" + length + message def verify_message(address, sig, message): @@ -643,8 +658,8 @@ def verify_message(address, sig, message): return False -def encrypt_message(message, pubkey, magic=b'BIE1'): - return EC_KEY.encrypt_message(message, bfh(pubkey), magic) +def encrypt_message(message, pubkey): + return EC_KEY.encrypt_message(message, bfh(pubkey)) def chunks(l, n): @@ -789,7 +804,7 @@ def verify_message(self, sig, message): # ECIES encryption/decryption methods; AES-128-CBC with PKCS7 is used as the cipher; hmac-sha256 is used as the mac @classmethod - def encrypt_message(self, message, pubkey, magic=b'BIE1'): + def encrypt_message(self, message, pubkey): assert_bytes(message) pk = ser_to_point(pubkey) @@ -803,20 +818,20 @@ def encrypt_message(self, message, pubkey, magic=b'BIE1'): iv, key_e, key_m = key[0:16], key[16:32], key[32:] ciphertext = aes_encrypt_with_iv(key_e, iv, message) ephemeral_pubkey = bfh(ephemeral.get_public_key(compressed=True)) - encrypted = magic + ephemeral_pubkey + ciphertext + encrypted = b'BIE1' + ephemeral_pubkey + ciphertext mac = hmac.new(key_m, encrypted, hashlib.sha256).digest() return base64.b64encode(encrypted + mac) - def decrypt_message(self, encrypted, magic=b'BIE1'): + def decrypt_message(self, encrypted): encrypted = base64.b64decode(encrypted) if len(encrypted) < 85: raise Exception('invalid ciphertext: length') - magic_found = encrypted[:4] + magic = encrypted[:4] ephemeral_pubkey = encrypted[4:37] ciphertext = encrypted[37:-32] mac = encrypted[-32:] - if magic_found != magic: + if magic != b'BIE1': raise Exception('invalid ciphertext: invalid magic bytes') try: ephemeral_pubkey = ser_to_point(ephemeral_pubkey) diff --git a/lib/blockchain.py b/lib/blockchain.py index 8a69276f3d1f..65ba152c481b 100644 --- a/lib/blockchain.py +++ b/lib/blockchain.py @@ -26,8 +26,19 @@ from . import util from . import bitcoin from .bitcoin import * +import lyra2z_hash -MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 +try: + import scrypt + getPoWHash = lambda x: scrypt.hash(x, x, N=1024, r=1, p=1, buflen=32) +except ImportError: + util.print_msg("Warning: package scrypt not available; synchronization could be very slow") + from .scrypt import scrypt_1024_1_1_80 as getPoWHash + +MAX_TARGET = 0x00000FFFFF000000000000000000000000000000000000000000000000000000 +HF_LYRA2VAR_HEIGHT = 500 +HF_LYRA2_HEIGHT = 8192 +HF_LYRA2Z_HEIGHT = 20500 def serialize_header(res): s = int_to_hex(res.get('version'), 4) \ @@ -57,6 +68,34 @@ def hash_header(header): header['prev_block_hash'] = '00'*32 return hash_encode(Hash(bfh(serialize_header(header)))) +def pow_hash_header(header): + # return hash_encode(getPoWHash(bfh(serialize_header(header)))) + # if (!fTestNet & & nHeight >= HF_LYRA2Z_HEIGHT) { + # lyra2z_hash(BEGIN(nVersion), BEGIN(powHash)); + # } else if (!fTestNet & & nHeight >= HF_LYRA2_HEIGHT) { + # LYRA2(BEGIN(powHash), 32, BEGIN(nVersion), 80, BEGIN(nVersion), 80, 2, 8192, 256); + # } else if (!fTestNet & & nHeight >= HF_LYRA2VAR_HEIGHT) { + # LYRA2(BEGIN(powHash), 32, BEGIN(nVersion), 80, BEGIN(nVersion), 80, 2, nHeight, 256); + # } else if (fTestNet & & nHeight >= HF_LYRA2Z_HEIGHT_TESTNET) {// testnet + # lyra2z_hash(BEGIN(nVersion), BEGIN(powHash)); + # } else if (fTestNet & & nHeight >= HF_LYRA2_HEIGHT_TESTNET) {// testnet + # LYRA2(BEGIN(powHash), 32, BEGIN(nVersion), 80, BEGIN(nVersion), 80, 2, 8192, 256); + # } else if (fTestNet & & nHeight >= HF_LYRA2VAR_HEIGHT_TESTNET) {// testnet + # LYRA2(BEGIN(powHash), 32, BEGIN(nVersion), 80, BEGIN(nVersion), 80, 2, nHeight, 256); + # } else { + # scrypt_N_1_1_256(BEGIN(nVersion), BEGIN(powHash), GetNfactor(nTime)); + # } + try: + height = header.get('block_height') + if height >= HF_LYRA2Z_HEIGHT: + return hash_encode(lyra2z_hash.getPoWHash(bfh(serialize_header(header)))) + elif height >= HF_LYRA2_HEIGHT: + return hash_encode(lyra2z_hash.getPoWHash(bfh(serialize_header(header)))) + else: + return hash_encode(lyra2z_hash.getPoWHash(bfh(serialize_header(header)))) + except Exception as e: + print_error(e) + blockchains = {} @@ -149,16 +188,21 @@ def update_size(self): self._size = os.path.getsize(p)//80 if os.path.exists(p) else 0 def verify_header(self, header, prev_hash, target): + return _hash = hash_header(header) + _powhash = pow_hash_header(header) if prev_hash != header.get('prev_block_hash'): raise BaseException("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash'))) + if int('0x' + _powhash, 16) > target: + raise BaseException("insufficient proof of work: %s vs target %s" % (int('0x' + _powhash, 16), target)) + return if bitcoin.NetworkConstants.TESTNET: return bits = self.target_to_bits(target) if bits != header.get('bits'): raise BaseException("bits mismatch: %s vs %s" % (bits, header.get('bits'))) - if int('0x' + _hash, 16) > target: - raise BaseException("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target)) + if int('0x' + _powhash, 16) > target: + raise BaseException("insufficient proof of work: %s vs target %s" % (int('0x' + _powhash, 16), target)) def verify_chunk(self, index, data): num = len(data) // 80 @@ -265,27 +309,35 @@ def get_hash(self, height): elif height < len(self.checkpoints) * 2016: assert (height+1) % 2016 == 0, height index = height // 2016 - h, t = self.checkpoints[index] + h, t, _ = self.checkpoints[index] return h else: return hash_header(self.read_header(height)) + def get_timestamp(self, height): + if height < len(self.checkpoints) * 2016 and (height+1) % 2016 == 0: + index = height // 2016 + _, _, ts = self.checkpoints[index] + return ts + return self.read_header(height).get('timestamp') + def get_target(self, index): # compute target from chunk x, used in chunk x+1 if bitcoin.NetworkConstants.TESTNET: return 0 if index == -1: - return MAX_TARGET + return 0x00000FFFF0000000000000000000000000000000000000000000000000000000 if index < len(self.checkpoints): - h, t = self.checkpoints[index] + h, t, _ = self.checkpoints[index] return t # new target - first = self.read_header(index * 2016) + # Zcoin: go back the full period unless it's the first retarget + first_timestamp = self.get_timestamp(index * 2016 - 1 if index > 0 else 0) last = self.read_header(index * 2016 + 2015) bits = last.get('bits') target = self.bits_to_target(bits) - nActualTimespan = last.get('timestamp') - first.get('timestamp') - nTargetTimespan = 14 * 24 * 60 * 60 + nActualTimespan = last.get('timestamp') - first_timestamp + nTargetTimespan = 84 * 60 * 60 nActualTimespan = max(nActualTimespan, nTargetTimespan // 4) nActualTimespan = min(nActualTimespan, nTargetTimespan * 4) new_target = min(MAX_TARGET, (target * nActualTimespan) // nTargetTimespan) @@ -293,8 +345,8 @@ def get_target(self, index): def bits_to_target(self, bits): bitsN = (bits >> 24) & 0xff - if not (bitsN >= 0x03 and bitsN <= 0x1d): - raise BaseException("First part of bits should be in [0x03, 0x1d]") + if not (bitsN >= 0x03 and bitsN <= 0x1e): + raise BaseException("First part of bits should be in [0x03, 0x1e]") bitsBase = bits & 0xffffff if not (bitsBase >= 0x8000 and bitsBase <= 0x7fffff): raise BaseException("Second part of bits should be in [0x8000, 0x7fffff]") @@ -348,5 +400,7 @@ def get_checkpoints(self): for index in range(n): h = self.get_hash((index+1) * 2016 -1) target = self.get_target(index) - cp.append((h, target)) + # Zcoin: also store the timestamp of the last block + tstamp = self.get_timestamp((index+1) * 2016 - 1) + cp.append((h, target, tstamp)) return cp diff --git a/lib/checkpoints.json b/lib/checkpoints.json index 0055895f484d..0637a088a01e 100644 --- a/lib/checkpoints.json +++ b/lib/checkpoints.json @@ -1,990 +1 @@ -[ - [ - "00000000693067b0e6b440bc51450b9f3850561b07f6d3c021c54fbd6abb9763", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000f037ad09d0b05ee66b8c1da83030abaf909d2b1bf519c3c7d2cd3fdf", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000006ce8b5f16fcedde13acbc9641baa1c67734f177d770a4069c06c9de8", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000563298de120522b5ae17da21aaae02eee2d7fcb5be65d9224dbd601c", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000009b0a4b2833b4a0aa61171ee75b8eb301ac45a18713795a72e461a946", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000fa8a7363e8f6fdc88ec55edf264c9c7b31268c26e497a4587c750584", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000008ac55b5cd76a5c176f2457f0e9df5ff1c719d939f1022712b1ba2092", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000007f0c796631f00f542c0b402d638d3518bc208f8c9e5d29d2f169c084", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000ffb062296c9d4eb5f87bbf905d30669d26eab6bced341bd3f1dba5fd", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "0000000074c108842c3ec2252bba62db4050bf0dddfee3ddaa5f847076b8822f", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "0000000067dc2f84a73fbf5d3c70678ce4a1496ef3a62c557bc79cbdd1d49f22", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000dbf06f47c0624262ecb197bccf6bdaaabc2d973708ac401ac8955acc", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000009260fe30ec89ef367122f429dcc59f61735760f2b2288f2e854f04ac", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000f9f1a700898c4e0671af6efd441eaf339ba075a5c5c7b0949473c80b", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "000000005107662c86452e7365f32f8ffdc70d8d87aa6f78630a79f7d77fbfe6", - 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ - "00000000984f962134a7291e3693075ae03e521f0ee33378ec30a334d860034b", - 22791193517536179595645637622052884930882401463536451358196587084939 - ], - [ - "000000005e36047e39452a7beaaa6721048ac408a3e75bb60a8b0008713653ce", - 20657752757787447339704949573503817091559730029795210136290380062967 - ], - [ - "00000000128d789579ffbec00203a371cbb39cee27df35d951fd66e62ed59258", - 20055900442607493419304231885070612388653052033693203212369143515380 - ], - [ - "000000008dde642fb80481bb5e1671cb04c6716de5b7f783aa3388456d5c8a85", - 14823964236757567892443379740509603561300486961438335652879209691748 - ], - [ - "000000008135b689ad1557d4e148a8b9e58e2c4a67240fc87962abb69710231a", - 10665478642773714533594093039651282002301533435475036254747899885223 - ], - [ - "00000000308496ef3e4f9fa542a772df637b4aaf1dcce404424611feacfc09e7", - 7129928201274994723790235748908587989251132236328748923672922318604 - ], - [ - "000000001a2e0c63d7d012003c9173acfd04ccd6372027718979228c461b5ed5", - 5949911830998722926292643443014583571932577723103865087785236463581 - ], - [ - "000000002e0c0ac26ccde91b51ab018576b3a126b413e9f6f787b36637f1b174", - 5905493731356012500002445562241380310188483401887904088185399375735 - ], - [ - "00000000103226f85fe2b68795f087dcec345e523363f18017e60b5c94175355", - 4430144627991408624040948791361640318006240855899368474057439916851 - ], - [ - "000000001ae6f66fd4de47f8d6f357e798943bbfc4f39ebf14b0975fab059173", - 3447600873975070077932488290376750731396138937686397230467460081722 - ], - [ - "000000000a3f22690162744d3bc0b674c92e661a25afb3d2ac8b39b27ac14373", - 2351604930866654632766829472567920383958332390561025111996712740267 - ], - [ - "0000000006dc436c3c515a97446af858c1203a501c85d26c4a30afa380aba4a1", - 2098151743855439919137531366951071713579837678345159724749870973527 - ], - [ - "000000000943fe1680ffcc498ce50790ff8e842a8af2c157664e4fbc1cb7cb46", - 2275792073644785018721128646741518076327875870388847727099387795022 - ], - [ - "000000000847b2144376c1fb057ea1d5a027d5a6004277ed4c72422e93df04e9", - 1622204498754365521718764766072378227544231556364276849425436764228 - ], - [ - "00000000094505954deb1d31382b86d0510fd280a34143400b1856a4d52b4c93", - 1551050141962082184940599235022157265046848054947355206102386866143 - ], - [ - "000000000109272cecb3f7e98ac12cf149fa8a1b2aaab248e1b006b0dc595a3a", - 1389323441362281405504133894690662702230469716601985716313296951861 - ], - [ - "0000000009e6aa0fe39b790625ffeb18a2d6ff5060a5bd14e699e83c54109977", - 1147154217026336014073920869620380692430705543951348139504758384216 - ], - [ - "0000000000d14af55c4eae0121184919baba2deb8bf89c3af6b8e4c4f35c8e4e", - 594008212391331743177258641174232971084553374243271275697110908234 - ], - [ - "0000000003dfbfa2b33707e691ab2ab7cda7503be2c2cce43d1b21cd1cc757fb", - 148501965484106068333659342839523859586884345264449234288706060288 - ], - [ - "0000000000c169d181d66d242901f70d006f3e088c1ae9cacb88b94b8266e9c3", - 110393704409292953137636253955510629068475916699790368077242928142 - ], - [ - "000000000009f7d1439d6a2fc1a456db8e843674275bf0133fc7b43b5f45b96e", - 76555780966028280774274008956877300222068246662708272689770207398 - ], - [ - "000000000011b8a8fad7973548b50f6d4b2ba1690f7487c374e43248c576354f", - 52679970922643127683947083904801524368866887307161543562595547363 - ], - [ - "000000000077e856b6cc475d9cf784119811214c9cac8d7b674ec24faa7c2c0c", - 43246875121342569218488803557695204365585581295709263857216301849 - ], - [ - "00000000004cbb474f2cbf3a65f690efa09804512af3351ba3a0888c806c6625", - 37817522176947171595261355763110820847417850236612020028828535138 - ], - [ - "0000000000235b1ec6656d8e91f3dde3b6ab9ad7e75b332e4da9355ce60d860e", - 29373105354589651513503064535568195122478342070358205617825458296 - ], - [ - "00000000002a153a2c95a8e5493db93086b0e3fe590b636a5871ace57523ef93", - 20444489530085161064085987129079503334049188267661948259198215487 - ], - [ - "00000000000e9550e084908cf91a4e8b74f9f1315d1bc4020709f9e7f261bb18", - 19563851393374294635996921207472450463857223702361327968607284610 - ], - [ - "00000000002c2cfef3bb85b463d3fcd39b73a6d3d5ae11c1e2a8113e3794f28d", - 12545027206560661467344001226069385793869578030934168709550533072 - ], - [ - "00000000000fa92b757ee29674aa97e98a49ba3ad340d2baa94155d71648dfe1", - 8719871918647905191685831001181973300414533694245757905046274783 - ], - [ - "0000000000030571601dbc8e13d00d45004eee6ea8b6ab3cdfb38d2546fee21c", - 5942997561411541711563156602531385577600077786198627208704997014 - ], - [ - "00000000000bb6adef42e63082b20fd2b1dc1b324c51973512a4c31f29a9986e", - 3926018509229572344313816286588613965571477415700629866143917555 - ], - [ - "000000000000765094788a98dbb8adac30d248b7129b59b1441ee2b7ef9e332f", - 3337325505332425700040650320729095537310516946108490809993884103 - ], - [ - "00000000000431a0aa9625f82975709f3c6f4f64d04c559512af051599872084", - 2200422254731939804709388022233205762025354383380152145148334197 - ], - [ - "00000000000292b850b8f8578e6b4d03cbb4a78ada44afbb4d2f80a16490e8f9", - 1861317049673577272902795125376526066826651733332976503154178702 - ], - [ - "0000000000025afe84e27423011af25f777e5a94545dbd00fd04bebe9050f7dd", - 1653210985697702096268217038408538100642620147117674184232799239 - ], - [ - "0000000000000e389cccae2a40437be574fd806909e24136711e7f8bce671d65", - 1462202160246170142640486657710301628879951515428353771159991652 - ], - [ - "0000000000030510bf6bc1649726cf2e6e4010c64a2c8fd3fde5dc92535ca40e", - 1224747759897877506274637367000463834699323352769332185408382770 - ], - [ - "00000000000082648057f14fc835779c6ce46a407bafb2e5c2ac1d20d9f4e822", - 1036993586117576703268996282150397585765576605730719362190807632 - ], - [ - "000000000000f38accd6b22959010471a6d9f159d43bf2a9d4c53c220201254e", - 739430452756642306146040915925451887239493960335784687377022899 - ], - [ - "0000000000004ed7a73133678b5eb883cd8882bf14dfb26c104ae0c3f94cf4ee", - 484980150867459464772730739859302095672636271057575743647282522 - ], - [ - "00000000000037bb3ff4cf649a1757d4028ecc10f893529b4a2214792c981f96", - 353834202080594446847490995785168095798368734611949601937470709 - ], - [ - "0000000000008008f46559fe7f181e9dc0648f213472a1e576e8bf506b88f22f", - 390846686979010943280302753017141998917705716027679590623447523 - ], - [ - "000000000000691d0c2444db713bf6c088844cc95a37cdc55cc269bb0a31d8c8", - 327399809810416473497219170054754564569687652741316499001410264 - ], - [ - "00000000000071153b0afcc64a425f8442c29749610797119e732dd4b723f675", - 291937852278662838074813817696277197987476923260730675453803937 - ], - [ - "000000000000a384acb522e4e5935ad2bc31366ecf1f16f1f11023e967ef033d", - 245829147781851502645710488124949429684812753873220896184598139 - ], - [ - "0000000000002e532093d43e901292121fb7c6583caf2d13b666fe7e194b4a97", - 171262571764606989041741296999128813297927395580615685573053946 - ], - [ - "00000000000033e435c4bbddc7eb255146aa7f18e61a832983af3a9ee5dd144d", - 110439004522135981410957929709803254805947931106765020063637821 - ], - [ - "00000000000028ff4b0bd45f0e3e713f91fa1821d28a276a1a1f32f786662f13", - 61993466854134149454140006024796140857619052825495269156061184 - ], - [ - "0000000000001ef9c75318e116a607af4de68fb4f67c788677ee6779fb5fa0d5", - 47525095027499967685539085016596651791271838150303471592202567 - ], - [ - "0000000000000e6e98694ccb8247aad63aaa1e2bec5a7be14329407e4cea6223", - 30742242324775075538370115437091356458943450412845263377277862 - ], - [ - "000000000000000a2153574b2523a6d1844c3cb82d085e2575846dd8c5d4ebb4", - 19547340168280248765311813293333293631817970001494998481269884 - ], - [ - "00000000000002a92c1b1ffb2a8388979cf30798e312335ae2a1b922927ee83d", - 17248294060755457364687620800167145237577978222086136949668577 - ], - [ - "00000000000004d54b1422ce733922e7672a4e2ecc86dcf96c0de06565cddaa6", - 15943944661534740097945584046599407470739618287604834836788345 - ], - [ - "00000000000009dd91ae96cbbf67af42340b0bc715b3606aa725f630b470262d", - 14273487520109069190865495135324295912393888045891964854360837 - ], - [ - "00000000000007d33d78522fa95bdcd4a25072aeac844cbe9b6bc5d0cc885d0a", - 14930240326912220437232591181374307607822146395712988852898063 - ], - [ - "00000000000003dd57f5dd1228f68390b586700063225d26bac972bd120546d2", - 15164777495018002532932947047554711971850359981358394796619712 - ], - [ - "000000000000076bdeca878b47c392f51fbda543b1e69612cf7d305deb537604", - 15357836661363254148000422860842573817259062733233058353910518 - ], - [ - "00000000000008eb1bb7e18d9dfe62210d761cbf114d59ca08e4f638b8563e30", - 15958691676650473757098043151847631737628132481844875166319930 - ], - [ - "00000000000001b0d8d885e4d77d7c51e8f1fdaba68f229ac04d191915845f09", - 18362382113291570192217962968958993778167022285180280072455374 - ], - [ - "000000000000081baa3a716d5f9ab072c9fc3b798900234c9be23ab02a287c30", - 22401656061533210580918575951901358551917227873474367195418168 - ], - [ - "00000000000005b88d0224b9b0d4b65d3de9a61d93609bb91c9297440f1c4657", - 22607630170339665188190152183146632918104515553204180801386220 - ], - [ - "000000000000027d6a6870403fa43a650b7d9a6e61243f375a79ea935ad9ef1f", - 24717308784096979165831027254372357786209337057535982141051915 - ], - [ - "0000000000000810a3490b86e4f302f6557f9621c5c8620c2b09ec8f0cf72794", - 23340837323532611728563455098354667083079032543420012677249737 - ], - [ - "000000000000073833bca8d0ea909fde717e251576b7b3ccaaa58ad5d39eed60", - 23242403153239567181248045649858932694926499996163845297462125 - ], - [ - "000000000000031b7fd2ed1f28ff74e969aa891297706c38bd2e1d3bc48183c4", - 21554570223215082708991040006621195807471559921461022664387024 - ], - [ - "0000000000000b0738bcba382983811d40b531f2e68cd57126092755f1be4ba6", - 20615559358036706401988446678345142325284830029403352655769482 - ], - [ - "000000000000000664cbfd5e3fa497c07614c33a0934b83e01fbe980634a9aa4", - 19540900118929245469513784022598005389554682908250308721002538 - ], - [ - "000000000000021eb520df39289a70e40c59822a8c47924dc4940e7d0c1455c4", - 19588382633956678748738987427134971684150657954263472331193639 - ], - [ - "0000000000000275e0c41b11bc250fe887c5e60c8ebaaa449f5c28c67133d496", - 18009312093826905807996061071987479121278814437031313100845126 - ], - [ - "000000000000097fb0fdbeee0cee7e8f4e1a4ef8fad49f3d549624b0d47abed0", - 17993487382135493395314550202532083574115934981151443202421804 - ], - [ - "000000000000053f199ae19d34365277e534f978ea2f6c69cd4757a4fc099af5", - 16574652347477707606538518827054821354422596190208356086094719 - ], - [ - "0000000000000217b2e7b4f61682d24b9357d62ad29f27ed45ea2a32dc1f32f6", - 17085566110414426392074980811822124799183310889195548936089857 - ], - [ - "000000000000039c1d77acd4702393f48ca61983c64fc0209ade141c694b2359", - 17870696125576904989516147458864032514115346444088781066283239 - ], - [ - "0000000000000ae53f0c78330f6c2fbece2752909bc3742823e4fab29c5fd2b0", - 15554723035590620381978382489682684584827446061258013409024347 - ], - [ - "00000000000004b4d72b8631a85ec7d226dc696f1913ba1bf735b7c8dec207b8", - 16944240402989056240270048857919858304172512515419325535711617 - ], - [ - "00000000000006e06735bffb7d2f215dcadd8311fc33f4a46661fdca3dc0560e", - 17028766006301915583302001014128348187011555103613522799474256 - ], - [ - "000000000000055fc0110d4a38ffb338eabc30c8b0aef355d4643d21b5b6a860", - 15614541816377627606833566623846498830327983334155710863946027 - ], - [ - "000000000000081b69cb4de006c14084c4861f0e4a140c37200117a738733fe8", - 15392658582903619517884239396883829533752908215468116311928350 - ], - [ - "00000000000009920770f2d40b5b6a8aba33d969b855c91b0f56e3db9c27e41a", - 14444739202621038642296525467957270513966223272539123613709315 - ], - [ - "0000000000000791dd1cb7a684a54c72ccde51f459fff0fc3e6e051641b1e941", - 13237069982010980053565410157895773782534548540484990599728904 - ], - [ - "000000000000019da474a1a598b5cf28534b7fd9b214eed0f36c67c203a9b449", - 12305441845260052457400411036992507599992679866354285875870526 - ], - [ - "000000000000074333e888bac730f9772b65e4cc9d07edb122c6e3c6606bc8ab", - 11046102047853392984991332456419807063224677592114743703633836 - ], - [ - "000000000000067080669115c445f378f3dec19787558d0e03263b9dec5d7720", - 10007086165511791816771124848728462094811571795311807624126594 - ], - [ - "0000000000000304760bf583f4ac241c5ffe77312fa213634eba252c720530f1", - 9412804029559050886132126846183090289448911866201243978830721 - ], - [ - "000000000000041fb61665c8a31b8b5c3ae8fe81903ea81530c979d5094e6f9d", - 8825807680257895657479991196220989276506275995152177228848553 - ], - [ - "000000000000022fc7f2a5c87b2bab742d71c4eb662d572df33f18193d6abf0e", - 8774981337152660993121733114298631263731662998207194412401974 - ], - [ - "000000000000013c6d43ba38bc5f24e699515b9d78602694112fefdc64606640", - 8158793708965770005321748925786317683564827171691288121295309 - ], - [ - "00000000000001665176b9a810fddf27cca60dfcfd80bf113289fcc8ffed0284", - 8002813558257060656072356380146767001272597020026124199745768 - ], - [ - "00000000000002dc6ef80f56a00f1091471d942ce9bfb656ebdab4ea0b77eb0b", - 7839578136187174365862370390163660393786299729896106652527867 - ], - [ - "00000000000002a1fa5546ec48ca88b9e5710e2c6d895bb3675004fdacd6ab13", - 7999436853933517849738304697453936802516675338771116464559736 - ], - [ - "00000000000000f517517c11e649b98feca7da84ae44fb643de5a86798fe3c31", - 9047933968943662429055854851798411859479270438104123361452456 - ], - [ - "0000000000000299cab92a923348acf9251f656bcbacdb641fd0a66d895a6e8f", - 8296401729498848716200066027575181804609215798824798623774115 - ], - [ - "000000000000027508b977f72c3a0f06f1f36e311ad079536630661880934501", - 9081043763417525999805054818818176389840193708186237826596038 - ], - [ - "00000000000001925959229452cc6fbfef0104ebed7ccd6f584f2439c5dd1f1b", - 8230756222604082728916412296377630357556635887892965869189316 - ], - [ - "00000000000003b34ca89509da5f558af468c194afaa8d458bbeb07c50cc7c74", - 7384132762576773456261468151764493698188252321818593178380086 - ], - [ - "0000000000000076559e314ab0c86cc552e34fd79488415d3d17f6ea3c01adb3", - 6172235633712067451972497618887145940241016806561805162089236 - ], - [ - "000000000000003a58043252cdc30ed2f37fb17e6ef1658324b1478f16c1463b", - 5561375174290806544537887055854541186367445945410171525594428 - ], - [ - "000000000000011babf767e60240658195b693711c217d7da0d9215ccab45333", - 4026320687087602082485484360946232153393536063582206994825059 - ], - [ - "000000000000027579d28fb480ccad8e2516d1219d4c1919e3fd4fc0c882955d", - 3513562835129894943437236119628516496362458327482173263945837 - ], - [ - "0000000000000074546fe07f80ba15fc81897ec56a5535de727df9fda9dab500", - 3004086841873755151847218915251583968757589997419002536446958 - ], - [ - "00000000000000b6c55833b80c07894f4c4d3bb686e5ddbc1b1d162e22752ca3", - 2675564091736135973597987074403776057837198839748912144832848 - ], - [ - "00000000000001326f2f970753122e35bfdf3358d046ddf5ea22e57f5d82b00d", - 2409853811740497723006216754124060157774336072925654369402748 - ], - [ - "00000000000000641084745613912464ff73c974bafd0bf6dd306295f019d306", - 2218270940716371747904935551989691447849649677886077648624174 - ], - [ - "000000000000011ae105ddb1a5bbac6931a6578d95c201525f3a945276a64559", - 1727570438327407251342043828017904756815782584333725141104066 - ], - [ - "00000000000000d9b66fee19af89eaaf3f3933d1acd2617924c107f0abbe0a41", - 1394050998377933499722472690026032322818492088393319462766728 - ], - [ - "0000000000000011956d42670c2f75eeb344ac0657a806775998e2c58fa4b157", - 1263613033940095470462619539828531085609177044392029609988618 - ], - [ - "00000000000000959b1ea990368fd16d494e68ee13bd7245ddd9cdfba3330100", - 1030471032625362817908252078771570487808270046919474202776261 - ], - [ - "0000000000000091f86b1e423e24fe358c72db181cfcc2738c85f2f51871a960", - 862536742724199235179104073167840532858949484653681168904647 - ], - [ - "0000000000000055e146e473b49fe656a1f2f4b8c33e72b80acc18f84d9fcc26", - 720982725653754866133106184196823339064064188411714396293721 - ], - [ - "000000000000004f6a191a3261274735292bc30a1f79f23a143e4ee7dd2f64c1", - 530591605956209005375408931042036763612094286954585940489028 - ], - [ - "000000000000005327c8e714272803c60277333362e74ec88b9ffab5410c2358", - 410030655694725315191023225682702558843537088229871225194892 - ], - [ - "0000000000000002e2a62b8705564c38d6a746fc8e971a450a69989152b5ee97", - 310118507134852270764417655876559284597214440570539833833949 - ], - [ - "00000000000000202bf3ff30109538bfd9b5075c6438ab5ef64ebe2cf9b61404", - 239366804613626989118705458454015500681551595998816410136871 - ], - [ - "000000000000001c997105893f5991cb45765ff856b6e503f8466cb22cdd330a", - 181156300891423147840813581996669801683959668074714341556907 - ], - [ - "0000000000000010c13ce182a3d8fc6748b75640447eb360d7739a5fe984ffc1", - 142431143903518058663503832095902619444236806543928975891292 - ], - [ - "000000000000000bbb49db68b79ecc8393376d78272d237bb612288af64c1de8", - 100696286705944192804288311731154032278221074156374274573154 - ], - [ - "0000000000000001bbfd0973c367d30eef2416d9e94bdddea53bccf541a4858f", - 68962785458117760598328072539715155134139124175836033018875 - ], - [ - "0000000000000004ee5b6ace996ab746f1e6dd952cdbc74c0b4f8b9ac51c7335", - 52765647417137724306257751915372504293019655403366801103482 - ], - [ - "0000000000000002f2f23b515085d0c9f37a2824304ccb7ca1546a48548d0dac", - 44233494692117781485772218913793271750746093635349642503033 - ], - [ - "00000000000000045590c3fdeca1753d148a87614a70fa0897a17f90bb321654", - 38110303308616451367971130315102755539751527244002747835354 - ], - [ - "0000000000000002b704edc0bf1435fe2116040b547adb1bc2d196eb81779834", - 29679712134953944285822600537404275892101515173751373902643 - ], - [ - "00000000000000038cc59dc6dd68ae0fbe2ded8a3de65dbd9a2f9a36d26772df", - 22829284162675848134182694598477416531051323480214451851537 - ], - [ - "0000000000000000a979bc50075e7cdf0da5274f7314910b2d798b1aeaf6543f", - 19005972021752888554737867279515830726136655207276613952446 - ], - [ - "0000000000000001dd8e548c8cf5b77cde6e5631cd542e39f42c41952e5e7085", - 15065030752662243106668159124876133476723125447787423397009 - ], - [ - "0000000000000002513542a461de351a5a94f96b4bcd3e324a48d2d71b403fe0", - 12288777851891587151373320769563000373599628572350950946294 - ], - [ - "000000000000000150cc07163e78d599a7e56c0d1040641bffb382705ac17df0", - 10284450072667651845630380921900049634274231900711580829901 - ], - [ - "00000000000000009051d83d276dad5c547612f67c2907acf6a143039bddb1bb", - 8614457133517962240383077577277860009688882364333357498735 - ], - [ - "00000000000000000b83d3947d2790ab0bcbbb61eba1eb8d8f0f0eb3e9d461e0", - 7065404376960081064548050202734411051432779994036264291865 - ], - [ - "00000000000000005a4fbbaeffee6d52fa329dd8c559f90c9b30264c46ad33fd", - 6343128691613752139911564815777925738673759990853012864417 - ], - [ - "00000000000000006b6834bae83e895a78c5026a8c8141388040d90506cf3148", - 5384566985902468539838947745491317290501351277582100625895 - ], - [ - "0000000000000000bf3c066c9acdb008e7fff3672f1391b35c8877b76b9e295e", - 4405445424268587912774001698765643657938467054813941696357 - ], - [ - "00000000000000006bcf448b771c8f4db4e2ca653474e3b29504ec08422b3fba", - 3863116091606416844204395924633339211949472882692642434091 - ], - [ - "000000000000000098686ab04cc22fec77e4fa2d76d5a3cc0eb8cbf4ed800cdc", - 3369644874471976788888364569461031006144821186115339704344 - ], - [ - "000000000000000036cc637d80982595b1fa30f877efe8904965e6fd70aeae1a", - 3045099804940836864917455634208357232827311736852711219052 - ], - [ - "00000000000000000ee9b585e0a707347d7c80f3a905f48fa32d448917335366", - 2578448738892556035161639572550297683334908085589209042124 - ], - [ - "00000000000000000401800189014bad6a3ca1af029e19b362d6ef3c5425a8dc", - 2293150027595934059742111263510686973492486336734191444857 - ], - [ - "00000000000000001b44d4645ac00773be676f3de8a8bff1a5fdd1fb04d2b3b2", - 2002553394643609738890838973561169711471353898661293921361 - ], - [ - "00000000000000003ff2a53152ee98910d7383c0177459ad258c4b2d2c4d4610", - 1602973121906621623499825176001242504910089450561449296745 - ], - [ - "00000000000000001bb242c9463b511b9e6a99a6d48bd783acb070ca27861c2b", - 1555090301026128543569302441423333574769288057539276771351 - ], - [ - "000000000000000019d43247356b848a7ef8b1c786d8c833b76e382608cb59e9", - 1438882618901096676077751337424466243540231648216042671672 - ], - [ - "00000000000000003711b624fbde8c77d4c7e25334cfa8bc176b7248ca67b24b", - 1366448148696423482270218240630565379904190231445288559686 - ], - [ - "0000000000000000092c1f996e0b6d07fd0e73dfe6409a5c2adc1206e997c3a2", - 1130631792721554272454999472203133803635779505498977249380 - ], - [ - "000000000000000020ce180d66df9d3c28aee9fcec7896071ec67091a9753283", - 982897902661444504749094486748895114762769275663213548760 - ], - [ - "000000000000000018d37d53ae02e13634eefb8d9246253e99c1bdf65ac293ea", - 903780674822307262725136466127288858430591999464421319774 - ], - [ - "00000000000000001607d1a21507dea1c0e5f398daf94d35fb7e0a3238f96a0f", - 777796786715545142990933608995805126717575855757223448283 - ], - [ - "00000000000000001acae244523061f650ddab9c3271d13c0cd86071ae6e8a5f", - 770217857427240993023051315984564139215374347389780685886 - ], - [ - "0000000000000000104430189dba1219b0e3dd90824e8c2271609aca5b71250f", - 749175002550855564826315453191856424408132088739667533908 - ], - [ - "00000000000000001aa260733b6d8f8faa2092af35e55973278bb17f8eaeca6b", - 680733332917879088904702563202563546480869669564659182916 - ], - [ - "000000000000000009925ad5866a9cb3a1d83d9399137bccc7b5470b38b1db2b", - 668970749931191589798031473561994304229010598616526068121 - ], - [ - "00000000000000001133acacb92e43e24af63a487923361a4a98c87a5550dffe", - 673862885517789065391946314370719009092913047398806257816 - ], - [ - "000000000000000018c66b4a76ca69204e24ee069da9368c7a9883adb36c24af", - 683252375980679323816587400004061743952674823748550569728 - ], - [ - "000000000000000010b13aed220b96c35ccd5f07125b51308db976eefcd718f9", - 663358898259210531333699235628449595078182768956016850932 - ], - [ - "0000000000000000031b14ece1cfda0e23774e473cd2676834f73155e4f46a2b", - 613111677421249032126095464155766633549817788831841702233 - ], - [ - "000000000000000010bfa427c8d305d861ab5ee4776d87d6d911f5fb3045c754", - 653202571346946874804858789924935228771775905822751784751 - ], - [ - "000000000000000005d1e9e192a43a19e2fbd933ffb27df2623187ad5ce10adc", - 606440210473080582646260971729051700700295823810315465086 - ], - [ - "00000000000000000f9e30784bd647e91f6923263a674c9c5c18084fe79a41f8", - 577485545195557219124205162278233745767078209386685370301 - ], - [ - "00000000000000000036d3e1c36e4b959a3e4ad6376ce9ae65961e60350c86e8", - 568436189899844976161013318161470010900802307864463999350 - ], - [ - "00000000000000000b3ec9df7aebc319bb12491ba651337f9b3541e78446eca8", - 577075446183156083131210077122535091982277790261940376730 - ], - [ - "000000000000000012d24ce222e3c81d4c148f2bce88f752c0dba184c3bc6844", - 545227685810993878908530774661151072647124692119579479626 - ], - [ - "000000000000000000c4ccbdd98c267bd16bda12b63b648c47af3ac51c1cc574", - 566251462633192796874293710752184671013063323002614261298 - ], - [ - "00000000000000000056bfec1dca8e82710f411af64b1d3b04a2d2364a81993f", - 565861163013726292152715860908846169118213713027013549266 - ], - [ - "00000000000000001275d1cadce690546f74f77f6d4a6190e2137a8a819946f6", - 552365082628398268882484833076555675653086455208105645421 - ], - [ - "000000000000000003816ae80c6413b84cbee2f639ba497ab5872ec9711eb256", - 566500826506537696689556913703962485638366020240431987761 - ], - [ - "00000000000000000d92953224570f521b09553194da1ca3c4b31a09a238f4f6", - 542528831070582225190358970054175523872885764221168055524 - ], - [ - "000000000000000006721943f23cfacf20c17c2ad6ea4e902af36b01f92e3c06", - 545717458684443426657861963694104795617022469075593560376 - ], - [ - "0000000000000000031d9af2fe38cc02410361fb213181fdb667c74e210d54c4", - 527828116295419256939747768525818422990809696098687485908 - ], - [ - "0000000000000000142e8a13ef6994961655c8e86aece3f0abebd2ee05473e75", - 515692649961651115318501607126660466594771968970128733915 - ], - [ - "00000000000000000c7a8db37a746d6637ef6a6eab28735608fd715ee2f394e7", - 511567833081612605062932845380344111401319750691048028647 - ], - [ - "000000000000000007854877c66c71a49af40d20f2d6f817becfe4d66d5e5a81", - 496889275651173623472900330204902534352929519684753746862 - ], - [ - "000000000000000005ce1d2d10aeb9def4d38233e859d98a4a168ea3fa36687a", - 473326016878892721329791660926511941983191613711888666872 - ], - [ - "000000000000000007c71decfe74855ad99dc2aa4a2e713165db5a8d6da5f32a", - 454358905739145490120646206475613103265889121292141221496 - ], - [ - "000000000000000008ce4f34161be6760569877c685e37ebebce3546ea42a767", - 443317174350997401226699663083830316501226707336190868827 - ], - [ - "0000000000000000086233f4843682eb47bacb58930a5577fbfd5c9ebd57ddf9", - 442803156296231091698861521258691618419467911445974398697 - ], - [ - "000000000000000010a904eee4fc763c6b88d378884f368fd652f63c1af71580", - 433057295538880306866830023102486508102611067408810729986 - ], - [ - "00000000000000000c114754749d622d4fa2f78c84d7147c345b2b99a8e83d2e", - 409419135913169127551416754586994781281659818649795994250 - ], - [ - "000000000000000000a5039e32cc9a89aeffbde1391e8bc9ae9724127904f01d", - 370716565562591807409073645534324134138902968133741824826 - ], - [ - "000000000000000003b0b73d9b3259c318cca48a6335b5d64545583f7f3773fa", - 340818601652590375722654926010534269909167221015231774473 - ], - [ - "00000000000000000198bcc5bd65fd0ccd1c7e3b49e0170ea80296cbfee05042", - 288495776454828940814130957501183806179235220269688957284 - ], - [ - "00000000000000000a60f379d3dc1413491f360809a97cbb02c81442c613dce7", - 259524927038954052049842432960406271327041356520946780931 - ], - [ - "0000000000000000038973a5f8ba8cdc7e371dcc8f4b24337ef695f24b962907", - 237834533496394499560421837048697627284447080833665891069 - ], - [ - "000000000000000004b8ec471974913d052a3af7dc2a8c6f01c2ac2f3d1f7b19", - 224600594221399775791208366807237501899705336368643295004 - ], - [ - "0000000000000000075d572eef1c4210adc7abf4e40986d7f0a80003853bfec4", - 187068024570118295326670137055767916260683809649859998591 - ], - [ - "0000000000000000074f9edbfc07648dc74392ba8248f0983ffea63431b3bc20", - 164898586657174446766450284432249324933473312757247241703 - ], - [ - "000000000000000003c4a4d9c62b3a7f4893afe14eef8a6a377229d23ad4b1ea", - 170169949941312779383320359289276524103458774855674537695 - ], - [ - "00000000000000000404b6939e6c35a5448386e5d58f318c82ce2fefb7d73e47", - 162900642628594452312926252009782198966469183066378413701 - ], - [ - "0000000000000000034656c96781091b5fbc799c881ea85b41cba0b88128eff7", - 161578253985639514393501040432436419806938319938347383115 - ], - [ - "0000000000000000045645e2acd740a88d2b3a09369e9f0f80d5376e4b6c5189", - 150883217088565412406283744917586302541065882485692466643 - ], - [ - "00000000000000000381e6a138308c6547d6fe3eb3437250ffefdebbf71eefd1", - 150899431314054665651533974629900879951167127567886958331 - ], - [ - "0000000000000000012100ddbb2102e65fb1ebbf104ead754a4110abffc4b8bc", - 138784704342716220538434620238263807017514526920482840730 - ], - [ - "0000000000000000046f56e59b9b1293b5e7c1587aa6d29c4f3f79b98cf22ee6", - 135263027158857483473983812897618462696878980167989570177 - ], - [ - "000000000000000001bd1c291e91f4476f93454d4542d2ed7e44fc86902c93bb", - 137505575960473580232190762314053902119220761315057010096 - ], - [ - "000000000000000001c37a483375ff6fd6ed7c5b79d80167b027a8fdb0721dcd", - 128714000003724620550017796842876174875520737762229396938 - ], - [ - "0000000000000000051804b4c2da5298c4573386bf1d4242bf0e26a49ec32e42", - 126334257597368896694079008874105899845411447996852366067 - ], - [ - "0000000000000000034bff7888f1f7294311f0199322f77c1457018c875bd9e1", - 126278728489740292169183109579386034099056145098127681816 - ], - [ - "00000000000000000506b43c9283ccbc40f583e0c734e4a8af2ce6a4262c6221", - 133533674521328301805375468020445677637867523414815983180 - ], - [ - "000000000000000003937068e19a0750a33978050f019d2b60f430e3da707db9", - 124023231761354306172598997090326962528984683316222123922 - ], - [ - "000000000000000002e2f6ec3c9eb965aa706c788da7dede201b6b4b8fae3971", - 122123890689597169329897975011373560881532793639713851004 - ], - [ - "000000000000000000b3076636b13562bb4315f895bcb324e0c962763c2196b1", - 119378471659813172166584350643745606396975629669615648535 - ], - [ - "00000000000000000025b8961d1d0cfba33b0205ec10b3ce541618e352b0bbd5", - 111760099061575845238587552104542233599456594020708180600 - ], - [ - "00000000000000000421d58b78b9f063a4b20e181d55c9c79082f9e4b8b30925", - 104283398725864083874296861096497976441886465506877958948 - ], - [ - "0000000000000000027fd968d41741f31c73c4a3b304472da0165245278e2ea3", - 106299891835047816880570816560226555729378855394467112113 - ], - [ - "00000000000000000364a23184b8a2c009d13172094421c22e4d9bc85dcf90a5", - 105881534387569087602448606393026827269357803018613746024 - ], - [ - "0000000000000000042a2ed4a504424060407825d774a54f2e148fa769ee72ff", - 95668758377605096786059344838386233938948428360571473100 - ], - [ - "0000000000000000025f769f13f2806fed19d9948b1a7ef19048177789afc5d3", - 94012478943487551583874745631213709785208280748731165788 - ], - [ - "000000000000000000b3ff31d54e9e83515ee18360c7dc59e30697d083c745ff", - 86923144448447518913809103136679872784564523201770836515 - ], - [ - "0000000000000000021ecdcb2368ce66c23efd8bd8ab6a88a8bb70571c6e67f0", - 84861696667064232085350895302379622169877065200841464945 - ], - [ - "000000000000000001972cb33b862b27c1dc3f3a723f7d1cfd69aebe0409126c", - 80022436630974307725804284020086214397285337936510125904 - ], - [ - "000000000000000000cb26d2b1018d80670ccc41d89c7da92175bd6b00f27a3e", - 68605895635350324123887563889758158648405285708846995220 - ], - [ - "00000000000000000276deb4022f66cacd929c690cd6b4f7e740836b614b21f4", - 63859488458993656960329361157926368758742149072401957675 - ], - [ - "000000000000000000587912ced677698c86eec8b1d70144dccb1c6b0bad0f17", - 61163588147080336562860372542789363550797760125590468374 - ], - [ - "0000000000000000009f989a246ac4221ebdced8ccebae9b8d5c83b69bb5e7c8", - 58509968837817799412963215131374851975666125194369450244 - ], - [ - "000000000000000000038bed8b89c4e82c13076dd64dc5f7a349c39d3921d607", - 56672978024443644437306289406994921596646228103740151166 - ], - [ - "00000000000000000122f47d580700a3a5b4b6cb46669a36e4fa974c720ab6cd", - 53958706289281806789111061412993899806784528297928389354 - ], - [ - "00000000000000000172ad9ea56a90bdfed0f364a902500e9ff4d74f000ced99", - 51765097045688608012424287693701763884232488530834902033 - ], - [ - "00000000000000000201d7429db233c7055e9699c5bfb57b167ca8d0c710dc71", - 51649247587912518226490987244672765779747315777961084943 - ], - [ - "000000000000000000c0549b2a8adbefbf6c909f61fdc4d6087c44a549cf8201", - 48144761676638685568393252844604229390549310101321306353 - ], - [ - "0000000000000000015b6789cdc5dc13766f58b38f16d5b35bf79ce4b040f7fd", - 45240056525891956455575817517143990421796325617308336169 - ], - [ - "0000000000000000013a31b29f845d97465bff53f901027f8ab4b1a2f59118a8", - 39719085345888042233262788103506269388987831055953076236 - ], - [ - "00000000000000000088cdeaa7389a7de9f09e3a28b3647630fea3bd1b107134", - 37880653743061241847157755785329340895782894371522587986 - ], - [ - "000000000000000001389446206ebcd378c32cd00b4920a8a1ba7b540ca7d699", - 38043253251243498799796359449649225329347481521269202959 - ], - [ - "000000000000000000f41e2b7f056b6edef47477d0d0f5833d5d4a047151f2dc", - 33510049713200839962002052974605137446441531580345905745 - ], - [ - "0000000000000000010e0373719b7538e713e47d8d7189826dce4264d85a79b8", - 31340511093499215382498875631096178729473407545556119324 - ], - [ - "00000000000000000053e2d10bd703ad5b7787614965711d6170b69b133aa366", - 29201554221106481014362444600779904393001928219662824381 - ], - [ - "000000000000000000cbeff0b533f8e1189cf09dfbebf57a8ebe349362811b80", - 30354232589320643409720162249214362116926806095467115096 - ], - [ - "000000000000000000d0ad638ad61e7c4c3113618b8b26b2044347c00c042278", - 29217445580005453044145144287633722880237231025559536344 - ], - [ - "000000000000000000a7bda943639876a2d7a8caf4cac45678fb237d59c28ba1", - 24433315186493117547015353728839494165411420867297244659 - ], - [ - "000000000000000000fb6c6a307c8363e923873499ba6299597769c10a438e61", - 23988337581966024451862874735374376736823985966238572778 - ], - [ - "0000000000000000006f408147ffbcaa0fb1dcf1f199c527ffdaf159d86e5cd9", - 22526603255015707503680924025827203599625190615869254262 - ], - [ - "000000000000000000e3be3cf7343d7792c0d47d3c39ddb9ceaf19961e9eeab4", - 18556473167918062248854389700869820348727762534776424137 - ], - [ - "000000000000000000b3fb09d6def197657e20f9c1d5e9680cfcac1e1f9aa269", - 19759157687224108664379003516351943599373215433413919905 - ], - [ - "000000000000000000bfe71f044145e1b42fdfb3a523ee2a215e80fa6afc2a98", - 20014601621424565995143800336070874732337755340431658220 - ], - [ - "000000000000000000cee3bff56ee49c0f96d1cbd17fa17dc6f84b3f48aed765", - 16946223147907286639275870228581142863500004051737247938 - ] -] \ No newline at end of file +[] \ No newline at end of file diff --git a/lib/checkpoints_testnet.json b/lib/checkpoints_testnet.json index 44c8b36a6b5b..47fc03291eda 100644 --- a/lib/checkpoints_testnet.json +++ b/lib/checkpoints_testnet.json @@ -1,4356 +1,837 @@ [ [ - "00000000864b744c5025331036aa4a16e9ed1cbb362908c625272150fa059b29", - [ - 0, - 0 - ] + "0a083934469e9bad81b1b7038ad3252fdbdca3c2a61b9cf67695d1e5339513e5", + 0, + 1487031391 ], [ - "000000002e9ccffc999166ccf8d72129e1b2e9c754f6c90ad2f77cab0d9fb4c7", - [ - 0, - 0 - ] + "64c8a77f51fae49d484b67f8e8ef59f0dcd706b95fcdb5dc75d9953384c097df", + 0, + 1487271985 ], [ - "0000000009b9f0436a9c733e2c9a9d9c8fe3475d383bdc1beb7bfa995f90be70", - [ - 0, - 0 - ] + "bebca2c6b59117df1e0ded81d6c805e3c1250c9ec42d43629a55a1aa99ece186", + 0, + 1487547539 ], [ - "000000000a9c9c79f246042b9e2819822287f2be7cd6487aecf7afab6a88bed5", - [ - 0, - 0 - ] + "4bec3dcfbd2614e74b399825b323226ea54fc0225c593b6c740f9b8d55b16165", + 0, + 1487625740 ], [ - "000000003a7002e1247b0008cba36cd46f57cd7ce56ac9d9dc5644265064df09", - [ - 0, - 0 - ] + "7c88208fc0837cbf9e986b949cbe0596daf896b643fa3b1d398d0edbd5670674", + 0, + 1487891850 ], [ - "00000000061e01e82afff6e7aaea4eb841b78cc0eed3af11f6706b14471fa9c8", - [ - 0, - 0 - ] + "328feda15b8eb91f4626ea0edda82989d46960e8c35f4bf1f9e590668a365892", + 0, + 1488178547 ], [ - "000000003911e011ae2459e44d4581ac69ba703fb26e1421529bd326c538f12d", - [ - 0, - 0 - ] + "9e4a65bbdb396817fa22278d0491dec4a52dfc81bd1284728ae1104d57cce248", + 0, + 1488472292 ], [ - "000000000a5984d6c73396fe40de392935f5fc2a8e48eedf38034ce0a3178a60", - [ - 0, - 0 - ] + "2b1698baef2860f34e78306d5f01b3c5f2924cd487e6c266a9dfc1c175af4336", + 0, + 1488817945 ], [ - "000000000786bdc642fa54c0a791d58b732ed5676516fffaeca04492be97c243", - [ - 0, - 0 - ] + "240c82a42cdfb7fa1238287e985379e9b8e8eff23d90c9c951f60213fe122fc2", + 0, + 1489444205 ], [ - "000000001359c49f9618f3ee69afbd1b3196f1832acc47557d42256fcc6b7f48", - [ - 0, - 0 - ] + "d225c6efd5431dbf81997835c9486c8aad7ad17e5a76b2df90906bc8b39d69d2", + 0, + 1489601589 ], [ - "00000000270dde98d582af35dff5aed02087dad8529dc5c808c67573d6dabaf4", - [ - 0, - 0 - ] + "cb61c73edbd859e38399301f6f74acc7f9b9e50527d0eec92ff512a7345c017c", + 0, + 1489884491 ], [ - "00000000425c160908c215c4adf998771a2d1c472051bc58320696f3a5eb0644", - [ - 0, - 0 - ] + "0e7acdf73282c080da3ee4e039facbcfe623bf91118cf84ead01e2a3443be18d", + 0, + 1490191735 ], [ - "0000000006a5976471986377805d4a148d8822bb7f458138c83f167d197817c9", - [ - 0, - 0 - ] + "9c158e6bcfe742cb6599d2fb2d95894438a01d8e163284b242bb16151dc56085", + 0, + 1490545488 ], [ - "000000000318394ea17038ef369f3cccc79b3d7dfda957af6c8cd4a471ffa814", - [ - 0, - 0 - ] + "5fdb1def0e18833487134ba974c869fec74f5d4f5ddc26ede8e077bd8d925b8e", + 0, + 1490783079 ], [ - "000000000ad4f9d0b8e86871478cc849f7bc42fb108ebec50e4a795afc284926", - [ - 0, - 0 - ] + "d5cd594e50532e3cbb7e887e8d8a586a71c9b49cef28300e8e40ed3d4aa93537", + 0, + 1491388405 ], [ - "000000000207e63e68f2a7a4c067135883d726fd65e3620142fb9bdf50cce1f6", - [ - 0, - 0 - ] + "7b8c7006b86e153c6e73f75e23d053920bb95fbf13fd578a3e869070774b10e9", + 0, + 1491557747 ], [ - "00000000003b426d2c12ee66b2eedb4dcc05d5e158685b222240d31e43687762", - [ - 0, - 0 - ] + "48f87162211b9fa7b28341b4b2c3de752eaa3ed854fb2533ac0ffbf89238ddb2", + 0, + 1491809515 ], [ - "00000000017cf6ee86e3d483f9a978ded72be1fa5af37d287a71c5dfb87cdd83", - [ - 0, - 0 - ] + "25db6e71e6f14a98066cf0e29e0186eade588c68a1b8f11cded81e166418a22b", + 0, + 1492147555 ], [ - "00000000004b1d9fe16fc0c72cfa0395c98a3e460cd2affb8640e28bca295a4a", - [ - 0, - 0 - ] + "e5f401565463c1581f823c7fc9f168b6d7dbb7dbb6fe06d05081dab3983a3ba5", + 0, + 1492446999 ], [ - "0000000046d191b09f7726e4f8bfaffed6c30734afbf1f95e6bddbe0b07d9e88", - [ - 0, - 0 - ] + "6740fa3580f2dda47d852b21ee2943e0ba0d4b385b9e560a78c199320358ec7f", + 0, + 1492773524 ], [ - "0000000082cec8200e9ea055c2991bf74560eb7e7140691ea53e7828dbdc9553", - [ - 0, - 0 - ] + "ea9360739a35cb829df1fc20def8a73471e31d27d856929ee008225bb5c18dfb", + 0, + 1492883273 ], [ - "000000003775b96d6b362d4804afe2d9c3cf3cbb46a45c3ccc377c94e83edd23", - [ - 0, - 0 - ] + "aca324bbe8e072d15849be5b3849b4a3a5e4312ebc9b2009d579b95a329279fa", + 0, + 1493204955 ], [ - "00000000037835a92404acb2f18768a49d4f93685ead30aad6bb3b073f411e02", - [ - 0, - 0 - ] + "eb32ce670b64427b6d982cc12e18339f03e37f5eef4c2fc29043e61ce6451269", + 0, + 1493336938 ], [ - "0000000006cf75d17706d1f62e6b08e6ba5facfde38a8920b7d808a6b6781ff2", - [ - 0, - 0 - ] + "5ba6fe56dfd9d2c729bf4f0a7762c05921bc40ca3055c6a5f976ddf9a503dda7", + 0, + 1493708364 ], [ - "0000000003dff257cdae43703fcd0ca91fda0970f5fc04258b4608fb1942a6f6", - [ - 0, - 0 - ] + "c12e478167babd663c3e0dff615b8ad82b8d085088748b0b9afec78fb45bedc4", + 0, + 1493889135 ], [ - "0000000000532d97d18867658e08c789f627535652382147e33bf8626d4131bc", - [ - 0, - 0 - ] + "38c247e2222bc7f23df39d18c4a8a9f3e9870b9d1af6f09f7609a2de4e108695", + 0, + 1494053295 ], [ - "000000000266dfb79bb11dedd0ae748505863ab3ab731269cd71a2c2fbd159b3", - [ - 0, - 0 - ] + "9bf789025cce72e6f9a73eaf83e9236433946b6fbad10baad12c22617a788536", + 0, + 1494063722 ], [ - "00000000349ff0119d5c0dd8ffad8bf41cd6126a88416148b81fa4dcaebc42e1", - [ - 0, - 0 - ] + "aeb9ce2a2959e64b8f1d531d2301164d013063306e2dc8ae1fb450db592a01f5", + 0, + 1494122264 ], [ - "000000003c61939b4799eeea4335218d30de9b1071605126d719dce0f0d14810", - [ - 0, - 0 - ] + "a8420d5dbef341ff4198c42186077948e47609188617d1956abe775af8f72c7c", + 0, + 1494337286 ], [ - "000000003d9284570ed648d2b12ad24046ac8b9abcf05c4e9813ea110490cf73", - [ - 0, - 0 - ] + "f7b8e6c92926add3db58751cdd52731d3bdde7a07d1c8150d074888cab9e7b7a", + 0, + 1494597416 ], [ - "0000000001360b66e6dc0ccfbd75356034e721ae55c3d5c71a58be5d281c252b", - [ - 0, - 0 - ] + "1176aea5d05f7162e440649338b3a4baacaf3d3fe1235faad1adfc2b14e4860e", + 0, + 1494931142 ], [ - "000000000c114f42504916bfb2ee26ed8307b3f7f74226c1cfe1f5302ec23d26", - [ - 0, - 0 - ] + "311af2d6491e32118af7918f684c4c8b0a30e0cf6344072a673b5d0094d77160", + 0, + 1495054877 ], [ - "0000000007acac3fcf97b4ca81821263b704364adaa2736fce0a0722bfed4f8d", - [ - 0, - 0 - ] + "15df5b0c4faf5895e426617356be99f51c7fc93b3644a149d9ffd7a15a70b29b", + 0, + 1495197350 ], [ - "00000000059768ef7731d27f9c2be48c6e16d7cb56680625f08ff25ead504280", - [ - 0, - 0 - ] + "327386817db660c5f70796a7a7b46390b2fb6177442a4fd306e5ad08aceec777", + 0, + 1495616316 ], [ - "000000000351c8908f1f52518ce4bd251b896ca3fbccb69a2607db6624bafcfc", - [ - 0, - 0 - ] + "c1c65035bffab1f00a2501a5340df8d4c6a2792f11a49062705348b0d7cdee9d", + 0, + 1495984860 ], [ - "0000000068d7ccae048e212e9e2ecb4d944f583b4490df4fbf654b4915597052", - [ - 0, - 0 - ] + "1b76a0697fa9ab75d945123dba28c213b61b1bd82e830890f7f55c01d1c600ed", + 0, + 1496317693 ], [ - "000000000e2aaa36417187233ff55325473bd5b7a164b358da60c96d1920fd77", - [ - 0, - 0 - ] + "4f5fa3b91b79720f2abd27976cbdb73f3dc90e3bfc33f02cd8412f0e97e24539", + 0, + 1496626709 ], [ - "000000001eb11ef6dbe0647bc87a8d218f6e59c2b9690f17edcf0dbd39cd0308", - [ - 0, - 0 - ] + "a700040d1fffbb99723b54281e3495a807513895f84030bc0158bb0b4661dbc0", + 0, + 1496912288 ], [ - "00000000022e7855e24cc3fff67ce093242434a8ffa45882333a0f08a40aad9c", - [ - 0, - 0 - ] + "5669e2d5cdfa36d346dfc4853424a3a2b4a266e9fe3237d3e4f872478d0cab68", + 0, + 1497008640 ], [ - "000000000210130ff4e3186258c09a8463c1e196f5c5432b4c7b6954e907bf63", - [ - 0, - 0 - ] + "5dd0c4a5dc98d6a942b12c617fa499c0151f5ed7a7c87ab77cfc41b07a25fb10", + 0, + 1497150657 ], [ - "0000000000e01372ede322bf88ee5ed8a46dd4fd8df832eca16180263fc8b1ef", - [ - 0, - 0 - ] + "14beed2fe1652915d4aa807f55293b438abd65258baae5b450dfb894c4eb6cd4", + 0, + 1497412738 ], [ - "00000000a0701896e26d5d884834b267512e0af52c92edc4bccf1c5c803d3c4f", - [ - 0, - 0 - ] + "3f8bb28b127ac7e5fd14c3bc6d1944a1c22cabd26dc9ac5756b2ea18c50c9e2a", + 0, + 1497843367 ], [ - "00000000869fc8d9ac1588f3e5bdfd60253e9824083800b7794010e0e9c6b6fe", - [ - 0, - 0 - ] + "d78882fce0596d56c99265fc840ad522f006ab6f456c5f6c48b83c29d8f5ad9e", + 0, + 1497894933 ], [ - "000000001d43b3165ec30736f28f0761600b092686f861db23ec38f2d92b0ec6", - [ - 0, - 0 - ] + "17223fa708285c6258f45244efd3d922063705237f579aced1a661226902847c", + 0, + 1497988852 ], [ - "000000000ef4092da8c2056e5933de0e1530194c3ad941a9b393fbb26f98862e", - [ - 0, - 0 - ] + "44f06da90d3836d37a01ea5d758be79ed09992870912e7dd2490d9c9b9b3b70f", + 0, + 1498253819 ], [ - "0000000001e3fed39f70023909f962bea146b03bc8e94e5d19d7da93123f4f64", - [ - 0, - 0 - ] + "5828007113bcebf1016aad38eea99f4a4305160afed747dd2af9efc77babded2", + 0, + 1498259753 ], [ - "0000000000b4b8c877bbe3cde97649845290bb78999ecff4621b9bf2ab16aa2e", - [ - 0, - 0 - ] + "d482356e7e977ff0b73a4fc432f1009a97bb8e73ebad062800af2914277afb31", + 0, + 1498549788 ], [ - "00000000006095ba3b4742883a0ec427a3fd685ffb65b987ea77ebfedea7da82", - [ - 0, - 0 - ] + "0a1a8c5434af036a3bb22efefb20aff51948aa71e4a8cfe1bd348c71972bc72c", + 0, + 1499081056 ], [ - "000000000168f0a76a6068a34fc042553aff4aa63b906028f28c2a4c327328e1", - [ - 0, - 0 - ] + "b64366f229369e7ba61b390a1ed026b2b5d618c637be8eb31e6291bbac4cfbdc", + 0, + 1499449930 ], [ - "0000000000af10f3079b4989ac4ff0baaecab38220510cdae9672d6922e93919", - [ - 0, - 0 - ] + "7db8dd1a7800faa4c1f711589769cbf5952a6d0a1e0545cb2428742d26a04eed", + 0, + 1499588110 ], [ - "0000000000312791ada0f6a4c5eaf2a1cd57cd06f5970a8ab49923817b862c35", - [ - 0, - 0 - ] + "8400774f2ce98720e9deec98d8e702a4a89eb71fe60078eb14025bc6f50b44fd", + 0, + 1499692551 ], [ - "000000000055f3d4f45c4d199d9c230cb2cfeb68c8e934cfd061bd616358655a", - [ - 0, - 0 - ] + "b501b69e334a59ff53418562dfa8d19f0c1ab9a6262094687320904888db4279", + 0, + 1499758298 ], [ - "000000000036b6129bb5a786bfdd75cb4b932f7dcae9da469d3ba35096f1e821", - [ - 0, - 0 - ] + "53c9c3eadc09607cea4a543b4198b1376fd0d873a7a431e3facd18ffb68c96af", + 0, + 1499764361 ], [ - "00000000002fbccf271c13e486673251ecd7951ecc12ee73c4390e0ff09e9b59", - [ - 0, - 0 - ] + "3dbeefacd672d741362b44993075f69910f6be0e2365b7baeefdd03f03c7c2f5", + 0, + 1499770673 ], [ - "0000000000314e297a81bf002fc40eb391d8883ea45ee4e782385aa0fdba6452", - [ - 0, - 0 - ] + "88d469e0722afccdae591d9fac3b2e9206b4337a2b4ceb860db5cc6e5b6a93e2", + 0, + 1499779442 ], [ - "00000000d3c473819ec3b3c268f7b555df22772e407bc8f246a47cfc579ec61f", - [ - 0, - 0 - ] + "0db530711cf188cad70d696ae43dc14ae449b351876486372120e9b699ac3552", + 0, + 1499801456 ], [ - "0000000075a438fda6bdb391263d0a2a6e8e68edd9dd8f70fe5734eab9351eb8", - [ - 0, - 0 - ] + "2c9a5a8880c7f8ea0bda04b38a83c91aec0781b11e99e59e1021045e324d0c48", + 0, + 1499873373 ], [ - "0000000017ebae0a2bec50008b4a4ea8839798cbd9ff228e76aba087d0ff1736", - [ - 0, - 0 - ] + "d3505c66dba3a58e506f8a41127310d57fecb187562df2ae70179de2ff83bd73", + 0, + 1500382038 ], [ - "000000000800466ba31c0bbc12b125f16d05ed27788de045e25d6f093817d29c", - [ - 0, - 0 - ] + "adb1c056849a74d9d78b3aa883d774bd7c9935853c1410a082592b5d10689f9c", + 0, + 1500459595 ], [ - "00000000002163c41f2264f202e611aeb9ba6c0a3ee95cd8e5e7e571edc64edf", - [ - 0, - 0 - ] + "af326d9bb82880939e646642787ee0a5a1dbce83b379903aa8d35edb9f618b22", + 0, + 1500710651 ], [ - "0000000000de9882d417786fce8c755cfaad17f40cda744d4badedfe5e414e31", - [ - 0, - 0 - ] + "52e6c9c0bad4223e60debda5621a960b0238486df24b5dd9cc4ded5b71849341", + 0, + 1500760523 ], [ - "00000000002af352cf41f60a5ebf033bf7e4967c0597cee706ba877b795aefb4", - [ - 0, - 0 - ] + "85087d9dfc8013b470dac2f3f8d71ed6bee9a6f3fb5f5afaf9698d5f99717a63", + 0, + 1500836909 ], [ - "0000000000009ca0030f1dd0b09cc628f2d4d278c87b20781a1b136dc395debf", - [ - 0, - 0 - ] + "1ae12813c8bddfab0693a4fc8b5353e6aca4c88ec8492e1cff431f766d25528c", + 0, + 1501359299 ], [ - "00000000ffd27370a76d06a0da0e3805f47e35e2cf584d73d2c5ecaa2e525642", - [ - 0, - 0 - ] + "10c76d53784f00b3b4433f123aeb24fae8d4ebadad186a025e55babc29bf5377", + 0, + 1501624492 ], [ - "00000000720da6910aa75099baa020cb8db37e1dc19cdff66152225b7609c23a", - [ - 0, - 0 - ] + "4f42c943670b4858f3a198ebde3edda4f6c999139ed572431d1a1d22df4a4c87", + 0, + 1501628395 ], [ - "000000000a5c2cc704bce5e8527ce91bac7430c659624ecd86e6a1bb9b697962", - [ - 0, - 0 - ] + "46d93984b064a07344b230ccb979c1106db0318769c364faa960ec5bcc395c83", + 0, + 1501632204 ], [ - "00000000084273545134e9a06483c8fab00c2b0628056bb1967f310c74a971bc", - [ - 0, - 0 - ] + "bfdfed63c9265e4ca71b749dba4ba079e7586f3a769fa0f34def7575ed1a2753", + 0, + 1502086628 ], [ - "0000000002f66f4da52804647b1c3e1f89d17bdb05e9cd4ebbd922007c773f21", - [ - 0, - 0 - ] + "8fce60c1ac1924f4782e9b8a148c9be1c5e16e8c07cbea49ffbf653c525ac3e2", + 0, + 1502108755 ], [ - "00000000c46146c9d0a67a354b3f82947e52670a3bded6d8513ab34a68ae18bd", - [ - 0, - 0 - ] + "12e77d4e2916c563a974b1fda3a1f2f5ea71767f1c6ef8340d3c96413beb3c60", + 0, + 1502227916 ], [ - "000000002f61c429d7dbe7bde75796086efe574998766806138710a2d6001eba", - [ - 0, - 0 - ] + "68b0df4d6ee6c155c21d79446fcdd50344ce3651a02ac73b2be9a9d5c3028e0e", + 0, + 1502448943 ], [ - "0000000001daf3e3e78a57df2c2d2ddd14093d10515925e75c818bec3bbd30c2", - [ - 0, - 0 - ] + "f0fd7e8b80a3668876493db84b35a6349c4c3077b7471903fd299a1947969e9a", + 0, + 1502623472 ], [ - "0000000002e133a7427a9aac6ceca969b27507c14111a45512cdf8f52a436de0", - [ - 0, - 0 - ] + "bfea3a1f2206a93f977ccfeeb2ba5354ac90e640de99f8f24ece095fd08b11d8", + 0, + 1502637950 ], [ - "0000000000f7c4374d458666740de1d0e8c55229a209ced7c38e38708781487c", - [ - 0, - 0 - ] + "babcb18933d36aefb2ac6c42557fc9d178026054ccd92937406aee52a7017e91", + 0, + 1502658737 ], [ - "000000000035bb9ea329ba30b83eeb4ea6f57c2fe703b97f9b879f21e22643e0", - [ - 0, - 0 - ] + "5e4eadc35f65e50248b4ef73e9b6434b373473befadc585c9a596030ba778de3", + 0, + 1502680445 ], [ - "00000000001220503e0aaee266bca85de09ce97b0091f24972d1ad1c8afe8609", - [ - 0, - 0 - ] + "c3d7eb99cf8d0e16d4e92ef3483c57d881abffb670e4d8a282c1821c4ee2c1c0", + 0, + 1502735499 ], [ - "000000000010a614c60457f8d2ae2bb826d037f52113252888fadda8ed773c9c", - [ - 0, - 0 - ] + "ad061c82cc119a5e479d4d86370e12c20a3dd51a2f152af86b4d75b0e20eb7e8", + 0, + 1502916488 ], [ - "00000000585a8b882ecff8aa8434feeac4ef199ca669bd81ed473e37f0bb4528", - [ - 0, - 0 - ] + "7387000a0c182042d90a92d962851b0746224d92bf2afae0b1b6e90bd49db176", + 0, + 1503294964 ], [ - "000000009504ffdb5fe82ad88218fb5e75a8bc185247e30e22d23b9fd9b7f282", - [ - 0, - 0 - ] + "e6a6d57151dd2ef53e470850125f873e567f9428d2ad21d5d60abb909f35c37e", + 0, + 1503368860 ], [ - "000000000ddec7d73bcd653168d82e34cf5746e006bccda8a9c031c3289b9568", - [ - 0, - 0 - ] + "12cbe96f31596816d5f9267a46182732e97ea973c30966fdec9dfa86a0b85b45", + 0, + 1503707060 ], [ - "000000000cb6620ee4e8cb8b6b4d51251e5961f7ae2e83538ab3a4fef3bcc773", - [ - 0, - 0 - ] + "cd2a723b20b6039206639a2b62e8ab795f6d7f72dd23560c41482fe4cc5383dc", + 0, + 1503947202 ], [ - "000000000239224a0841738513c1eda712b73266ea958aa75f44a3985ebfab82", - [ - 0, - 0 - ] + "a03c6e2eb8f76c380f2dfdcc462f071bb1b51459bc6570788d0dde8d8fc15931", + 0, + 1504386196 ], [ - "00000000002630c7c3586fcc19079300403c54dc293bcfdf8a9981f85a5c31bc", - [ - 0, - 0 - ] + "525dfcdd8bffda56c593e1b0dd0ce46317c08dac8347b88da84859be80a3945b", + 0, + 1504395103 ], [ - "000000000028d8c34f44e51fd71f5401094a983f6566e6d08ce86ec5d1bd639c", - [ - 0, - 0 - ] + "079ec52212b748a953968f13dc6a224336f94d9a0a3f5c7156edf26554297288", + 0, + 1504404536 ], [ - "00000000000dca95f1828adc3c37b4625f60aeb35a6614a4358322b7a6bc2f7d", - [ - 0, - 0 - ] + "7872488a596536837faf87c87616ab8b8a043eacd8ab31c4b0a08eedeb37dae4", + 0, + 1504414377 ], [ - "00000000d72ec84fda18959ddc474d1a31a3a13b1d94695136c4810af8c01a0b", - [ - 0, - 0 - ] + "05bfbfa2d3b194f38babd171f7f694dda1edb493ce61201e2e2264090eb8cc06", + 0, + 1504423920 ], [ - "00000000327c29604996eb7f0a208160969ee4408a1cad277a956334f94e0f35", - [ - 0, - 0 - ] + "cfb1943c6a7821c11bbf3d40f6fd35f2054b1db63c046b964551391329cf9e0b", + 0, + 1504433399 ], [ - "000000000e1bd41d009c1910fcfee7bf1cc1adb04b0b7a632ac36c1092f01bb7", - [ - 0, - 0 - ] + "1a677c66a4d21bde0581a04fbe7a31e36340ee5263e460d1f7becf1465e190d9", + 0, + 1504450920 ], [ - "000000000201a5afed48b9d095b949229e9882ef8bc96767be3097c87264dfb6", - [ - 0, - 0 - ] + "efdf992d0d6bb4bbc09d13f365d32756297664d94eaa4586b1d137d5e37b23e0", + 0, + 1504518607 ], [ - "00000000003f28e8f3f9c80b1269bb0aa3b57501c12458550ef04fd43aca6a33", - [ - 0, - 0 - ] + "6e308250d2db09d593af7a9b411d7ccff8d997e6cce5fb05d3538be1a1692785", + 0, + 1505200043 ], [ - "000000000029e09fc14e38a6a0103c8c67383f41af7d76998055682525f4ca89", - [ - 0, - 0 - ] + "0e9b1b29775236a3613cda5a9944add77d2c08a8051ae9ebba113ebfd3ea5e72", + 0, + 1505370936 ], [ - "00000000285ce297602995582ba5d32d583d618a6a92643566e25dd36cf2b7ab", - [ - 0, - 0 - ] + "c670314a5346b357eb06632b467421f3787390a0fa76efe2b8122c90d44f5afb", + 0, + 1505376098 ], [ - "00000000657045fa54fac52b8480dc84bd4c418940ba63679f4bd6add6a39962", - [ - 0, - 0 - ] + "e22b59d871637f9dca5ad1bacef248706ad75bbe99d4659b2d78b3274ed8b880", + 0, + 1505376644 ], [ - "0000000017b7bb58be05a47ff7c4ead27db750813d6bcf3f99cbcc35324cf445", - [ - 0, - 0 - ] + "4e0c82930edc8d3b55cb879fcce459c29fb895a0ddf72acd892690432e65beae", + 0, + 1505377048 ], [ - "00000000003a310e39b6df17f17450496b4f5c1593399bfa1ab8b4d39bac9b25", - [ - 0, - 0 - ] + "07a974c9e7874df72d3320831a1fdfad6bc8b2e52db7d52bf109cfe466cbd2bc", + 0, + 1505814246 ], [ - "00000000000bfbc5294f003548a9636ebbcea3ba42577821266317676fbc363c", - [ - 0, - 0 - ] + "7800648f7725971127345c27dee98867583888ae0a8f8c955c2ce15604845664", + 0, + 1505823902 ], [ - "000000002329351dd70c24da2eea5ac19f65b6053c4611aa4eb93bcc2783c57e", - [ - 0, - 0 - ] + "9048f9d8d30c3dfae1cd37333a1b39aa6adcdc49467114c9d325b11d5c988bef", + 0, + 1505833115 ], [ - "000000004ce02f1005aa6fa4d158c6e4fce95ab053d88ae74881dd080c24e057", - [ - 0, - 0 - ] + "645420bfef16e27c66be824b857eac67b045ad06be7f3af02da0ceb8472ace00", + 0, + 1505855305 ], [ - "0000000000fdaaa54cdaade8cfb75245de0747c60c0307ad11be9fe154535565", - [ - 0, - 0 - ] + "8e0d17dc4f71eeefcdd3be44378829fa040dc9b51c90a5dd5b78a9991bc4f848", + 0, + 1505939481 ], [ - "0000000003dc49f7472f960eedb4fb2d1ccc8b0530ca6c75ed2bba9718b6f297", - [ - 0, - 0 - ] + "fcc044b4942344578e5ed164dad40eb6780bcbc290f2f73d86dee80d881ae4f3", + 0, + 1506167616 ], [ - "00000000014ca604d769d4b99fff03ae3ac84d1e8eb991c5dac7c3cd4d9e68ee", - [ - 0, - 0 - ] + "6cbdc6d7e021c3921f9c57285dc7af47d678f1c071928a7e5422828ec5e5bd74", + 0, + 1506413620 ], [ - "0000000000190ab8ecef3a3d5583563851672d81a4d4d952b8cf3bd503c655e5", - [ - 0, - 0 - ] + "8f25bda4312fa8e69aafb1d9473e47aeb4aa1f8787e6949be46e9621458467b7", + 0, + 1506732628 ], [ - "00000000001204d263b607987fab11e1c19c94b7e3e674cc73cc2fb7b05fbf07", - [ - 0, - 0 - ] + "70c3a4ff6ec718257ba940c48a85ff7312cfebe2b52d2e06dbf95b25462f9fdb", + 0, + 1507077945 ], [ - "0000000000141e8d7f7ac359a8ae58e35ce6010c25ddd6f1881f41c0b939332e", - [ - 0, - 0 - ] + "951d285017cb9385ac11b707adbafd5dac65fdf6038ccca26eed3047cc36e3f1", + 0, + 1507391141 ], [ - "00000000946344dd06ef5ddd13fb74f20c475daf911ff4e3f1dcdf64c330e274", - [ - 0, - 0 - ] + "d49edd271268efee9d30832468c0c25fb7fd16788ee2c65e9957b4920f930927", + 0, + 1507675477 ], [ - "00000000ec77a7892e48b85bcbaf404d16d7fc93747d7e9e3ba6195a9b6f1525", - [ - 0, - 0 - ] + "50f628962e3786bb6429bc5ead30603695f8c8a3ad22404377e61c462733ec53", + 0, + 1507958942 ], [ - "0000000018a305c04dea8e93e423ce9569872e0ec5af49d23a0e3872b0ad6297", - [ - 0, - 0 - ] + "bd15f130f8d1ce7546b33a15c1786e9c5cf58882e197aa21aaf7e6c1df47f831", + 0, + 1508251619 ], [ - "00000000055e32c5f8a86c9a712eeb6440bbf9810ae6da12d0cea2493138a885", - [ - 0, - 0 - ] + "122ba36eeaefa3a495741ed988c61fd0baa9811108745a93e9ef1b6ac074d3c0", + 0, + 1508549611 ], [ - "0000000001913fcbe67badbce4234e86e35a1ea867ecd69814b5f5ab039b7d4b", - [ - 0, - 0 - ] + "90ee4052c6b3cc4474041b399f9de1e7111280827dacaba16385e10d920a74eb", + 0, + 1508556022 ], [ - "00000000002c71fe4403aee704720ceafd21f9f8c9c97a8bfbd25bb46223aa40", - [ - 0, - 0 - ] + "458926783d9204d434a126448f7d23a687643fa10b9366f35307a87afab6d26a", + 0, + 1508560990 ], [ - "0000000000343a42da0c811836d0785c272591facd816f0e7fdcfb1109d8f9a8", - [ - 0, - 0 - ] + "989cc92c146d06257510879ff097d7612b75d26cb7fc59a8bde44647eaf776a1", + 0, + 1508565525 ], [ - "00000000000309b182608b3eea7fafd0d72e3c79a0a3a9cda03cde3947e332e1", - [ - 0, - 0 - ] + "cb13a3217dac25ea8fc93ac6a26a3277bdb738fabf5a95969176b3b082574d09", + 0, + 1508570875 ], [ - "00000000000204cc04e421c3958a64d7bc024a474ce792d42ab5b48a5a6f3927", - [ - 0, - 0 - ] + "fde843237c2e4d63dc489629e64197d45646216317811e2c52104826487060c2", + 0, + 1508576170 ], [ - "000000005eaa010e7255bd37e0b00780575074a74d889e17c4dbc578f917348d", - [ - 0, - 0 - ] + "4a453857d6fef29856fd8824d0efcb8670499513fd6474106610e5f19c4d7712", + 0, + 1508593698 ], [ - "00000000a0d425f62d9196c069286dc6635ded9d027de40070d397e45bd63e0e", - [ - 0, - 0 - ] + "d661e4b940672c07d1caa8622eb3c27cb513a90eff079ef6f8cbbb63d68325db", + 0, + 1508660981 ], [ - "000000003355fd37068ce2d5d2a94ef964eeb9b687f21f4a00850a3e6cc4a71f", - [ - 0, - 0 - ] + "3196b5c73bbe4743e0a9f81bbc96ac8b265865365e878304b487e14e6e5d5e52", + 0, + 1508893643 ], [ - "000000000ca9148dabe9424cd8c96860c90d836ab25970a3e91856764e2e640c", - [ - 0, - 0 - ] + "ae05edd6255a7ab91915a6c1f304fd546e5111be5987b17a36c9b7240872c242", + 0, + 1508903759 ], [ - "0000000000bde23f829dde8edef35436be4b8978da21fd2c3a8100ef5334e3cc", - [ - 0, - 0 - ] + "9560072b185a9b844f15cc2d31993bc1acbf1dc74bebddb7a194e575afb5a539", + 0, + 1508913856 ], [ - "000000000028bb26f1427fbfabeae65d55a9e59e18230713e40f0f7c9c2dee12", - [ - 0, - 0 - ] + "accf359d5c4b288c0dfc55aec650eaf23395723e3072ec5f187040bcbc18ca37", + 0, + 1508923502 ], [ - "00000000002ac05422d254e597ee6b5e0f8be9b3e2f887486442d720c7766919", - [ - 0, - 0 - ] + "195a8ef9de9e7b9406ed47d120066fd995d80ff6733c86f177e31781f3582a7e", + 0, + 1508933161 ], [ - "00000000000e36d0b6f187dd9601b1d1dcd987c3e0f6a081ffd039c7c5e32462", - [ - 0, - 0 - ] + "fb5133b6ea27d54d19030ca5f5a8d0b2ba07328db8ed48807a1c88067794f611", + 0, + 1508942548 ], [ - "0000000000048d7b1f2a2a11fda34a5cfeea067ab03e482931e5a0f463f438ba", - [ - 0, - 0 - ] + "6a7451b1da111502846ce31817bbb41e406d2addb470ac35a11bc02f1c145be4", + 0, + 1508965207 ], [ - "00000000f780ab88c8a4f4247573a749fbb087a4e3fb6a7d29926de8a9ab3462", - [ - 0, - 0 - ] + "97a5da8ddf783e92723d8f144ccfb298fb71aa5500a0866c52d8603951d500d6", + 0, + 1509054503 ], [ - "000000000313bbe6a940e6a8c40ba091aa1ebbaad135bbbff3ed8ae07cf574d2", - [ - 0, - 0 - ] + "25f511ac099be0a19fb6be5310213b30b2079a0261ef996c4fbac368fae8b6fa", + 0, + 1509295929 ], [ - "000000001d4ab29721aa2722482562670a0d71dc1eb73231c5dafb64756b04e8", - [ - 0, - 0 - ] + "1d93a96e4f9167e5ce92c06875f0e40d27b50b5a93268b91a7d6a5a31fe87f06", + 0, + 1509849489 ], [ - "0000000006588bcbdec38d19962b96cf0352cbf1b90f3379cc6787d018cdb96d", - [ - 0, - 0 - ] + "4af6bbb0c7cc6b713ed198e2fe843eb157f21ef7d819ced11ed1dabaa7154002", + 0, + 1510031044 ], [ - "000000000022e79539a21ac24f9daa2cbddf2bb4a3125f88a5efc20d13ea856b", - [ - 0, - 0 - ] + "36d45e0e2f66f44161ff60e71f8c8dec910c4f09a04bbeaa742f4cda6512f4ed", + 0, + 1510665766 ], [ - "0000000000dd284b7fee584cc578a10fbe57e8efe6bf6ebacb23c0ac5d46cdf7", - [ - 0, - 0 - ] + "2abf82b0a4e5934b1358463b4bc31e50ba4ef14cbcab91e77a14dd4b44c08053", + 0, + 1510736546 ], [ - "00000000001451143787f411c93d5506065c3fb597966f2fd7a4a5c078ee6aa2", - [ - 0, - 0 - ] + "54915147123860724f1123295b47252cfeda0169cd073524c1bbeaa171a97943", + 0, + 1510811445 ], [ - "00000000000ca977394af1e414dc1f9d83efa007f7226e11d3a00f59a1fdfad1", - [ - 0, - 0 - ] + "5d8c25eec3e9d247007280725d712091c0b59c72d19121fa961a1294833b9fc3", + 0, + 1510836356 ], [ - "0000000000011f8caa80580e7a796bbce5b84e60731bf48e03c6ff5c6bba868e", - [ - 0, - 0 - ] + "490d07773a8f44524d7e9515be56f95bbf25db3c75c26de5fac0691751d5c9b4", + 0, + 1510937948 ], [ - "000000000001705beb1376af1af08b437acef6befbe7d3b60c5fbaf6bb7f38c9", - [ - 0, - 0 - ] + "d76907b5f14aa52c454ece23f9ef8b1b943220eeadba6cf31223968f6f83758e", + 0, + 1511172624 ], [ - "000000000000c838f1f45422d93ca9b5838368a37423efa8439ee24b2bf247a2", - [ - 0, - 0 - ] + "e2a7ca19f416fa0322e485059d09f262bf0c760abee1276eaad3fbbd9268dee2", + 0, + 1511425493 ], [ - "00000000000111ad857d31d07fdc8b32d17af2522c18bdaccfef449b29d17362", - [ - 0, - 0 - ] + "c384f0c07d8bb7609f344b91fedc4c664423fa27b138121bd1168e91812110b2", + 0, + 1511750602 ], [ - "000000000000312a7718fc616b0ecfdbf6066f71ec1a4a8c43f50f02f61cc398", - [ - 0, - 0 - ] + "aaed18fed1a4c7a2b4c9e5c194cdf86aa22f5c65a9541b9c4cbd104c59e1fe19", + 0, + 1511764732 ], [ - "0000000000007d232b217a59b804ef67091c5720a5460c2c16bf97b97a24801e", - [ - 0, - 0 - ] + "aeb3d1cdb62a6ab51b0d9e27155c86c6c0702f225eba44c47cdd8ab4482c89b0", + 0, + 1511786043 ], [ - "000000000000177235c33695aced585685b4c500eb76e72caad02e17503900eb", - [ - 0, - 0 - ] + "6a735b5812a4cfb558ff3e3eeb6f012768121d17e0f269e9dd38e8f2a35c0e63", + 0, + 1511811517 ], [ - "00000000000037f5c5890da7a8e2acd2b0669ad7db648ac43140c637a1c81637", - [ - 0, - 0 - ] + "ec498d0508a46af973abb5c8473672360dcf08dacd6f702988b524e3db6424af", + 0, + 1511907405 ], [ - "0000000000002123904063f223bc35135c426a4f9a0b74c1907e837b810f0321", - [ - 0, - 0 - ] + "814ad78f99524088fa312702e9ea67cc3125fd84f6713442362df8816af32420", + 0, + 1512446876 ], [ - "0000000000000961db809da357d91a9341170fafef9f24896d8730bd05cf3f96", - [ - 0, - 0 - ] + "cc87089c316fc639eb7403269dacd9445f96aa8083f3fabc1c87f862e4f619f5", + 0, + 1512511314 ], [ - "000000000d2e8fcd05eb874e98cfc3a6e239f6974950e6f50b0487513ecab760", - [ - 0, - 0 - ] + "81c544d05c0893b62ff75e6d3828ed8a565c3d95b7290a3f9b714bb9c5ee24cf", + 0, + 1512668729 ], [ - "00000000017e362508c8db23fae0431eaed708d9db13e48fd5d318066bf6733f", - [ - 0, - 0 - ] + "5be3e23cbba3ccfd79ca9b38754574ba8a3829a7af4c8b5635f3d221c45cc7f9", + 0, + 1512807779 ], [ - "000000000011b2bc4fe36f90b7ba5a62f974db250bfdc285b70c71148023c7e3", - [ - 0, - 0 - ] + "9512e0c6a5113040b2808a726ad20df456b55da11cf14ad428895b15434ad2b0", + 0, + 1513082065 ], [ - "000000000001be28570b378dd5dd2eb3aa495c229913b6757fe8900dfa3cce99", - [ - 0, - 0 - ] + "3ba5f489ac96e4db346442b2bd8109ca4eeb23266938aa19bc1174d69a7d5b1f", + 0, + 1513317649 ], [ - "0000000000242bd0bb16d0a5324e0b4b5a83697dabb3b4a059084557478e50b9", - [ - 0, - 0 - ] + "b9416e79c25718001ac423c8f2201651e5d02b0a773c7adfe49eb8c76b74bce8", + 0, + 1513349588 ], [ - "0000000000d8ce69d18da32ed52e503d6b5ad48d970b90545f956b2d2af2edf6", - [ - 0, - 0 - ] + "892f8da9c402aa8f12759c2aebeba479ce28559a424b4af5b4d8d14a5943beed", + 0, + 1513503564 ], [ - "0000000000366655bf0cb3dd0cd7801e0adbd26b5b441b77a9e3642597effb00", - [ - 0, - 0 - ] + "33fd9f4c6c4e4542a3744f43a5573361fbadc44223e499e5445b966a563f52b6", + 0, + 1513712219 ], [ - "00000000000dc7aa00d4607ca8374d40d1187f1c084b620edb45fc39bc8d2db8", - [ - 0, - 0 - ] + "83d7a51080ce5c2d255b2ff97014014c958bf2512c491124bcb90d7d41bee1cb", + 0, + 1513763627 ], [ - "000000000003baf60d9c6e70a765cf517f66a124509191188e9547ad09edf68b", - [ - 0, - 0 - ] + "968c97fbc02cd5f1a83efdadf45bef494b58cc6031379fe00b41222f1763855b", + 0, + 1513894393 ], [ - "000000000000e0f476893b8fb4d37e855353075fde73dbc1fe181cc956349f19", - [ - 0, - 0 - ] + "935f58e69e0dae752e2b051f1e5a3d247d89c408e521ebf56f2fbba359cacbaa", + 0, + 1514242833 ], [ - "00000000000032ed16b7de758abadf4a4fb2df7a101ff275c51f29e1555a89a5", - [ - 0, - 0 - ] + "1a667efb2bf148d822b15012c1feafa1f0a7723749c711ca24283a4a9b099351", + 0, + 1514322812 ], [ - "0000000000000a564d03f0f2fe20f6fb5f038d931f732d817641cd7fff3b0acd", - [ - 0, - 0 - ] + "a91d8a9a51700af722e8c14e05a817842b731b5cc7f079a715cf626874ca3288", + 0, + 1514498771 ], [ - "000000000000011aa4d0fdcea8d4ca85cd5d548e322e2b6abd17f8444be855c5", - [ - 0, - 0 - ] + "747a922ce3c20970de8927be185539b6224f67dee6b6c4792363bdb0af2ca8fc", + 0, + 1514513511 ], [ - "0000000000000610588540267a0eb544531047d4c8af0f21fca7cd3d96205cfc", - [ - 0, - 0 - ] + "678f2129c71f030dc67a84d514e0f876ba003f28179d567ff67998242233d61c", + 0, + 1514528178 ], [ - "00000000000002770dab5e14843149df8f76b8dc8458ed3ed2ed8a14a6e2e564", - [ - 0, - 0 - ] + "beb4554068dd2aef462957a8e29c0aec2d56a75597d71c881511969b09a9bb46", + 0, + 1514542196 ], [ - "00000000000006b70ebc9f75bd32f466602cbd4b86c3c2d2379059542bb8bec6", - [ - 0, - 0 - ] + "e8fb9985ba0fcabe870e59551756e89e7df2c388a7ecba73e66accc138b9b951", + 0, + 1514551024 ], [ - "00000000000000ef579af389fa7674f98a2371063fa8b218c5ca0ad94e21b896", - [ - 0, - 0 - ] + "5ce74447071a2bd566dae15621ef128489b14e51de5e2dfd24c7d4831bdad02d", + 0, + 1514581587 ], [ - "000000000000021b6108dc988f9153383f9501ab9001109aa87902ddd4c8a4d1", - [ - 0, - 0 - ] + "8f64b7bbcd52e073036bc27b1395a4eb8dec3dd64bce06062e7002a0b6260692", + 0, + 1514767565 ], [ - "000000000000022c02ff22bc0af5201f0e1a14a75879c494731e4fbf999218c8", - [ - 0, - 0 - ] + "895f4b8179cc6be6d1276fca80ddd217fd7170aec945fb0a5e7b73461e0b2d36", + 0, + 1515036061 ], [ - "000000000000032651c988edc1ccd08e82b888cbb8135e24a958ac0c0b640d5d", - [ - 0, - 0 - ] + "6487f0b9ebfe3b70cb713777a13aac4052ce821ebd21e8db0b0f55a60370835d", + 0, + 1515051084 ], [ - "000000000000015aefdfa0790bed326c38c358c07aac0674f5b2e771258b8df3", - [ - 0, - 0 - ] + "25fe87131d5624aaa57eaf26c1b4124c262445aaada56390964a40b4d32c957f", + 0, + 1515065475 ], [ - "00000000000000822e1534c86afef911b67d3fa20cf2b12d93d20d64005f54d7", - [ - 0, - 0 - ] + "4d4f81f73de56193863d7a8aa6d9baec1f992614a3bed2ba7b69566ae1f76b54", + 0, + 1515079878 ], [ - "00000000000000338b871276768c923b1c603fd6150bd054c2287e532e61de7f", - [ - 0, - 0 - ] + "9ef2a3513244340f7dc4ef161ce15b320b8cdb239602189a76d5c9d800406782", + 0, + 1515094753 ], [ - "00000000000002d0af52c0cae894bf836b61137ace2bd7500abd13a584c02741", - [ - 0, - 0 - ] + "a980bbd7ca94482deb4a224c8cb431856d34bb7f3d8b86fd16405824261b09b0", + 0, + 1515109848 ], [ - "000000006f8443a458f38d8731821c07a2fda0ecdbb1cf797f541844d468ce0c", - [ - 0, - 0 - ] + "70c3974624aa1586cba0a2fce7b930e4878c012dc837009837652350c157ae6a", + 0, + 1515125019 ], [ - "0000000000b6fbd8b4e227f5514979a61d8b0b918d2adc154e585ca926386704", - [ - 0, - 0 - ] + "88406b8010bf2986264ac9c4b2714dfc89365e07aa8f9f22f0f3a0e90d7c11a1", + 0, + 1515140313 ], [ - "000000000f4f5e49b10278e27d9dee15b92f9d4a257138a206831e0c00188767", - [ - 0, - 0 - ] + "cdf0ddced3d0db3b020d64211904d08a2bb323dbc3b6b79ae6b9102a0ef577b6", + 0, + 1515190247 ], [ - "0000000002c7e9769bd8ae9906fc5682e937b5c31ab5b5b86e4d70af2c15a95c", - [ - 0, - 0 - ] - ], - [ - "0000000000f68a1db8cd387e0a2f93f45149fe1ee4a230bb386313bdd42058e8", - [ - 0, - 0 - ] - ], - [ - "0000000000f0f65c360c8f0f9853ad1142f16675dc1175d61afdbef977776b25", - [ - 0, - 0 - ] - ], - [ - "000000000004f734e634156511cbef7dfefebdf317e7488aa6c2562572d7ecb7", - [ - 0, - 0 - ] - ], - [ - "0000000000002a46a7a16787e8317dc567ae26816324c2035be0186ba54d5cb8", - [ - 0, - 0 - ] - ], - [ - "000000000001a593e6f01875b77e270163538d88452779bb557df7c2607c28e0", - [ - 0, - 0 - ] - ], - [ - "0000000000004f24cfafa10bd50a452535f64be577a6161e51c7c71542f654c4", - [ - 0, - 0 - ] - ], - [ - "00000000597cce73e84b63f08cfcb9b01f5e7621752d8c8e08fabbd6ab5c0dd5", - [ - 0, - 0 - ] - ], - [ - "000000007cad379df01247771fff471bc99faea1b86218602f45ab13efc5e9f6", - [ - 0, - 0 - ] - ], - [ - "000000000d6085aab25892be49c49d6c0a3949befdc3ddce2faa46b104e1e804", - [ - 0, - 0 - ] - ], - [ - "0000000002be5996786b42d6a229093896aea9966b1854ea261e01e84da1f420", - [ - 0, - 0 - ] - ], - [ - "00000000002684b72056e270b115d80b12b2f68eac7412355287226aecd9b5e0", - [ - 0, - 0 - ] - ], - [ - "0000000079ea27efb24366c87856a9e371c56fcbd59d09d3164a5c2fc15fcbca", - [ - 0, - 0 - ] - ], - [ - "000000001694120525dba4548ca54087544da1fbefa51c38f0208d683418825d", - [ - 0, - 0 - ] - ], - [ - "000000000693e80d372938f3553151ab9d0a9a6922182591c701df739dc9a502", - [ - 0, - 0 - ] - ], - [ - "0000000002950d9cb23c8511937811910b712f73d448e6fdc2e39e029b86848b", - [ - 0, - 0 - ] - ], - [ - "000000000091c40056c6a48f33db17764af89c01f62ae653aa5e494146164cee", - [ - 0, - 0 - ] - ], - [ - "00000000001f373c47e1a39af4e1ebcd8c88411ec49d6bd520c2781564070971", - [ - 0, - 0 - ] - ], - [ - "00000000000809ca4b2170c57958709b867095b1972d80a2ee55359fbd0940fe", - [ - 0, - 0 - ] - ], - [ - "0000000000038e7bd66fc3308447b1370dbdd0661c427c512bdbc641ff360fb2", - [ - 0, - 0 - ] - ], - [ - "000000009a3325df76e2de1fc1970cc2f241fa8a41da9ad745a0d9666d9ff51d", - [ - 0, - 0 - ] - ], - [ - "000000003176e92ff837bf43a48a995c1a321b166475f586ffb4b962e0254a4a", - [ - 0, - 0 - ] - ], - [ - "0000000001ae3292e81ca3859b75bccd5bff825cd9f496efd085160c716ed05e", - [ - 0, - 0 - ] - ], - [ - "00000000033bdac4f0d36bb912fba28bb5caa54d1b611759a10f79ff3c969cf2", - [ - 0, - 0 - ] - ], - [ - "00000000004c6db7fa0e2c9f08693abfeb128c5827b511a5c46c623a103b416b", - [ - 0, - 0 - ] - ], - [ - "00000000003d87f48bb95e9431760d0c5f4f93c77d02fce9dd1673e9f5b01029", - [ - 0, - 0 - ] - ], - [ - "00000000000e214fc3d8b97571eb75d248ca29f8e25a584c33de8488ceee72b0", - [ - 0, - 0 - ] - ], - [ - "00000000000133269b7159b828700d02de770a8cbd91f3d166e6bbc95d8e0dfc", - [ - 0, - 0 - ] - ], - [ - "000000000000cc92e2dd933a08f7fd87f84451627982fb66583587858217c059", - [ - 0, - 0 - ] - ], - [ - "00000000000030708136c20c4c8216314005b3cb5c551ded33b26cf64d2ff47d", - [ - 0, - 0 - ] - ], - [ - "00000000c472a1341d479ed02f31b699e448c035049a7092670b38f4ec6121f0", - [ - 0, - 0 - ] - ], - [ - "000000000a358834d6eed41b9b7161a338aba53828111414cdea7552ed15548a", - [ - 0, - 0 - ] - ], - [ - "000000000e13e77372daea775c8358916e57ed11835899c14e5140ed9be11089", - [ - 0, - 0 - ] - ], - [ - "00000000008252cd0931f94b2465bd4f93e4bfeec6697962c5b034cf3d12cf7c", - [ - 0, - 0 - ] - ], - [ - "00000000019812cd6cde3a43831234be71e68118be24a80161349b8b327acb5b", - [ - 0, - 0 - ] - ], - [ - "00000000005865499f301adfb59f8380743e4c3b3ab220ca4eb97dc6628df626", - [ - 0, - 0 - ] - ], - [ - "000000000015f77e1e61329560a4378eb401fa5bf0ef90b0a014a4d7857ca7a8", - [ - 0, - 0 - ] - ], - [ - "00000000e9cbcbb625e8a463ba8e7f14be46ba9538ffe93338784ccad3d992e8", - [ - 0, - 0 - ] - ], - [ - "000000000fb27169efcc2873cfaac223ebb91cc5e1e5ad7e9a312d42bedf7c42", - [ - 0, - 0 - ] - ], - [ - "000000000c9c96d62ebfbf3fa4003f1d46d175140ab084dee17e8125fa40f24a", - [ - 0, - 0 - ] - ], - [ - "000000000311e3a766b1ab2064b68a344a561eb496d595126808ffb166c71cc1", - [ - 0, - 0 - ] - ], - [ - "00000000677568c82262ac3a4ca3f909bdfb0b35145ad490fa3fbdc719d06b91", - [ - 0, - 0 - ] - ], - [ - "000000000ee77ba9ab657e51fd9140f5c9b46731d9341e98188f929c97d04746", - [ - 0, - 0 - ] - ], - [ - "0000000008a67eb9c91a6d74168f3f385270fa942ea00bdd31924d1b6ea11148", - [ - 0, - 0 - ] - ], - [ - "00000000017f93c9e0026e90d579e18c83b4a8557f0c00e9b85ab164cf4466c5", - [ - 0, - 0 - ] - ], - [ - "0000000000994efa379235c03711a8e6b29895d928b5fde96cb01c02374c0602", - [ - 0, - 0 - ] - ], - [ - "00000000b3be9f23c943d71d7c7dbdf6dd672d77a712f6c83e9796a85e4379f2", - [ - 0, - 0 - ] - ], - [ - "000000000713e1089b0b2bdcba462b740c9396f822f1c73e090713978a7f1314", - [ - 0, - 0 - ] - ], - [ - "0000000002fc44d358401a7ac9ce4ddcb17f3cbac08e40242e755e60ab2292ed", - [ - 0, - 0 - ] - ], - [ - "00000000021ef2c04fd30be7049f73b9a8353ac96a467dd5f0b9c1457be1bc5e", - [ - 0, - 0 - ] - ], - [ - "000000000023b95b440ccbbdcb914172cf675cd15d6111bd7f5a436a4925d36e", - [ - 0, - 0 - ] - ], - [ - "00000000001983521dbffd1b742a6d4b5dfda3f46579fbbdd83a2ebf9a039bec", - [ - 0, - 0 - ] - ], - [ - "0000000000044d53dbea312432e68fa90dc2148946f613216dbdeec86f6a67c1", - [ - 0, - 0 - ] - ], - [ - "00000000000107667692f12d21a55a72ff1dce828f96872e36c35bfbae475a8d", - [ - 0, - 0 - ] - ], - [ - "000000000000252d1d0c01744ec25af801ef7c57e2581c95295070b6a8a85bd5", - [ - 0, - 0 - ] - ], - [ - "000000001c1da54e16dc06158677024d9e74bff39bfaec83434ac33673fcc251", - [ - 0, - 0 - ] - ], - [ - "00000000b4d0c6ae86bfdf7ba4c205fc3e6b3b6d63836b85e30e9d8bac922301", - [ - 0, - 0 - ] - ], - [ - "000000002b16179cb022bf678bd847dd6fc1908d0df04abf0c7874981eb33ee7", - [ - 0, - 0 - ] - ], - [ - "000000000e6783554aae41856424d184dc4fa061f40676efd107e6f933a25641", - [ - 0, - 0 - ] - ], - [ - "00000000005ae4acbab519895b4b523d97a09e381c9e4b044e642f73b8c0f1b0", - [ - 0, - 0 - ] - ], - [ - "000000000010372b59c9595d947064804b75ab21868dd075a3842ab7d2df6181", - [ - 0, - 0 - ] - ], - [ - "00000000002f9f587ea304093be049d3142ac0c92f9c68928a4f82d12b929b69", - [ - 0, - 0 - ] - ], - [ - "000000000005d4cae51b3c76dc3c61bed0c265c4f228c0c4d1d3d147146c34eb", - [ - 0, - 0 - ] - ], - [ - "000000000001a5b6c0e0a0b485a490cb52ccdf9b22596656039b51545bb07be5", - [ - 0, - 0 - ] - ], - [ - "000000000000d723d0976338edf55d08edab995dd6283cbb688855f0dca6e8f5", - [ - 0, - 0 - ] - ], - [ - "00000000bfebfae90208a82c7fa06c0f61674dbf1e4f9162e370656c38d611bb", - [ - 0, - 0 - ] - ], - [ - "000000000c91cd144b2a92ab5024c87f70cc1d76a4a7f26a82a98c5aaad62850", - [ - 0, - 0 - ] - ], - [ - "00000000077c8114eb5cfb69c3924c699d0c70334360dd1daa95db0db4816953", - [ - 0, - 0 - ] - ], - [ - "000000000348a6443e091db8f68e88a10afad7c6e3e5392247902c4b4feade43", - [ - 0, - 0 - ] - ], - [ - "0000000000d63b70351e05829ad8a56336521b361b0d50eb7ea1f5b46c25b00a", - [ - 0, - 0 - ] - ], - [ - "00000000004658603163f0ede572120a1bbfce8d313aa282ae54d2ffd9fe9079", - [ - 0, - 0 - ] - ], - [ - "0000000000048063b410c793db34856f23acfb19a0ce72f5997fa572773378c8", - [ - 0, - 0 - ] - ], - [ - "00000000000228fb6e587fa593ff8b4764064bba8bfc2f43ba5b1f12af33d04a", - [ - 0, - 0 - ] - ], - [ - "00000000000082e3ddb75c0ea2a98922b1556ce10346f9bb0cedd97ccb3fdf62", - [ - 0, - 0 - ] - ], - [ - "00000000000005571b54d4886b44b81c21dfbefa554cd7c23430e5aeff6b5ae2", - [ - 0, - 0 - ] - ], - [ - "00000000306a603ca1a0d961e08e103a9f13f3615163c3373d1bd2a67cadc2a7", - [ - 0, - 0 - ] - ], - [ - "00000000195d93ba7ae19832b622de86ebdadf3c78f1751ef2b2e9b0e3a530d8", - [ - 0, - 0 - ] - ], - [ - "0000000000476d0d00cbc68bb20b4893f0e608b02a1e029b8c6c73e169c49e69", - [ - 0, - 0 - ] - ], - [ - "000000000051348044bc10fc05960c244c3ccd3b3b6c145ffd9958a1c8bc0215", - [ - 0, - 0 - ] - ], - [ - "0000000001e4df369203badca9aedc28c240d592b12d284ce0b0463fc7537c09", - [ - 0, - 0 - ] - ], - [ - "000000000091cc1ccd448b0ec9185618a84dea96f52477cfb9b9ca2b60cebe83", - [ - 0, - 0 - ] - ], - [ - "000000000024a50299c0ef0c6dec9c64336b6cf5c1a1b0013e22fd4fcee1d7d1", - [ - 0, - 0 - ] - ], - [ - "00000000000349248c1df06c3783d1270cd97ce7f605b9036fca0fdc2f0fbb96", - [ - 0, - 0 - ] - ], - [ - "000000000001afe6793e7427a3d780876d26eb7f2ded92563f991bf7302aea69", - [ - 0, - 0 - ] - ], - [ - "0000000000007148006e139e24d9fccc307661c9a0cbcd1af983487c2f0780c9", - [ - 0, - 0 - ] - ], - [ - "0000000000002734722a341984738177a3f6f264291424e4984f2128d921bf29", - [ - 0, - 0 - ] - ], - [ - "000000000109b02caaa95e49a477757a41a42daed40e92f54fa09e63f5538cd2", - [ - 0, - 0 - ] - ], - [ - "000000009a11c7ff8b8fa7fbff5a04c25906f701ab5bd67195736f9ccc839ab9", - [ - 0, - 0 - ] - ], - [ - "000000002b1d77f8e0cd60af1c62ef6d381e8905665b15a7fbc546d0c1a45e18", - [ - 0, - 0 - ] - ], - [ - "0000000002588cb017de9e2f23cea7edc5082f1b3faec890f9252d556efeac40", - [ - 0, - 0 - ] - ], - [ - "00000000008b07f177adc24a4b1a64d2dbcfbcc903ba861d493e11d6b33af7dc", - [ - 0, - 0 - ] - ], - [ - "0000000000bab8db5020aa8e052165275e8eb3e7c843533246bf6e4c8374757e", - [ - 0, - 0 - ] - ], - [ - "0000000000138488fdca8bfc327e6dbd6c72c5f1dc5868d9c0ea886665b9b56b", - [ - 0, - 0 - ] - ], - [ - "0000000000094021fc954efbf08be667fef1b817e8715d4093a561fc30264aa7", - [ - 0, - 0 - ] - ], - [ - "000000000000e8183e64072db79adfc6c09b650c4178001be3fade4050b06005", - [ - 0, - 0 - ] - ], - [ - "0000000000004c93e8661c75974cd191c68dd66999da4f70d039c0ba4a12b970", - [ - 0, - 0 - ] - ], - [ - "00000000000021c675b3ec404bb996f5e68f9eeceeac6946e5a6822987824d33", - [ - 0, - 0 - ] - ], - [ - "0000000000000ad85684d30f25d1ec34638f099df2f33b418a07307c68fe3c2d", - [ - 0, - 0 - ] - ], - [ - "000000000009c6add76ac42a1942c4ce74d25d1b8975d4e3ac8932185e785a44", - [ - 0, - 0 - ] - ], - [ - "000000001e7d828d354716881683eb6fb5caec5d91afce298e4e3bcee9574924", - [ - 0, - 0 - ] - ], - [ - "000000000a0e438ab203d8fd3e56100f2f14759f704bff6c699df0bb4e9aad64", - [ - 0, - 0 - ] - ], - [ - "000000000b7d5c2895df8bc1fdf5d31e0f663564cb5cff3b18642c44a71b6248", - [ - 0, - 0 - ] - ], - [ - "000000000193209ecd92fce00a75975446423d94a325ed525c15d5ab921da273", - [ - 0, - 0 - ] - ], - [ - "000000000020835bdc30ac67efdbc785d15186914bc14e86387f97450df46418", - [ - 0, - 0 - ] - ], - [ - "00000000000c9078321f0030214c75e170b01ec664d39bab1b1e48460a54eb63", - [ - 0, - 0 - ] - ], - [ - "00000000000ac68b63d486ade190dc9108eb3730d25e7537649fe21c30e0121f", - [ - 0, - 0 - ] - ], - [ - "000000000002a94dfc5f4b677b251a7a7647dbb99c0803df8658222227fe3e3f", - [ - 0, - 0 - ] - ], - [ - "000000000000b076bbef0e50593b1595ffb3d571e7ad95dbdf06dca8824ef7f3", - [ - 0, - 0 - ] - ], - [ - "000000000000167075c8bcd24233d25cd268271c0e8fcb6f301ee1b6f6ff0341", - [ - 0, - 0 - ] - ], - [ - "00000000013107aa587bcf12ac445330ff0325d73c5253f7e6a49ed8c50257bb", - [ - 0, - 0 - ] - ], - [ - "00000000090ff53d49c9ffd51511af8d5cba2038a8e25e3b17186b1bc941f43d", - [ - 0, - 0 - ] - ], - [ - "000000000d9e704d5607f77f8983cc56069571a3761d5bd5da55f05ec5d8e844", - [ - 0, - 0 - ] - ], - [ - "0000000002b2b4c0950fb6390f0ae860840e84eb0a82e5e8a9bc37c14bbf43b0", - [ - 0, - 0 - ] - ], - [ - "0000000000be10137a2434dce1d97850b768ce878c1c80ec905f6e9f21e65fa7", - [ - 0, - 0 - ] - ], - [ - "00000000005cd966f80183d4c048e63a5c14f649298dfd261d989d9e3c026bf4", - [ - 0, - 0 - ] - ], - [ - "00000000000e8f30e55006a4082380c4b1a372b7ad919d3a9b0a52fe5ee881d3", - [ - 0, - 0 - ] - ], - [ - "0000000000018c70a4c27bdba237ad19ebae5d3ca23f1394ccc746d73669a1c4", - [ - 0, - 0 - ] - ], - [ - "0000000000022acc8432c883953227786f7a6560aeaf0176d232c8affa5b25b4", - [ - 0, - 0 - ] - ], - [ - "0000000000001854e95b28b4efcb2cfeb08c76d8cf1fb03f2055b3fb758f3a1c", - [ - 0, - 0 - ] - ], - [ - "000000000000187080c2c39f5a3ea8be72ac4d3ec0d16b21cd34f1541bef23be", - [ - 0, - 0 - ] - ], - [ - "0000000000001593766a3c63b524f658ec7690df467cc7bbcebbdb56385500d4", - [ - 0, - 0 - ] - ], - [ - "00000000000012d6966dc51a41f2c617192169ec8418405e164ba83b9f7ecdfe", - [ - 0, - 0 - ] - ], - [ - "0000000000001d0c7d0a2605e127b00448b71e756ad96625116ab8ca18f74900", - [ - 0, - 0 - ] - ], - [ - "000000000009cb439ea49282d257595ad1f7602856c16cc26fff423f7783c792", - [ - 0, - 0 - ] - ], - [ - "0000000000889282b98336c994d7420a639221e0484b511227fd616d78dbd028", - [ - 0, - 0 - ] - ], - [ - "000000000071a4a2ad6767864bd21239c74c9912a40ca9fd3b209e21b66460d9", - [ - 0, - 0 - ] - ], - [ - "0000000000f3ed2c3c9a7c3a7291e859cecba8cf9243d23a4892e6be8ea9b70f", - [ - 0, - 0 - ] - ], - [ - "00000000006a4258ffdff8b7f6f4f685ce18c6eb1d7a1cf501ca9e02fcb7620a", - [ - 0, - 0 - ] - ], - [ - "00000000004af78f1a109d1267a9c24d69c6a4b30fea49f0efa6c8834cf394f9", - [ - 0, - 0 - ] - ], - [ - "0000000000193bf3efbb145747198470a81b2cd33c991057676742d5c22a64b2", - [ - 0, - 0 - ] - ], - [ - "000000000006b436798c7e4a8c3bdbf054a66707feee5a18ce9ca57eb95bb48a", - [ - 0, - 0 - ] - ], - [ - "0000000000001db50c7caa3a02ea4f173343f958f334a8bf3f8638add9e69b34", - [ - 0, - 0 - ] - ], - [ - "0000000000003c621629cc0bcec5968d61d2e42c6673de4d46555118ad5001d8", - [ - 0, - 0 - ] - ], - [ - "0000000000001262bef2918265f6dd4534013a4650444054fb4f5e490c5ed57b", - [ - 0, - 0 - ] - ], - [ - "0000000000000120ceee972d70cc84430006645997c7337976c673bd75cbef2b", - [ - 0, - 0 - ] - ], - [ - "00000000ba16134dc0c418a116b97ad5deccd6bf6e3daa028a8a6a80d7823faf", - [ - 0, - 0 - ] - ], - [ - "00000000a1a00d6d6fe0660e63402a5a7c7248589211594d37fd800456ce84b6", - [ - 0, - 0 - ] - ], - [ - "00000000394766cec78f962c29aaa715b66e3ad34e1f2323dba45e087cb3b395", - [ - 0, - 0 - ] - ], - [ - "0000000008b15a3020676f5e084210ecc05f646885eca1cf6a10e9ae9e3995cc", - [ - 0, - 0 - ] - ], - [ - "0000000002cf7eb98abe784f6e516670a88b9028a6faabfd099a364c2dc5c42b", - [ - 0, - 0 - ] - ], - [ - "000000000054015fec337a9ee43eea501d2292f031f5bc1f09758d20f5cd3135", - [ - 0, - 0 - ] - ], - [ - "0000000000068d24d31a9f1192d848155a2f90939627bc456c9a337135a923fa", - [ - 0, - 0 - ] - ], - [ - "000000000006262bd09358258edcc455f9ba46b7f9d6e69d0f6b9da89488a4a5", - [ - 0, - 0 - ] - ], - [ - "000000000002327bf77ae67961463ea98a78dab06c24ac7d58b1727c5f856626", - [ - 0, - 0 - ] - ], - [ - "0000000000006672235c1606fbacd7861b16b267d203b4d687708eeb1fc25e6d", - [ - 0, - 0 - ] - ], - [ - "000000000000ac0c9a39a47313a8715f125c46d6ea8be8741b99b1db4a8aae47", - [ - 0, - 0 - ] - ], - [ - "0000000000007e93f6578e7856aae0ecf6341e1312664d9e1d812ff254c37ae6", - [ - 0, - 0 - ] - ], - [ - "0000000000002a980acdb1443926875e7d4a57859b2b45ce3fa92c7716319f62", - [ - 0, - 0 - ] - ], - [ - "0000000000683bfd82c63514bc58a80daf699a6bcd040bb2a499540baf52463d", - [ - 0, - 0 - ] - ], - [ - "00000000373e6262928d7a6cac965b294aef35f90b72c85100ef91501775e06a", - [ - 0, - 0 - ] - ], - [ - "0000000000f7bc44061b65c62d4d7747138df127dd2a30f583c3ebb66a25c7a4", - [ - 0, - 0 - ] - ], - [ - "000000000212a71c38d0e13ab7c5646c949d4b7ca23afedbe351a43b7607043b", - [ - 0, - 0 - ] - ], - [ - "0000000000a836e88f76ee5dcca1e884572f32f4460a3b024280738d76e98ced", - [ - 0, - 0 - ] - ], - [ - "0000000000413f6c1b1c9841961636bb3290f2410ba0731f3522c4ff3faa2e0e", - [ - 0, - 0 - ] - ], - [ - "0000000000082336107412226110ab2a53016d4faad4deec048828507a300248", - [ - 0, - 0 - ] - ], - [ - "000000000000a91e7a3f35a23f01621dd051e314da617714991467131808d3bf", - [ - 0, - 0 - ] - ], - [ - "000000000000cd6576950f6f238227c3ba7f62405ed1bf3af4878c6dc1b04635", - [ - 0, - 0 - ] - ], - [ - "0000000000674099e9741e44da03e9531402a2607a19a65660b57470340828db", - [ - 0, - 0 - ] - ], - [ - "0000000030c4744001ae85f9e6b46ed0664449927b86b8fbf25b22b851d23671", - [ - 0, - 0 - ] - ], - [ - "00000000002f5095ad1a12eb9eedf88ce1e7268368461b6b4e10051148f436cb", - [ - 0, - 0 - ] - ], - [ - "000000000057d3e2a77eadb8b9613cb839ab02a96094dd5d0a6d1f09026c3936", - [ - 0, - 0 - ] - ], - [ - "00000000004e0a28be887d6ed037cd9102cbbda7d6c9e584ba51f2c2dce96232", - [ - 0, - 0 - ] - ], - [ - "0000000000211346d8099f7ecea72481c4cd45591f5e0d7e347725ac2162f142", - [ - 0, - 0 - ] - ], - [ - "0000000000199ae9fc06c5acee766db6033b86f76c266cadefe1461c611c2198", - [ - 0, - 0 - ] - ], - [ - "00000000004c9e5748558d4f5a75bc824171e3b958152dfd6844330f1e907f8c", - [ - 0, - 0 - ] - ], - [ - "0000000000137addf1521361dad1ee007eb9e6dd4eb8441492ebfaa3c240d556", - [ - 0, - 0 - ] - ], - [ - "000000000054d4c77bb7964e5327c35760d87b890ea336aec5ecdeb783350738", - [ - 0, - 0 - ] - ], - [ - "00000000006b7b06d04818e97a4df66164b471912f88d9cd02de4af6c8bbe74f", - [ - 0, - 0 - ] - ], - [ - "0000000000380fa9858e3e90335c061a3776a26bee1e8b6851de33ec63670782", - [ - 0, - 0 - ] - ], - [ - "00000000000842598b03fb79ce7386e9f9181a02dcf1effc8f70d3ff7368ccd5", - [ - 0, - 0 - ] - ], - [ - "000000000003d3475edecd733fc7b82432882d9c9f1350a98ef8921b87db4dec", - [ - 0, - 0 - ] - ], - [ - "00000000000000e330a8d57a38dbcc0b0a5dc7a4210f231b8082b9be5f9e4bce", - [ - 0, - 0 - ] - ], - [ - "000000000000218ff87fd50cfba2fd04203a78d2600cb2c4dcb039d803426e19", - [ - 0, - 0 - ] - ], - [ - "00000000007c96e6e3ed3146260348ac79ea7dc2ec2ae6bf8dc203400a37721d", - [ - 0, - 0 - ] - ], - [ - "000000005abaa10bf7260470c28ba32f1755b4cfd3734aad580681e39a9605a5", - [ - 0, - 0 - ] - ], - [ - "00000000005e77c226e6fffccafa56055e68f0ea0a30101e6a243ab9b3e07db0", - [ - 0, - 0 - ] - ], - [ - "0000000000e989fe27f85b89c1e852d7bc94b09033cc6c8b32fbbbd9383a9ae1", - [ - 0, - 0 - ] - ], - [ - "000000000091a1e962438583146293ef34156962445ffc5e81e4d0fe327d37ac", - [ - 0, - 0 - ] - ], - [ - "0000000000477978a6903217e2817d10e99bdfedb4f8bc396b96fd5b0b93b522", - [ - 0, - 0 - ] - ], - [ - "00000000000bfd9e5f13a9c03c48e8b58a937cf1ae2849160f1ca11f8fcced3c", - [ - 0, - 0 - ] - ], - [ - "00000000000158dd3c31b6379887b4353ef2898c03b7ce55458fcd57cb6f0639", - [ - 0, - 0 - ] - ], - [ - "00000000000029d7009eb56b9d38366005576b82a9b59fc845522a34ad36a38a", - [ - 0, - 0 - ] - ], - [ - "0000000000e6e207a82b8ad7136352204bb8e9ccfcd25885a715d3c65cbee997", - [ - 0, - 0 - ] - ], - [ - "0000000000fadc4429f50fc534ccac4db5e51a313df25034d6c5c25f7e83448c", - [ - 0, - 0 - ] - ], - [ - "000000000019c58defcfdab6c6ab9497685e61118effda4c2613bf44be19fcbd", - [ - 0, - 0 - ] - ], - [ - "000000000006cf444d846093c5045d42ddc0986ca805f261476d0fd2eb474c39", - [ - 0, - 0 - ] - ], - [ - "0000000000d0856a3d6a1e5b1ac7e388cc029bd8410b3b1489598974fe470568", - [ - 0, - 0 - ] - ], - [ - "00000000003d9aae63ed532b78082ca5386211e22410fd24ebd5318d1a4cd1da", - [ - 0, - 0 - ] - ], - [ - "00000000000345003879f86021a6d5e3fe93813246818c145947b7e225691177", - [ - 0, - 0 - ] - ], - [ - "00000000000175393730cde3e49de7af2b81ae736eee005a9f9c4a1e878c52ec", - [ - 0, - 0 - ] - ], - [ - "00000000000087a8c621c879aec2a897258632d6aa631b9a38ba4d564e08682a", - [ - 0, - 0 - ] - ], - [ - "0000000000002ea641b2975935bd9caf337b51ac9f9bb90a54f6ea6ee5d3112b", - [ - 0, - 0 - ] - ], - [ - "0000000000000c544f9b6a8cbab6d25caf949875622bf75139234850b10affe1", - [ - 0, - 0 - ] - ], - [ - "0000000000000f66fc4e37232a29f3389c493863a980d58a1d570eddd5268999", - [ - 0, - 0 - ] - ], - [ - "00000000001213fe2bbb8aacb1fc14983586e09db964151cb507956a81b35f25", - [ - 0, - 0 - ] - ], - [ - "0000000000ba82c2160602ddc1913bc4c133ad0af8848e014367c84110d00e05", - [ - 0, - 0 - ] - ], - [ - "0000000000b7a98b364b1cf9521275a915c7a1b3a0f0c052c7d8efb620ec0870", - [ - 0, - 0 - ] - ], - [ - "000000000047dc62db23540ab4aee43e54812aedb623a2a158aa3244fc784722", - [ - 0, - 0 - ] - ], - [ - "00000000005291002da10e53c3855882251a6e5a425b5e639ef9be3bd05767ca", - [ - 0, - 0 - ] - ], - [ - "00000000005ffbcbc0d9b380584bdc78050a6f0c3582b4c9c5103a150cbc71f5", - [ - 0, - 0 - ] - ], - [ - "00000000000a7a69cc06b0a68b27a8fa5d29727ec3b6db8d32d61cf7489b5ff3", - [ - 0, - 0 - ] - ], - [ - "000000000007212eb8c49758d98cefaa6098da2b877a6055be341f5f7c0ad301", - [ - 0, - 0 - ] - ], - [ - "000000000068d1099d8cf3f43f6d164f2925b1d52ede75640cc65ca020e1de1c", - [ - 0, - 0 - ] - ], - [ - "0000000008d5ddef4468a4414bd08184c2eba0ec536b85a743b1091828a6a884", - [ - 0, - 0 - ] - ], - [ - "000000000acae40db93b589783b0cde70b98552955cb3c12f08de1b417d9008d", - [ - 0, - 0 - ] - ], - [ - "000000000066a51eaa3a54036f338719da3d5779180c0bc3787b533410de90e5", - [ - 0, - 0 - ] - ], - [ - "00000000008b521677a6e897950aac69640e52efb01b7af10bba3820ecd09a89", - [ - 0, - 0 - ] - ], - [ - "00000000001823f0e399311cab0fcf57403e094feebf99b22030bafd2004da87", - [ - 0, - 0 - ] - ], - [ - "00000000000bf821c2abf5bcd00ca96439ddf5b0b593be5601145fda5338efdc", - [ - 0, - 0 - ] - ], - [ - "000000000003f4fd19b2af0141289177014ecc6dce6ea8fb50bab93d4a291095", - [ - 0, - 0 - ] - ], - [ - "00000000000011842d892a02e55ca594caddc9f3cea1979ddffefc070eda8498", - [ - 0, - 0 - ] - ], - [ - "000000000000208aa0259d20f51c0e7b8895e18a93aea79af9b3832e710ef134", - [ - 0, - 0 - ] - ], - [ - "00000000000007218f849e72dee1f7fb6fcf36f3b6745c6468187ed2ed13287f", - [ - 0, - 0 - ] - ], - [ - "00000000000f79f656cae641c2b74554c6ecd673c0c7550671c4c2af940661b3", - [ - 0, - 0 - ] - ], - [ - "0000000000199b4d178c05fd1c3154c9a4632eadc7bfc734c4522176c977ce8a", - [ - 0, - 0 - ] - ], - [ - "00000000085d0682d481635cb2e6de2e4d9884589455a86194f0b222f9acb3c6", - [ - 0, - 0 - ] - ], - [ - "00000000015972a5a6786a14b009bf582c4bbf7b9854591dd8d26f82b43ddaef", - [ - 0, - 0 - ] - ], - [ - "000000000064bf72b7bdbfcbe96dbbd0efcaf7aa94c0f92cb4e6662819468fe4", - [ - 0, - 0 - ] - ], - [ - "00000000003df36b7962bb4ad62266c462382eddc93f4bfeac464b95f7a89ee9", - [ - 0, - 0 - ] - ], - [ - "000000000006516d3a9f424eb61db5dfb85aeee29708b78c65d24827bd926263", - [ - 0, - 0 - ] - ], - [ - "000000000001c1709fe1b294712638db356e89155650f6fbecde79ec47a92af7", - [ - 0, - 0 - ] - ], - [ - "000000000000dfc23251344b593c16c28cd195abcb337519d7bc82175721a033", - [ - 0, - 0 - ] - ], - [ - "0000000000000aae2dd2bf0b8581d137fcfa3d9c4cadbe3ef3834d7cae4268c0", - [ - 0, - 0 - ] - ], - [ - "000000000000092a5baff3d9a5ae87689b2afe668e71bac3b342c7d383f0060f", - [ - 0, - 0 - ] - ], - [ - "00000000000fa906eeff7d2e126698d88b8cda01d32ea2c039c26984daaa17a3", - [ - 0, - 0 - ] - ], - [ - "00000000002d4315e5bdc2bcfdb245b914130764a50943a2b2e02ea3acf5c47b", - [ - 0, - 0 - ] - ], - [ - "0000000000fc2bc9bb83e04cbe922d64719295bfef6320027725402306bcf1a0", - [ - 0, - 0 - ] - ], - [ - "000000000142690e7c334b97612746d6db208e6153bdfa8479d86d1b575feacd", - [ - 0, - 0 - ] - ], - [ - "0000000000629a7820e8cdbbed18dcfe16c992152badc745ca73b9b34e53fb0d", - [ - 0, - 0 - ] - ], - [ - "000000000023c2e9dbf3fe03248e40f4ec3fb2dc81ac573d5a6a4f490c701877", - [ - 0, - 0 - ] - ], - [ - "000000000013658a43b6d1c4be95fa36e32d3edf80716de3a8f7e98858016adb", - [ - 0, - 0 - ] - ], - [ - "000000000007c847295d8c4b6da9d8a64b57c3a2307e64387bf8882b9d35d6de", - [ - 0, - 0 - ] - ], - [ - "0000000000032bf90b823332af80bd2ea18f411f081c7dca8f2fe79d9215526b", - [ - 0, - 0 - ] - ], - [ - "000000000000001bc0655da6f24c6952e811006897a0c6dd8b6bd94f178636c8", - [ - 0, - 0 - ] - ], - [ - "0000000000001e1d09b15393190cf686e25488db7fcbc2f1ebacc8165fe6e3a0", - [ - 0, - 0 - ] - ], - [ - "00000000000cc79ae066badb4157def4067057cefd705bf87f1d832845a7ab36", - [ - 0, - 0 - ] - ], - [ - "000000000014408398244b94b4eff6b54875802ede6df2d1d21915333a195719", - [ - 0, - 0 - ] - ], - [ - "0000000000114135a1bc757110c05162fa649b694db9569be117e34832c87257", - [ - 0, - 0 - ] - ], - [ - "00000000009b15fb2bcee1af904989ba0761e4cddc6b3ee214c0bb07dac6211f", - [ - 0, - 0 - ] - ], - [ - "000000000012be506dde2c54adf355bdb41a457b0abec436202a3be73f0b052c", - [ - 0, - 0 - ] - ], - [ - "00000000000963760ceb5fc65570650d494805e05c9d753f3ea6d44247ad3d08", - [ - 0, - 0 - ] - ], - [ - "00000000000bfec54977673f68b6fe5f088398e697d778fa7987f8bab6a70825", - [ - 0, - 0 - ] - ], - [ - "000000000000e7f428bb413c17032c0031af0d26133ba93f744a5a0c16cf7e1a", - [ - 0, - 0 - ] - ], - [ - "00000000000036bc80378323c6eaff8ab350b6d89955f602960cb7c93d2feb4c", - [ - 0, - 0 - ] - ], - [ - "00000000000f0d5edcaeba823db17f366be49a80d91d15b77747c2e017b8c20a", - [ - 0, - 0 - ] - ], - [ - "00000000001ff8fd57798082ab5a7452ada211e1c3be38745155505601498829", - [ - 0, - 0 - ] - ], - [ - "000000000020f960b535eac585e5810ad64f158c1142f0eecd925c8058172933", - [ - 0, - 0 - ] - ], - [ - "0000000000067bd89409368d221507a160e5c45972eeb01efe210054fe8e7d85", - [ - 0, - 0 - ] - ], - [ - "00000000003521f2d5ea3232d4835ca6c6bae083ba90458f67d4cd765ce93b09", - [ - 0, - 0 - ] - ], - [ - "000000000005ab3ff3a0c484eff7b571fb78ce27d93f77a480074232e5ce0c1d", - [ - 0, - 0 - ] - ], - [ - "00000000001048c9eca7cc1cbb86946c04498052071f7e7c775bba565ada337c", - [ - 0, - 0 - ] - ], - [ - "00000000000154caacde41be616f924d7d478812148242fba85605eefec9ac61", - [ - 0, - 0 - ] - ], - [ - "000000000000c34f75bd6f338c0206a31a8d5021cc2ded51e88a6ef4fe686d10", - [ - 0, - 0 - ] - ], - [ - "0000000000001e0581d86c49a6ca14ba88639ef908abb09210b57989e06b1a1f", - [ - 0, - 0 - ] - ], - [ - "0000000000d0e6dc0bf830b50bde3e400e16ec4f772f92a55390e62d4aa73af3", - [ - 0, - 0 - ] - ], - [ - "00000000069c2501a2f32cc69af72a602ff674438ae04dd05516f72a71b9ab26", - [ - 0, - 0 - ] - ], - [ - "0000000000c926b38954550c9b8d363ff058c2eb135eebdb3e640cfa67df803d", - [ - 0, - 0 - ] - ], - [ - "000000000011e9ad9c18e9e2095c3662af5be1e918dff653758583aa45dc8197", - [ - 0, - 0 - ] - ], - [ - "0000000000f311624ff4dcdf07400d0d2fec8b16b14c1c16babc377a2d85ad21", - [ - 0, - 0 - ] - ], - [ - "00000000002e455cabfdc2a8955e8ddfe717b12efe5b80937b0c0ad6ac977fc5", - [ - 0, - 0 - ] - ], - [ - "00000000000fed8889a22339b340f599ac7908e790bfc3cfca9b78078a52d228", - [ - 0, - 0 - ] - ], - [ - "0000000000012ca4492956b3f859b00e5db14b54d422cd95c68c7150743db365", - [ - 0, - 0 - ] - ], - [ - "0000000000004c58e8f7bac59eb4a036764a4d8e0da51c0290858ab14fb72481", - [ - 0, - 0 - ] - ], - [ - "0000000000002f60bc99563ff5b4b800c176fe8bde95e8f968fd6b53d74c9cef", - [ - 0, - 0 - ] - ], - [ - "0000000000000bffd10a3fb0b5b86d8b2561f39d07f8a4c41dfa08e3e49b7db5", - [ - 0, - 0 - ] - ], - [ - "00000000000006a296be9cd8fd4e3145c146863adbe08b71831abb8a869d032c", - [ - 0, - 0 - ] - ], - [ - "0000000000000c557f496e82891039ff22e277bd604be6e2e8b95e519bee91f9", - [ - 0, - 0 - ] - ], - [ - "0000000000399b30d2111c4bf3051c1f7f2f35bba7ff290d92393341ae47df55", - [ - 0, - 0 - ] - ], - [ - "000000001f88733439e4e8d3c474504aed62037faa16f3845b4c671f69732e26", - [ - 0, - 0 - ] - ], - [ - "0000000018aa2f93d2ab76a7e2f1bf5b565b4a1b0ececb6ee46490984f6c0d4b", - [ - 0, - 0 - ] - ], - [ - "0000000005e22674fcf65ce7be896a0557205ab26d1f76d73a717f5f14a6d6ad", - [ - 0, - 0 - ] - ], - [ - "0000000000223d866b324c097973210f8fc715c9535908359d61d8e1ab2f0100", - [ - 0, - 0 - ] - ], - [ - "00000000002b321fd6452ab43849bd7a781953ec4485554e0fdc579f2a52c90a", - [ - 0, - 0 - ] - ], - [ - "0000000000173132748c51b5754b0341232325bd118455bf3c8d25164d3eb92a", - [ - 0, - 0 - ] - ], - [ - "00000000000143158cdea5fbb9453bbe1a7a900e6feba1e2193e4f5c106d9fba", - [ - 0, - 0 - ] - ], - [ - "0000000000014677751456af5630025b3d9921a4eafb4d36a06498f0c6a84c56", - [ - 0, - 0 - ] - ], - [ - "000000000000243976cf2d30ecd3cb1fd0b805fba4da92d2758f78e1c6f8ae92", - [ - 0, - 0 - ] - ], - [ - "0000000000001323db1ab3f247bcb1e92592004b43e4bed0966ed09f675cf269", - [ - 0, - 0 - ] - ], - [ - "000000000000017a410c22c4b6caf710f5ccf005d644caf276ea8626a538798d", - [ - 0, - 0 - ] - ], - [ - "0000000000170b2b1374e3a0dfdce2fbc5e302e1e0e9fb419dc057c9959902d1", - [ - 0, - 0 - ] - ], - [ - "000000000015b4fad4d929630487680cda2d3aada138c58cc08241ef6dd4ab09", - [ - 0, - 0 - ] - ], - [ - "00000000000abebab869f1620843d413a3d9e06dc7d9f5201a414d547ace1f99", - [ - 0, - 0 - ] - ], - [ - "00000000000b0bdaf05c2fe8b12ebd2372f49d8eabcfbccdadd68b5e5b7c9565", - [ - 0, - 0 - ] - ], - [ - "00000000000ca1af42ee1be2c8895d94f39dab5fcdbe0b4b4065f4be534e7294", - [ - 0, - 0 - ] - ], - [ - "000000000069d0cc8c0452bf86cff87db05232f801a162acab2d080d6e4e9ea9", - [ - 0, - 0 - ] - ], - [ - "000000000019c7f7685f5bdc3afbb5e978cb3f4f70fea7b2b410139741303b53", - [ - 0, - 0 - ] - ], - [ - "00000000000d3874ce21db78f4d1883ad9ae8b26c1d7c13f3d723ff85629d595", - [ - 0, - 0 - ] - ], - [ - "0000000000033f87c25275ff72b58630d8da90221f2c84bcbd77c8e615709f8b", - [ - 0, - 0 - ] - ], - [ - "000000000000dc72adaaae6483eb6737de7d21b3a24b2426330e80b078ceaed1", - [ - 0, - 0 - ] - ], - [ - "00000000000002fb1337228db02ac464565271f22f045c1b6ee5e449f057a829", - [ - 0, - 0 - ] - ], - [ - "00000000000001902376ff640d3088899af0819dbd15f602156a13ac2fc8e94e", - [ - 0, - 0 - ] - ], - [ - "000000000000007ee49761a1c8284a3b8acefa39e37e455be4773d648e2db794", - [ - 0, - 0 - ] - ], - [ - "00000000000005b4d495a77f57018dbc72bf47993d494349329a3c653f04ab93", - [ - 0, - 0 - ] - ], - [ - "000000000000009dcb3ae6d68828e2f5ccfd58780abb260354e74484106f81ce", - [ - 0, - 0 - ] - ], - [ - "00000000a3ceb118021fb42d39be52db951c6f852bb9a241046e972706f7329a", - [ - 0, - 0 - ] - ], - [ - "00000000574e8e1c27fa54c77b4e7cd1b79de070f0d3ad5b383206ab9777d983", - [ - 0, - 0 - ] - ], - [ - "0000000039d562f640c1743421d53e7e04c3e8ba222c339fff6f3d25b1d4a7fe", - [ - 0, - 0 - ] - ], - [ - "000000000001cb1559d55c697871e18d5c26800f77fb11587241bfbec3b15e26", - [ - 0, - 0 - ] - ], - [ - "000000000006e01a93090319756c7ca826ef655feb0cc2ef9abcc59d67de5e5b", - [ - 0, - 0 - ] - ], - [ - "000000000000a81aaf5a4c013032638a077af6aad8bc449d74daef8ad3a74419", - [ - 0, - 0 - ] - ], - [ - "00000000000087d0574963c1582f2161298e2de5e48f74566291ef9afc2be24a", - [ - 0, - 0 - ] - ], - [ - "0000000000033251e71c347cd663945fb68efe82a8c6666c0b41e93f1c46658d", - [ - 0, - 0 - ] - ], - [ - "000000000000f592857e6f0e4711b5b93fdf95f2b21a5963bde15be750a07908", - [ - 0, - 0 - ] - ], - [ - "0000000000004353c8426e18b942a5012934ddac8322b86d6ab98ed7c0ee86ed", - [ - 0, - 0 - ] - ], - [ - "00000000004f027845b699f42e7d0d30c530e99524c5f97186ce6a250a5fac42", - [ - 0, - 0 - ] - ], - [ - "000000002fc6407edc060df90785082834867331e6746a43ed34a26fbdc5df64", - [ - 0, - 0 - ] - ], - [ - "0000000000048733007c91ea3665bd4e1653b10799e3f43abee0fe830ffbb3ad", - [ - 0, - 0 - ] - ], - [ - "0000000000025a9b1c5afceba0c78c4b0320797acdc1ad50b4e040f148fbff7f", - [ - 0, - 0 - ] - ], - [ - "00000000007ca6d026d27387edc1c5570de41c61bacbcb1dad2c0f300b49e637", - [ - 0, - 0 - ] - ], - [ - "00000000000258f683a77ad509da82a4fab24188fdb4b4690e212c50794a9abb", - [ - 0, - 0 - ] - ], - [ - "0000000000015111bce7b6ac13c930484e14e31e13e43355cb4d63c8f1782440", - [ - 0, - 0 - ] - ], - [ - "000000000001ca074fdecac7749d95f28f10c83a7e13787fd865bfbe505382bc", - [ - 0, - 0 - ] - ], - [ - "0000000000001c11a6505dd44ab405fdc07ddfc015f3c1166a5d9352ab58b52c", - [ - 0, - 0 - ] - ], - [ - "0000000000000c83f7f8e1cab4efa08d6c68c4555fb6ab542e01b87edd8f56ac", - [ - 0, - 0 - ] - ], - [ - "00000000000009561d0ceba15388573d2a994aff24512ec3ed7d7881aa0997dd", - [ - 0, - 0 - ] - ], - [ - "00000000007dc7cfbbb94db1fbc076a70a1252fd595686b4d75b2ea77ed6ee9e", - [ - 0, - 0 - ] - ], - [ - "00000000000251feb68a8c90852f73aeb29ebda191038737b7edd37c9475f4ac", - [ - 0, - 0 - ] - ], - [ - "0000000000013f9a97045ea9047654e514951288911b2c3986787c27bab49106", - [ - 0, - 0 - ] - ], - [ - "0000000006e8c37735c61f22bec69f4cb7eba03172349e7012b7704652f3e83a", - [ - 0, - 0 - ] - ], - [ - "0000000001f341add5657043d8e50e53ba079fe24966a2668f904be5579c84b9", - [ - 0, - 0 - ] - ], - [ - "000000000029a6275cd477d77939424bd183c2f1308a9912f45aa7cc9ed13b56", - [ - 0, - 0 - ] - ], - [ - "00000000000a0336239e5e1faedf5bd2eedf38c9a5ba34a832356aea70aeb102", - [ - 0, - 0 - ] - ], - [ - "000000000003c1a2b25093a64eb624055f6a3a26e18b8e7ea2d9382ec7a3609a", - [ - 0, - 0 - ] - ], - [ - "000000000001bd89bf7e8740ce22adfa6e8793bd1716a647e558ed1742ee8329", - [ - 0, - 0 - ] - ], - [ - "0000000000001320421f1bb2c94000e11a621f581fc277c0e2911c3b89f680bd", - [ - 0, - 0 - ] - ], - [ - "000000000054ce90a949f5ae2d43c4ace599668c6ccbc50620f6d5705922ea7c", - [ - 0, - 0 - ] - ], - [ - "00000000200d16fea4857e6b73169cc593421a57971acdbcaf87a31d7d8d72c8", - [ - 0, - 0 - ] - ], - [ - "0000000000e75602181c88f713b91c49de291ed878be305d25b75c0ec5fbe942", - [ - 0, - 0 - ] - ], - [ - "000000000081f8169c3c3665f20351dc0fe499612ae232ec0b55858a8e5dc6e9", - [ - 0, - 0 - ] - ], - [ - "0000000000d7ad232e7593fb435d125343b8113bbdb3705ab58ac0e18c26cc79", - [ - 0, - 0 - ] - ], - [ - "0000000000076df615d887e33193ca2dc0f2fc0e70744512c95da6242e9b1a81", - [ - 0, - 0 - ] - ], - [ - "0000000000084a62093d1929843e74456686429b698a7ea9b1901c1565779f58", - [ - 0, - 0 - ] - ], - [ - "00000000000251d1da01e9de9fcaf3ca3a64bff78a5faf51a8e697dfab6b5e4b", - [ - 0, - 0 - ] - ], - [ - "000000000000609a8798996b1f1fe0b66060a628eadc380d0d369a2318c2d0ec", - [ - 0, - 0 - ] - ], - [ - "00000000000014770aeab044a022e86d888a6ede75b6474022c71aead3a1db74", - [ - 0, - 0 - ] - ], - [ - "00000000000004101d04ebc90ade5d4b911aa13c038ecf25e9887d877203ddb8", - [ - 0, - 0 - ] - ], - [ - "000000007c700410b61eb7ff1aaccbfc3a79e4e4484ad7a2b0eda4d91dc4b613", - [ - 0, - 0 - ] - ], - [ - "00000000055ff438a031413ee042fd3c0a2b69be98690542806ff123b7988024", - [ - 0, - 0 - ] - ], - [ - "000000002eca5f9f2c3b656d2550662fdee4c95da133eade51a5cae653bc69fe", - [ - 0, - 0 - ] - ], - [ - "000000000c679b76ccf0c5b943095fdee8fa466311edbea2c4a05f9430ffef3f", - [ - 0, - 0 - ] - ], - [ - "00000000007c6f494e32d5d9de58fa008a770fdc0a7b4a141be5b7c2de3ab970", - [ - 0, - 0 - ] - ], - [ - "0000000000d5dcd5a26c8ad29c1293e70401e2f90d8288469df3816b8cc6d4aa", - [ - 0, - 0 - ] - ], - [ - "00000000000d754d94f36cacbfb620710672afb1558499cabe17ca62c54a7d3a", - [ - 0, - 0 - ] - ], - [ - "000000000004096bb78fba714b130f7f1f929e2803c75a7a85619f7a2b86567f", - [ - 0, - 0 - ] - ], - [ - "0000000000020e686c38d44c35896df35f9f1b7723a82a826a5e2393c25ef68c", - [ - 0, - 0 - ] - ], - [ - "000000000000504f9af6885c0cb6484109ea205a956c8efae9557a1f5b9233da", - [ - 0, - 0 - ] - ], - [ - "0000000000000e8746e52e4320ec17e66434a3936a3825f7046fe874e92275fb", - [ - 0, - 0 - ] - ], - [ - "0000000000000f48d818a9a026270c9f733f629959bea25192596d59874b1ce2", - [ - 0, - 0 - ] - ], - [ - "00000000eaa9214cb05b241828a1cfb0c4209fb7ea64429815d61f7c1d98939e", - [ - 0, - 0 - ] - ], - [ - "000000001f7f915a6002cce4edd5cba392307f3a199a520ee8937327a9135162", - [ - 0, - 0 - ] - ], - [ - "0000000009674ee0c606d687bdcddf8e023462927e2902b3381bc4bb862a7397", - [ - 0, - 0 - ] - ], - [ - "0000000001f3f3528c083a4b11eb2f04d8bbeca92b57f05d8282909bde78bc77", - [ - 0, - 0 - ] - ], - [ - "000000000131917ac459aefb91774dbb42caeca497afc0cfd1766e0338cc7f88", - [ - 0, - 0 - ] - ], - [ - "000000000027634444081e1289354cb50034a506bb306a2ac1d8280683771c5c", - [ - 0, - 0 - ] - ], - [ - "000000000017a852acff78fbee573329d45bb8b121e9f6fc1e4f687bb3778ada", - [ - 0, - 0 - ] - ], - [ - "000000000006789e1a00eca982fb2827f680b254c4a0ecb005af4464f3585a02", - [ - 0, - 0 - ] - ], - [ - "0000000000015d2e9f54b1e9419d6b32ce68ae626cdd7f2a1954f22ca39ae0fa", - [ - 0, - 0 - ] - ], - [ - "0000000000002f7893bc169165ed9fefb434b6201103f23cc84a747a68ff8797", - [ - 0, - 0 - ] - ], - [ - "00000000000008471ccf356a18dd48aa12506ef0b6162cb8f98a8d8bb0465902", - [ - 0, - 0 - ] - ], - [ - "0000000000000596f00b9db53c4111bcde16f3781471c5307af1a996e34ec20a", - [ - 0, - 0 - ] - ], - [ - "000000000000007b5d2406f64f5f5833c063a6906552e815e603140c00bca951", - [ - 0, - 0 - ] - ], - [ - "0000000093ca5d935740a1b25f10ce092fd777c2bb521f3156619389ae78931e", - [ - 0, - 0 - ] - ], - [ - "00000000292f3a48559527341f72400a0f8a783aebcaae5bfa0e390dfaa5286b", - [ - 0, - 0 - ] - ], - [ - "000000001e852ed7ddf0108d1fce0f4f686f43c8c1b85bcb12c43e564dc7630e", - [ - 0, - 0 - ] - ], - [ - "000000000c4bea8fb1e7f3a1f3e6c6b3f71388c0ec7eef3de381853767e89f87", - [ - 0, - 0 - ] - ], - [ - "00000000029ef31a21711b55c4300efa38ace0b706091e373f48285286f2c578", - [ - 0, - 0 - ] - ], - [ - "0000000000979060786bb008f193d3917e28667bb1b28329f3adadc172e4cce7", - [ - 0, - 0 - ] - ], - [ - "000000000019030ceb98013b1627517b45b04ee055ef445813bbebaa25fa1ed3", - [ - 0, - 0 - ] - ], - [ - "00000000000adf202247bb794fc9a3c82cd8767143f1e6ed5f60940ee18b09a8", - [ - 0, - 0 - ] - ], - [ - "000000000000b19061e2481d8be6183b3d881b0d58601072d2a32729435f6af3", - [ - 0, - 0 - ] - ], - [ - "0000000000007a6d34f59b29e8d4da53e51e3414acd18527466d064945fe19fc", - [ - 0, - 0 - ] - ], - [ - "0000000000002e66ca213a2c3e9eb5fa62de29feb83880a0bd29f90fca8ad199", - [ - 0, - 0 - ] - ], - [ - "0000000000000b4ca10aa100728d0928f37db5296303db1b74ffe29e4a17b6cd", - [ - 0, - 0 - ] - ], - [ - "0000000000000143309f6b19567955743775f61f8dc6932c0b46cf5fb11c6c72", - [ - 0, - 0 - ] - ], - [ - "00000000000000b04d5409b3ac60cc18c0b9a3d58b303594635a8f75a9d2abd5", - [ - 0, - 0 - ] - ], - [ - "000000000000040a2699f62a552703a278608248c2ce823f4cd8845376e9a371", - [ - 0, - 0 - ] - ], - [ - "00000000000005cfcb850db7e83d4963994f958bae9b1de1483f5aeb3d449925", - [ - 0, - 0 - ] - ], - [ - "00000000000190f80220e70c1481153671a7c90fd856988c183ab0e3d9313df8", - [ - 0, - 0 - ] - ], - [ - "000000009374563a06178641d06776f66554c2a094b5319f0801fe35cef72ccf", - [ - 0, - 0 - ] - ], - [ - "00000000003e4e6e5e8e4a89e7de50eed104d4a49d2992ff101b6740beec7cb5", - [ - 0, - 0 - ] - ], - [ - "0000000000618cd377d14aaa441cbdb92527894f98da316eca81664f8ab5488d", - [ - 0, - 0 - ] - ], - [ - "00000000000d977ab2897885fee712f58612fce8c10ffbe9400326fe3429b77b", - [ - 0, - 0 - ] - ], - [ - "00000000000c3575b487dd0f938c5bc744fa65ca4ca3a9c981b8bda903ec110b", - [ - 0, - 0 - ] - ], - [ - "0000000000247ac689595ed8d62678bfe53e5af13c0f5455e558f5e6bb375c16", - [ - 0, - 0 - ] - ], - [ - "0000000000093d175376aa621176511f335a48f824b66d998e8082f85134a48b", - [ - 0, - 0 - ] - ], - [ - "000000000000c0c0448fe922f2c737946297d35f2c25ad7cc223e11bbe58e1f8", - [ - 0, - 0 - ] - ], - [ - "00000000000016abe4e7c10ddb658bb089b2ef3b1de3f3329097cf679eedf2b5", - [ - 0, - 0 - ] - ], - [ - "000000000000242757cea5b68c52b83dd8c2eb9257492074fc69dfa30bd4cbf4", - [ - 0, - 0 - ] - ], - [ - "00000000000006813f3dd7726a509fbe3101835db155dfd35d44aeae6aedb316", - [ - 0, - 0 - ] - ], - [ - "000000000000053cc4f39cff1c8cee1aff7e289a85dee84164d2d981afc8f17a", - [ - 0, - 0 - ] - ], - [ - "00000000000000789724805cf1d37ef689acf52c47a460507f540d5e5ca79bfa", - [ - 0, - 0 - ] - ], - [ - "00000000000003d71618bb8952887f65540270a5e54d6246b9419e08831b5e4e", - [ - 0, - 0 - ] - ], - [ - "0000000000000251a513a33eadfad67c015f6e3b291dfd0ae1cc4bb3a43006dc", - [ - 0, - 0 - ] - ], - [ - "00000000968009e3f8d6e6071e7def68298307717a9af6c2d44986deaae297d5", - [ - 0, - 0 - ] - ], - [ - "0000000062bcacb734df83bbfa3e1b9a8dfa570ecffb6c29eaaf8e9498cccd30", - [ - 0, - 0 - ] - ], - [ - "000000001d4618c0931bd3c25ee592c35341f30ff3b549a671f637b3c26ef414", - [ - 0, - 0 - ] - ], - [ - "000000000418b329df96a004f1b652ad06a7ca295f9f2e711c412d00493f5a86", - [ - 0, - 0 - ] - ], - [ - "000000000302bfb88e9027237d023c4b969e106c9a7a23a84103776de7880836", - [ - 0, - 0 - ] - ], - [ - "000000000069b9f7d9134fd93c8b7e3af8b26bbcbb5553af02fb6ed644d7fca5", - [ - 0, - 0 - ] - ], - [ - "00000000000411ec444240ee91e2777ad18b80dee854e3e838e32209e84774fa", - [ - 0, - 0 - ] - ], - [ - "0000000000007c73f322eba4dee5463305227c7e1a8139f1b7b296444f265052", - [ - 0, - 0 - ] - ], - [ - "00000000000129adf0f9c0242aedbb9d87935d67ee4ddea758c00344d4b6a29e", - [ - 0, - 0 - ] - ], - [ - "000000000000343594e671158b6e1b4b6499f6ad66e2aeabf1f6d295d3dba850", - [ - 0, - 0 - ] - ], - [ - "000000000000320f0d5c22ba22b588b97a0e02273034bcd53669b1c8c4eeda1b", - [ - 0, - 0 - ] - ], - [ - "0000000000001e8cdb2d98471a5c60bdbddbe644b9ad08e17a97b3a7dce1e332", - [ - 0, - 0 - ] - ], - [ - "0000000000000026c9994ccdd027e86f51a2e36812f754bd855a7f9b1ca56511", - [ - 0, - 0 - ] - ], - [ - "00000000000002746a820a2c08b35b8d0493c4b5d468fcc971b9c88003e84849", - [ - 0, - 0 - ] - ], - [ - "000000000002949f844e92645df73ce9c093e5aac0d962a0fa13eb076eec835c", - [ - 0, - 0 - ] - ], - [ - "00000000000156fbda67468ae2863993b98a41227c420246e4bc4e68c84df0e8", - [ - 0, - 0 - ] - ], - [ - "000000000003b43c6c807122c8dd10e2a0cffbf72946f41c97c1ab82d416f74d", - [ - 0, - 0 - ] - ], - [ - "000000000004e0635c2438b1b649007e5d424b3de846299a8db53049ebf4da0c", - [ - 0, - 0 - ] - ], - [ - "00000000000258e4b79e3cca2ab7d12b35ba77fc491572f2e794f0a10f5236d9", - [ - 0, - 0 - ] - ], - [ - "0000000000f5816875d9fece105e499b0467b8fb23ea973c48d828a235acdebd", - [ - 0, - 0 - ] - ], - [ - "000000000001353bbaec810af7a4c74b4964ae072361c0889ed6d59cf16db6fd", - [ - 0, - 0 - ] - ], - [ - "00000000000b354d8c389473670ca6bed7e3dffa069f270d35ec9dad810af141", - [ - 0, - 0 - ] - ], - [ - "000000000002fa1f39e7cd8730fa08085ba2b532146ad1ef3b400a13e835ca36", - [ - 0, - 0 - ] - ], - [ - "000000000000d2c7943eee59652a9783bff27e474a92ec206c5c6e3cdd58d0d7", - [ - 0, - 0 - ] - ], - [ - "00000000000036034181b4d9a84a97490b49fbee4262b9cfb25a7bfc9c0eec9f", - [ - 0, - 0 - ] - ], - [ - "00000000000007deb59381cce692f152fc902732d96a7e7d463bc83915b37c0a", - [ - 0, - 0 - ] - ], - [ - "00000000ea7d32833462c0f72ade0cae4766e6065caa4e510331929c56d16632", - [ - 0, - 0 - ] - ], - [ - "000000000068fce0ddd370d4c8f9129a7bc7843e75fc57666202d3b90239e269", - [ - 0, - 0 - ] - ], - [ - "0000000026b4a2212c9c9493f8bd9d5331cab6d8eda8ee017410e58a783ca069", - [ - 0, - 0 - ] - ], - [ - "0000000009535ea2dc7e83c31cd17f1db1bb78b0a678fc0610844273de143bf5", - [ - 0, - 0 - ] - ], - [ - "00000000008607cbd5baca91d5b8b82ee965aace335744a3e21578af22bee8ba", - [ - 0, - 0 - ] - ], - [ - "000000000030dcedae0f5e98c4e176f9569ce76c4d4135bb028fc3144ef381d9", - [ - 0, - 0 - ] - ], - [ - "0000000000297c3f0e3fa85731222ba934a955bf513247a72a33c74c498cadbe", - [ - 0, - 0 - ] - ], - [ - "0000000000020a0d4a1e8120cbdb486e758b58919c9df12e0edc8ca1f2795e94", - [ - 0, - 0 - ] - ], - [ - "000000000000078773afc9023182bfb6534a60158672e6bc6e8aa5052854da80", - [ - 0, - 0 - ] - ], - [ - "00000000000102ecdd67800807d9e137357805b9bbf8a439ed86bde5b19fbeb7", - [ - 0, - 0 - ] - ], - [ - "0000000000005c3d2e3c7ee737c67ab465533acb233e0df902c1525fc11c3a55", - [ - 0, - 0 - ] - ], - [ - "0000000000001a77771650cdbbceff87caa4461391ba6a4ddc9815b5b0ab47b0", - [ - 0, - 0 - ] - ], - [ - "000000000000071ec390bbd28fa2a84e52ab5b32901d0723d22646b04ae01dc3", - [ - 0, - 0 - ] - ], - [ - "00000000000005c3ec3194f710c6f26ee736d59cc935ddfa574440f39846433a", - [ - 0, - 0 - ] - ], - [ - "00000000000001cc3df6924591939269d61ead563b9eb68402a2ca01d7ff99e2", - [ - 0, - 0 - ] - ], - [ - "000000008c778b3554ceaf3a13a856acbfe46b5750fb86fd92ba30651c2852f4", - [ - 0, - 0 - ] - ], - [ - "00000000107ca31f75f8ea76073dda3c33330b2706c1ec20c3ec240e853b65c5", - [ - 0, - 0 - ] - ], - [ - "0000000006ba99b08e7f2869ce113e2ad7464891de7b4cfa96f330d706a2da46", - [ - 0, - 0 - ] - ], - [ - "000000000f31036bd51b2818f6dfb90ada9be5019abf55fb15694b181e269865", - [ - 0, - 0 - ] - ], - [ - "00000000004fcc101bc47eb7a379b9f608d5c00ac04d2d0ea165ae2937070796", - [ - 0, - 0 - ] - ], - [ - "000000000044d5ca3eda838edef0df7e69e1934047f8482822ce58ff7a18466d", - [ - 0, - 0 - ] - ], - [ - "000000000029bdfb157be6d400c4dd3370d98afdd8cd3db6f1ada8c19bbf4650", - [ - 0, - 0 - ] - ], - [ - "000000000005e9699ad8035caa4f73af781ac2040c87b8aa77459b3607209aa8", - [ - 0, - 0 - ] - ], - [ - "000000000001c0ba033f7d85beeaa167c9bde0e192240653a7ff6d9b81679842", - [ - 0, - 0 - ] - ], - [ - "0000000000000e0176111f29e800b49c7b8c7226dbbf4df715f1a4f06bcaaa49", - [ - 0, - 0 - ] - ], - [ - "00000000ac3bb2cf42192e9053f5384355228a2b3d70b4ece4d45773a5d5ddd2", - [ - 0, - 0 - ] - ], - [ - "000000000f29f7b60842b1044b2db7998e9bcbd92f8ec6fe8d159c6d582f1f1a", - [ - 0, - 0 - ] - ], - [ - "00000000352f86bc5f9760961a25de009940508bb2cd0b37f378fbc87dc97eef", - [ - 0, - 0 - ] - ], - [ - "000000000e9b3086008679ed57f59857f64c3954368ba1088117dbf88d5839cd", - [ - 0, - 0 - ] - ], - [ - "000000000015324bd8fed0e61b62bd1d6c663b862cb98ea03c494a92e4a8d0af", - [ - 0, - 0 - ] - ], - [ - "000000000020475a181b7a084b341860a72fc0c1fdfcc13a85adeb0471444b0f", - [ - 0, - 0 - ] - ], - [ - "0000000000031905c508a975707b74f24e733880382775ee0e6250666473e1d8", - [ - 0, - 0 - ] - ], - [ - "000000000000ca38b15d2ea33a6eef505a9c661540a18882f79ba9a3c575a9bd", - [ - 0, - 0 - ] - ], - [ - "000000000002739979a7a89fa279303b6606885e750b19e91ed637d7f222b392", - [ - 0, - 0 - ] - ], - [ - "00000000000091e935fc266facc2c92759d5468a39aee5be6b76b519a9bc7567", - [ - 0, - 0 - ] - ], - [ - "00000000000006e339938254208203b67c3c400f703fc29535fc646699e36e58", - [ - 0, - 0 - ] - ], - [ - "00000000000008f6f1d1150d77f93a7f1baa24b65ceb471b1825b2e92ca6997c", - [ - 0, - 0 - ] + "efda9a1f82cb5e6ac5558782ff638e492e21792530f2ee0e91edf780f152d7d6", + 0, + 1515502379 ] ] \ No newline at end of file diff --git a/lib/coinchooser.py b/lib/coinchooser.py index ffc5bfd8e901..472e3aa3820f 100644 --- a/lib/coinchooser.py +++ b/lib/coinchooser.py @@ -87,8 +87,6 @@ def strip_unneeded(bkts, sufficient_funds): class CoinChooserBase(PrintError): - enable_output_value_rounding = False - def keys(self, coins): raise NotImplementedError @@ -137,13 +135,7 @@ def trailing_zeroes(val): zeroes = [trailing_zeroes(i) for i in output_amounts] min_zeroes = min(zeroes) max_zeroes = max(zeroes) - - if n > 1: - zeroes = range(max(0, min_zeroes - 1), (max_zeroes + 1) + 1) - else: - # if there is only one change output, this will ensure that we aim - # to have one that is exactly as precise as the most precise output - zeroes = [min_zeroes] + zeroes = range(max(0, min_zeroes - 1), (max_zeroes + 1) + 1) # Calculate change; randomize it a bit if using more than 1 output remaining = change_amount @@ -158,10 +150,8 @@ def trailing_zeroes(val): n -= 1 # Last change output. Round down to maximum precision but lose - # no more than 10**max_dp_to_round_for_privacy - # e.g. a max of 2 decimal places means losing 100 satoshis to fees - max_dp_to_round_for_privacy = 2 if self.enable_output_value_rounding else 0 - N = pow(10, min(max_dp_to_round_for_privacy, zeroes[0])) + # no more than 100 satoshis to fees (2dp) + N = pow(10, min(2, zeroes[0])) amount = (remaining // N) * N amounts.append(amount) @@ -380,6 +370,4 @@ def get_name(config): def get_coin_chooser(config): klass = COIN_CHOOSERS[get_name(config)] - coinchooser = klass() - coinchooser.enable_output_value_rounding = config.get('coin_chooser_output_rounding', False) - return coinchooser + return klass() diff --git a/lib/commands.py b/lib/commands.py index d6c71a8a7879..8f3b67751a75 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -34,7 +34,7 @@ from decimal import Decimal from .import util -from .util import bfh, bh2u, format_satoshis, json_decode, print_error +from .util import bfh, bh2u, format_satoshis, json_decode from .import bitcoin from .bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS from .i18n import _ @@ -81,8 +81,8 @@ def func_wrapper(*args, **kwargs): wallet = args[0].wallet password = kwargs.get('password') if c.requires_wallet and wallet is None: - raise BaseException("wallet not loaded. Use 'electrum daemon load_wallet'") - if c.requires_password and password is None and wallet.has_password(): + raise BaseException("wallet not loaded. Use 'electrum-xzc daemon load_wallet'") + if c.requires_password and password is None and wallet.storage.get('use_encryption'): return {'error': 'Password required' } return func(*args, **kwargs) return func_wrapper @@ -130,8 +130,8 @@ def create(self, segwit=False): @command('wn') def restore(self, text): """Restore a wallet from text. Text can be a seed phrase, a master - public key, a master private key, a list of bitcoin addresses - or bitcoin private keys. If you want to be prompted for your + public key, a master private key, a list of Zcoin addresses + or Zcoin private keys. If you want to be prompted for your seed, type '?' or ':' (concealed) """ raise BaseException('Not a JSON-RPC command') @@ -175,8 +175,7 @@ def getaddresshistory(self, address): """Return the transaction history of any address. Note: This is a walletless server query, results are not checked by SPV. """ - sh = bitcoin.address_to_scripthash(address) - return self.network.synchronous_get(('blockchain.scripthash.get_history', [sh])) + return self.network.synchronous_get(('blockchain.address.get_history', [address])) @command('w') def listunspent(self): @@ -193,8 +192,7 @@ def getaddressunspent(self, address): """Returns the UTXO list of any address. Note: This is a walletless server query, results are not checked by SPV. """ - sh = bitcoin.address_to_scripthash(address) - return self.network.synchronous_get(('blockchain.scripthash.listunspent', [sh])) + return self.network.synchronous_get(('blockchain.address.listunspent', [address])) @command('') def serialize(self, jsontx): @@ -288,7 +286,7 @@ def ismine(self, address): @command('') def dumpprivkeys(self): """Deprecated.""" - return "This command is deprecated. Use a pipe instead: 'electrum listaddresses | electrum getprivatekeys - '" + return "This command is deprecated. Use a pipe instead: 'electrum-xzc listaddresses | electrum-xzc getprivatekeys - '" @command('') def validateaddress(self, address): @@ -316,12 +314,20 @@ def getaddressbalance(self, address): """Return the balance of any address. Note: This is a walletless server query, results are not checked by SPV. """ - sh = bitcoin.address_to_scripthash(address) - out = self.network.synchronous_get(('blockchain.scripthash.get_balance', [sh])) + out = self.network.synchronous_get(('blockchain.address.get_balance', [address])) out["confirmed"] = str(Decimal(out["confirmed"])/COIN) out["unconfirmed"] = str(Decimal(out["unconfirmed"])/COIN) return out + @command('n') + def getproof(self, address): + """Get Merkle branch of an address in the UTXO set""" + p = self.network.synchronous_get(('blockchain.address.get_proof', [address])) + out = [] + for i,s in p: + out.append(i) + return out + @command('n') def getmerkle(self, txid, height): """Get Merkle branch of a transaction included in a block. Electrum @@ -440,24 +446,50 @@ def paytomany(self, outputs, fee=None, from_addr=None, change_addr=None, nocheck return tx.as_dict() @command('w') - def history(self, year=None, show_addresses=False, show_fiat=False): + def history(self): """Wallet history. Returns the transaction history of your wallet.""" - kwargs = {'show_addresses': show_addresses} - if year: - import time - start_date = datetime.datetime(year, 1, 1) - end_date = datetime.datetime(year+1, 1, 1) - kwargs['from_timestamp'] = time.mktime(start_date.timetuple()) - kwargs['to_timestamp'] = time.mktime(end_date.timetuple()) - if show_fiat: - from .exchange_rate import FxThread - fx = FxThread(self.config, None) - kwargs['fx'] = fx - return self.wallet.export_history(**kwargs) + balance = 0 + out = [] + for item in self.wallet.get_history(): + tx_hash, height, conf, timestamp, value, balance = item + if timestamp: + date = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] + else: + date = "----" + label = self.wallet.get_label(tx_hash) + tx = self.wallet.transactions.get(tx_hash) + tx.deserialize() + input_addresses = [] + output_addresses = [] + for x in tx.inputs(): + if x['type'] == 'coinbase': continue + addr = x.get('address') + if addr == None: continue + if addr == "(pubkey)": + prevout_hash = x.get('prevout_hash') + prevout_n = x.get('prevout_n') + _addr = self.wallet.find_pay_to_pubkey_address(prevout_hash, prevout_n) + if _addr: + addr = _addr + input_addresses.append(addr) + for addr, v in tx.get_outputs(): + output_addresses.append(addr) + out.append({ + 'txid': tx_hash, + 'timestamp': timestamp, + 'date': date, + 'input_addresses': input_addresses, + 'output_addresses': output_addresses, + 'label': label, + 'value': str(Decimal(value)/COIN) if value is not None else None, + 'height': height, + 'confirmations': conf + }) + return out @command('w') def setlabel(self, key, label): - """Assign a label to an item. Item may be a bitcoin address or a + """Assign a label to an item. Item may be a Zcoin address or a transaction ID""" self.wallet.set_label(key, label) @@ -535,7 +567,7 @@ def _format_request(self, out): PR_PAID: 'Paid', PR_EXPIRED: 'Expired', } - out['amount (BTC)'] = format_satoshis(out.get('amount')) + out['amount (XZC)'] = format_satoshis(out.get('amount')) out['status'] = pr_str[out.get('status', PR_UNKNOWN)] return out @@ -601,8 +633,7 @@ def addrequest(self, amount, memo='', expiration=None, force=False): def addtransaction(self, tx): """ Add a transaction to the wallet history """ tx = Transaction(tx) - if not self.wallet.add_transaction(tx.txid(), tx): - return False + self.wallet.add_transaction(tx.txid(), tx) self.wallet.save_transactions() return tx.txid() @@ -662,8 +693,8 @@ def help(self): param_descriptions = { 'privkey': 'Private key. Type \'?\' to get a prompt.', - 'destination': 'Bitcoin address, contact or alias', - 'address': 'Bitcoin address', + 'destination': 'Zcoin address, contact or alias', + 'address': 'Zcoin address', 'seed': 'Seed phrase', 'txid': 'Transaction ID', 'pos': 'Position', @@ -673,8 +704,8 @@ def help(self): 'pubkey': 'Public key', 'message': 'Clear text message. Use quotes if it contains spaces.', 'encrypted': 'Encrypted message', - 'amount': 'Amount to be sent (in BTC). Type \'!\' to send the maximum available.', - 'requested_amount': 'Requested amount (in BTC).', + 'amount': 'Amount to be sent (in XZC). Type \'!\' to send the maximum available.', + 'requested_amount': 'Requested amount (in XZC).', 'outputs': 'list of ["address", amount]', 'redeem_script': 'redeem script (hexadecimal)', } @@ -691,7 +722,7 @@ def help(self): 'labels': ("-l", "Show the labels of listed addresses"), 'nocheck': (None, "Do not verify aliases"), 'imax': (None, "Maximum number of inputs"), - 'fee': ("-f", "Transaction fee (in BTC)"), + 'fee': ("-f", "Transaction fee (in XZC)"), 'from_addr': ("-F", "Source address (must be a wallet address; use sweep to spend from non-wallet address)."), 'change_addr': ("-c", "Change address. Default is a spare address, or the source address if it's not in the wallet"), 'nbits': (None, "Number of bits of entropy"), @@ -710,9 +741,6 @@ def help(self): 'pending': (None, "Show only pending requests."), 'expired': (None, "Show only expired requests."), 'paid': (None, "Show only paid requests."), - 'show_addresses': (None, "Show input and output addresses"), - 'show_fiat': (None, "Show fiat value of transactions"), - 'year': (None, "Show history for a given year"), } @@ -723,7 +751,6 @@ def help(self): 'num': int, 'nbits': int, 'imax': int, - 'year': int, 'entropy': int, 'tx': tx_from_str, 'pubkeys': json_loads, @@ -741,10 +768,10 @@ def help(self): 'requests_dir': 'directory where a bip70 file will be written.', 'ssl_privkey': 'Path to your SSL private key, needed to sign the request.', 'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end', - 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"', + 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum-xzc.org/\')\"', }, 'listrequests':{ - 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"', + 'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum-xzc.org/\')\"', } } @@ -787,7 +814,7 @@ def subparser_call(self, parser, namespace, values, option_string=None): parser = self._name_parser_map[parser_name] except KeyError: tup = parser_name, ', '.join(self._name_parser_map) - msg = _('unknown parser {!r} (choices: {})').format(*tup) + msg = _('unknown parser %r (choices: %s)') % tup raise ArgumentError(self, msg) # parse all the remaining options into the namespace # store any unrecognized options on the object, so that the top @@ -809,19 +836,19 @@ def add_global_options(parser): group = parser.add_argument_group('global options') group.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Show debugging information") group.add_argument("-D", "--dir", dest="electrum_path", help="electrum directory") - group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False, help="Use local 'electrum_data' directory") + group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False, help="Use local 'electrum-xzc_data' directory") group.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path") group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet") def get_parser(): # create main parser parser = argparse.ArgumentParser( - epilog="Run 'electrum help ' to see the help for a command") + epilog="Run 'electrum-xzc help ' to see the help for a command") add_global_options(parser) subparsers = parser.add_subparsers(dest='cmd', metavar='') # gui parser_gui = subparsers.add_parser('gui', description="Run Electrum's Graphical User Interface.", help="Run GUI (default)") - parser_gui.add_argument("url", nargs='?', default=None, help="bitcoin URI (or bip70 file)") + parser_gui.add_argument("url", nargs='?', default=None, help="zcoin URI (or bip70 file)") parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio']) parser_gui.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline") parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup") diff --git a/lib/contacts.py b/lib/contacts.py index 5157adc41057..571d195e0f74 100644 --- a/lib/contacts.py +++ b/lib/contacts.py @@ -23,12 +23,9 @@ import re import dns import json -import traceback -import sys from . import bitcoin from . import dnssec -from .util import FileImportFailed, FileImportFailedEncrypted class Contacts(dict): @@ -54,12 +51,8 @@ def import_file(self, path): try: with open(path, 'r') as f: d = self._validate(json.loads(f.read())) - except json.decoder.JSONDecodeError: - traceback.print_exc(file=sys.stderr) - raise FileImportFailedEncrypted() - except BaseException: - traceback.print_exc(file=sys.stdout) - raise FileImportFailed() + except: + return self.update(d) self.save() @@ -94,13 +87,13 @@ def resolve(self, k): 'type': 'openalias', 'validated': validated } - raise Exception("Invalid Bitcoin address or alias", k) + raise Exception("Invalid Zcoin address or alias", k) def resolve_openalias(self, url): # support email-style addresses, per the OA standard url = url.replace('@', '.') records, validated = dnssec.query(url, dns.rdatatype.TXT) - prefix = 'btc' + prefix = 'xzc' for record in records: string = record.strings[0] if string.startswith('oa1:' + prefix): diff --git a/lib/currencies.json b/lib/currencies.json index a4e85f1f6fc4..af8c4b5fba37 100644 --- a/lib/currencies.json +++ b/lib/currencies.json @@ -1,538 +1,194 @@ { - "BitPay": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BCH", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BTC", - "BTN", - "BWP", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNY", - "COP", - "CRC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EGP", - "ETB", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "STD", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VEF", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XCD", - "XOF", - "XPF", - "YER", - "ZAR", - "ZMW", - "ZWL" - ], - "BitStamp": [ - "USD" - ], - "BitcoinAverage": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BTN", - "BWP", - "BYN", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNH", - "CNY", - "COP", - "CRC", - "CUC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EGP", - "ERN", - "ETB", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GGP", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "IMP", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "SSP", - "STD", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VEF", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XCD", - "XDR", - "XOF", - "XPD", - "XPF", - "XPT", - "YER", - "ZAR", - "ZMW", - "ZWL" - ], - "Bitmarket": [ - "PLN" - ], - "Bitso": [ - "MXN" - ], - "Bitvalor": [ - "BRL" - ], - "BlockchainInfo": [ - "AUD", - "BRL", - "CAD", - "CHF", - "CLP", - "CNY", - "DKK", - "EUR", - "GBP", - "HKD", - "INR", - "ISK", - "JPY", - "KRW", - "NZD", - "PLN", - "RUB", - "SEK", - "SGD", - "THB", - "TWD", - "USD" + "Bit2C": [ + "NIS" ], - "CoinDesk": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", + "BitcoinAverage": [ + "AED", + "AFN", + "ALL", + "AMD", + "ANG", + "AOA", + "ARS", + "AUD", + "AWG", + "AZN", + "BAM", + "BBD", + "BDT", + "BGN", + "BHD", + "BIF", + "BMD", + "BND", + "BOB", + "BRL", + "BSD", + "BTC", + "BTN", + "BWP", + "BYN", + "BZD", + "CAD", + "CDF", + "CHF", + "CLF", + "CLP", + "CNH", + "CNY", + "COP", + "CRC", + "CUC", + "CUP", + "CVE", + "CZK", + "DJF", + "DKK", + "DOP", + "DZD", + "EGP", + "ERN", + "ETB", + "ETH", + "EUR", + "FJD", + "FKP", + "GBP", + "GEL", + "GGP", + "GHS", + "GIP", + "GMD", + "GNF", + "GTQ", + "GYD", + "HKD", + "HNL", + "HRK", + "HTG", + "HUF", + "IDR", + "ILS", + "IMP", + "INR", + "IQD", + "IRR", + "ISK", + "JEP", + "JMD", + "JOD", + "JPY", + "KES", + "KGS", + "KHR", + "KMF", + "KPW", + "KRW", + "KWD", + "KYD", + "KZT", + "LAK", + "LBP", + "LKR", + "LRD", + "LSL", + "LYD", + "MAD", + "MDL", + "MGA", + "MKD", + "MMK", + "MNT", + "MOP", + "MRO", + "MUR", + "MVR", + "MWK", + "MXN", + "MYR", + "MZN", + "NAD", + "NGN", + "NIO", + "NOK", + "NPR", + "NZD", + "OMR", + "PAB", + "PEN", + "PGK", + "PHP", + "PKR", + "PLN", + "PYG", + "QAR", + "RON", + "RSD", + "RUB", + "RWF", + "SAR", + "SBD", + "SCR", + "SDG", + "SEK", + "SGD", + "SHP", + "SLL", + "SOS", + "SRD", + "SSP", + "STD", + "SVC", + "SYP", + "SZL", + "THB", + "TJS", + "TMT", + "TND", + "TOP", + "TRY", + "TTD", + "TWD", + "TZS", + "UAH", + "UGX", + "USD", + "UYU", + "UZS", + "VEF", + "VND", + "VUV", + "WST", + "XAF", + "XAG", + "XAU", + "XCD", + "XDR", + "XOF", + "XPD", + "XPF", + "XPT", + "XRP", + "YER", + "ZAR", + "ZEC", + "ZMW", + "ZWL" + ], + "BitcoinVenezuela": [ "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BTC", - "BTN", - "BWP", - "BYR", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNY", - "COP", - "CRC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EEK", - "EGP", - "ERN", - "ETB", "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LTL", - "LVL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MTL", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "STD", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", "USD", - "UYU", - "UZS", - "VEF", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XBT", - "XCD", - "XDR", - "XOF", - "XPF", - "YER", - "ZAR", - "ZMK", - "ZMW", - "ZWL" + "VEF" + ], + "Bitfinex": [ + "USD" + ], + "Bitso": [ + "MXN" + ], + "BitStamp": [ + "USD" ], "Coinbase": [ "AED", @@ -547,7 +203,6 @@ "AZN", "BAM", "BBD", - "BCH", "BDT", "BGN", "BHD", @@ -557,6 +212,7 @@ "BOB", "BRL", "BSD", + "BTC", "BTN", "BWP", "BYN", @@ -567,7 +223,6 @@ "CHF", "CLF", "CLP", - "CNH", "CNY", "COP", "CRC", @@ -623,7 +278,7 @@ "LKR", "LRD", "LSL", - "LTC", + "XZC", "LTL", "LVL", "LYD", @@ -707,96 +362,32 @@ "ZMW", "ZWL" ], - "Foxbit": [ - "BRL" + "CoinSpot": [ + "AUD" ], - "Kraken": [ - "CAD", + "GoCoin": [ + "USD" + ], + "HitBTC": [ "EUR", - "GBP", - "JPY", "USD" ], - "LocalBitcoins": [ - "AED", - "ARS", - "AUD", - "BAM", - "BDT", - "BHD", - "BOB", - "BRL", - "BYN", - "CAD", - "CHF", - "CLP", - "CNY", - "COP", - "CRC", - "CZK", - "DKK", - "DOP", - "EGP", - "ETH", + "Kraken": [ "EUR", - "GBP", - "GHS", - "HKD", - "HRK", - "HUF", - "IDR", - "ILS", - "INR", - "IRR", - "JOD", - "JPY", - "KES", - "KRW", - "KZT", - "LKR", - "MAD", - "MXN", - "MYR", - "NGN", - "NOK", - "NZD", - "PAB", - "PEN", - "PHP", - "PKR", - "PLN", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SEK", - "SGD", - "THB", - "TRY", - "TTD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "VEF", - "VND", - "XAR", - "ZAR", - "ZMW" + "USD" + ], + "OKCoin": [ + "USD" ], "MercadoBitcoin": [ "BRL" ], - "NegocieCoins": [ - "BRL" + "QuadrigaCX": [ + "CAD" ], "WEX": [ "EUR", "RUB", "USD" - ], - "itBit": [] -} \ No newline at end of file + ] +} diff --git a/lib/daemon.py b/lib/daemon.py index bebcf4046f57..8bdd9bb978e3 100644 --- a/lib/daemon.py +++ b/lib/daemon.py @@ -25,8 +25,6 @@ import ast import os import time -import traceback -import sys # from jsonrpc import JSONRPCResponseManager import jsonrpclib @@ -123,12 +121,13 @@ def __init__(self, config, fd, is_gui): self.config = config if config.get('offline'): self.network = None + self.fx = None else: self.network = Network(config) self.network.start() - self.fx = FxThread(config, self.network) - if self.network: + self.fx = FxThread(config, self.network) self.network.add_jobs([self.fx]) + self.gui = None self.wallets = {} # Setup JSONRPC server @@ -264,7 +263,7 @@ def run_cmdline(self, config_options): path = config.get_wallet_path() wallet = self.wallets.get(path) if wallet is None: - return {'error': 'Wallet "%s" is not loaded. Use "electrum daemon load_wallet"'%os.path.basename(path) } + return {'error': 'Wallet "%s" is not loaded. Use "electrum-xzc daemon load_wallet"'%os.path.basename(path) } else: wallet = None # arguments passed to function @@ -300,10 +299,6 @@ def init_gui(self, config, plugins): gui_name = config.get('gui', 'qt') if gui_name in ['lite', 'classic']: gui_name = 'qt' - gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui']) + gui = __import__('electrum_xzc_gui.' + gui_name, fromlist=['electrum_xzc_gui']) self.gui = gui.ElectrumGui(config, self, plugins) - try: - self.gui.main() - except BaseException as e: - traceback.print_exc(file=sys.stdout) - # app will exit now + self.gui.main() diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py index 6931e3388a18..e3a39dbd7e36 100644 --- a/lib/exchange_rate.py +++ b/lib/exchange_rate.py @@ -2,8 +2,6 @@ import inspect import requests import sys -import os -import json from threading import Thread import time import csv @@ -35,7 +33,7 @@ def __init__(self, on_quotes, on_history): def get_json(self, site, get_string): # APIs must have https url = ''.join(['https://', site, get_string]) - response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'}, timeout=10) + response = requests.request('GET', url, headers={'User-Agent' : 'Electrum'}) return response.json() def get_csv(self, site, get_string): @@ -61,44 +59,19 @@ def update(self, ccy): t.setDaemon(True) t.start() - def read_historical_rates(self, ccy, cache_dir): - filename = os.path.join(cache_dir, self.name() + '_'+ ccy) - if os.path.exists(filename): - timestamp = os.stat(filename).st_mtime - try: - with open(filename, 'r') as f: - h = json.loads(f.read()) - except: - h = None - else: - h = None - timestamp = False - if h: - self.history[ccy] = h + def get_historical_rates_safe(self, ccy): + try: + self.print_error("requesting fx history for", ccy) + self.history[ccy] = self.historical_rates(ccy) + self.print_error("received fx history for", ccy) self.on_history() - return h, timestamp - - def get_historical_rates_safe(self, ccy, cache_dir): - h, timestamp = self.read_historical_rates(ccy, cache_dir) - if h is None or time.time() - timestamp < 24*3600: - try: - self.print_error("requesting fx history for", ccy) - h = self.request_history(ccy) - self.print_error("received fx history for", ccy) - self.on_history() - except BaseException as e: - self.print_error("failed fx history:", e) - return - filename = os.path.join(cache_dir, self.name() + '_' + ccy) - with open(filename, 'w') as f: - f.write(json.dumps(h)) - self.history[ccy] = h - self.on_history() - - def get_historical_rates(self, ccy, cache_dir): + except BaseException as e: + self.print_error("failed fx history:", e) + + def get_historical_rates(self, ccy): result = self.history.get(ccy) if not result and ccy in self.history_ccys(): - t = Thread(target=self.get_historical_rates_safe, args=(ccy, cache_dir)) + t = Thread(target=self.get_historical_rates_safe, args=(ccy,)) t.setDaemon(True) t.start() return result @@ -107,8 +80,6 @@ def history_ccys(self): return [] def historical_rate(self, ccy, d_t): - if d_t is None: - return None return self.history.get(ccy, {}).get(d_t.strftime('%Y-%m-%d')) def get_currencies(self): @@ -116,11 +87,18 @@ def get_currencies(self): return sorted([str(a) for (a, b) in rates.items() if b is not None and len(a)==3]) +class Bit2C(ExchangeBase): + + def get_rates(self, ccy): + json = self.get_json('www.bit2c.co.il', '/Exchanges/XZCNIS/Ticker.json') + return {'NIS': Decimal(json['ll'])} + + class BitcoinAverage(ExchangeBase): def get_rates(self, ccy): json = self.get_json('apiv2.bitcoinaverage.com', '/indices/global/ticker/short') - return dict([(r.replace("BTC", ""), Decimal(json[r]['last'])) + return dict([(r.replace("XZC", ""), Decimal(json[r]['last'])) for r in json if r != 'timestamp']) def history_ccys(self): @@ -128,227 +106,137 @@ def history_ccys(self): 'MXN', 'NOK', 'NZD', 'PLN', 'RON', 'RUB', 'SEK', 'SGD', 'USD', 'ZAR'] - def request_history(self, ccy): + def historical_rates(self, ccy): history = self.get_csv('apiv2.bitcoinaverage.com', - "/indices/global/history/BTC%s?period=alltime&format=csv" % ccy) + "/indices/global/history/XZC%s?period=alltime&format=csv" % ccy) return dict([(h['DateTime'][:10], h['Average']) for h in history]) -class Bitcointoyou(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('bitcointoyou.com', "/API/ticker.aspx") - return {'BRL': Decimal(json['ticker']['last'])} - - def history_ccys(self): - return ['BRL'] - - class BitcoinVenezuela(ExchangeBase): def get_rates(self, ccy): json = self.get_json('api.bitcoinvenezuela.com', '/') - rates = [(r, json['BTC'][r]) for r in json['BTC'] - if json['BTC'][r] is not None] # Giving NULL for LTC + rates = [(r, json['XZC'][r]) for r in json['XZC'] + if json['XZC'][r] is not None] # Giving NULL sometimes return dict(rates) def history_ccys(self): return ['ARS', 'EUR', 'USD', 'VEF'] - def request_history(self, ccy): + def historical_rates(self, ccy): return self.get_json('api.bitcoinvenezuela.com', - "/historical/index.php?coin=BTC")[ccy +'_BTC'] + "/historical/index.php?coin=XZC")[ccy +'_XZC'] - -class Bitmarket(ExchangeBase): +class Bitfinex(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('www.bitmarket.pl', '/json/BTCPLN/ticker.json') - return {'PLN': Decimal(json['last'])} - - -class BitPay(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('bitpay.com', '/api/rates') - return dict([(r['code'], Decimal(r['rate'])) for r in json]) + json = self.get_json('api.bitfinex.com', '/v1/pubticker/xzcusd') + return {'USD': Decimal(json['last_price'])} class Bitso(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('api.bitso.com', '/v2/ticker') - return {'MXN': Decimal(json['last'])} + json = self.get_json('api.bitso.com', '/v3/ticker/?book=xzc_mxn') + return {'MXN': Decimal(json['payload']['last'])} class BitStamp(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('www.bitstamp.net', '/api/ticker/') + json = self.get_json('www.bitstamp.net', '/api/v2/ticker/xzcusd/') return {'USD': Decimal(json['last'])} -class Bitvalor(ExchangeBase): - - def get_rates(self,ccy): - json = self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['total']['last'])} - - -class BlockchainInfo(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('blockchain.info', '/ticker') - return dict([(r, Decimal(json[r]['15m'])) for r in json]) - - -class BTCChina(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('data.btcchina.com', '/data/ticker') - return {'CNY': Decimal(json['ticker']['last'])} - - -class BTCParalelo(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('btcparalelo.com', '/api/price') - return {'VEF': Decimal(json['price'])} - - class Coinbase(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('coinbase.com', - '/api/v1/currencies/exchange_rates') - return dict([(r[7:].upper(), Decimal(json[r])) - for r in json if r.startswith('btc_to_')]) + json = self.get_json('api.coinbase.com', + '/v2/exchange-rates?currency=XZC') + rates = json['data']['rates'] + return dict([(k, Decimal(rates[k])) for k in rates]) -class CoinDesk(ExchangeBase): - - def get_currencies(self): - dicts = self.get_json('api.coindesk.com', - '/v1/bpi/supported-currencies.json') - return [d['currency'] for d in dicts] +class CoinSpot(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('api.coindesk.com', - '/v1/bpi/currentprice/%s.json' % ccy) - result = {ccy: Decimal(json['bpi'][ccy]['rate_float'])} - return result - - def history_starts(self): - return { 'USD': '2012-11-30', 'EUR': '2013-09-01' } - - def history_ccys(self): - return self.history_starts().keys() + json = self.get_json('www.coinspot.com.au', '/pubapi/latest') + return {'AUD': Decimal(json['prices']['xzc']['last'])} - def request_history(self, ccy): - start = self.history_starts()[ccy] - end = datetime.today().strftime('%Y-%m-%d') - # Note ?currency and ?index don't work as documented. Sigh. - query = ('/v1/bpi/historical/close.json?start=%s&end=%s' - % (start, end)) - json = self.get_json('api.coindesk.com', query) - return json['bpi'] - -class Coinsecure(ExchangeBase): +class GoCoin(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('api.coinsecure.in', '/v0/noauth/newticker') - return {'INR': Decimal(json['lastprice'] / 100.0 )} - - -class Foxbit(ExchangeBase): - - def get_rates(self,ccy): - json = self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['exchanges']['FOX']['last'])} + json = self.get_json('x.g0cn.com', '/prices') + xzc_prices = json['prices']['XZC'] + return dict([(r, Decimal(xzc_prices[r])) for r in xzc_prices]) -class itBit(ExchangeBase): +class HitBTC(ExchangeBase): def get_rates(self, ccy): - ccys = ['USD', 'EUR', 'SGD'] - json = self.get_json('api.itbit.com', '/v1/markets/XBT%s/ticker' % ccy) + ccys = ['EUR', 'USD'] + json = self.get_json('api.hitbtc.com', '/api/1/public/XZC%s/ticker' % ccy) result = dict.fromkeys(ccys) if ccy in ccys: - result[ccy] = Decimal(json['lastPrice']) + result[ccy] = Decimal(json['last']) return result class Kraken(ExchangeBase): def get_rates(self, ccy): - ccys = ['EUR', 'USD', 'CAD', 'GBP', 'JPY'] - pairs = ['XBT%s' % c for c in ccys] + dicts = self.get_json('api.kraken.com', '/0/public/AssetPairs') + pairs = [k for k in dicts['result'] if k.startswith('XXZCZ')] json = self.get_json('api.kraken.com', '/0/public/Ticker?pair=%s' % ','.join(pairs)) - return dict((k[-3:], Decimal(float(v['c'][0]))) - for k, v in json['result'].items()) + ccys = [p[5:] for p in pairs] + result = dict.fromkeys(ccys) + result[ccy] = Decimal(json['result']['XXZCZ'+ccy]['c'][0]) + return result + def history_ccys(self): + return ['EUR', 'USD'] -class LocalBitcoins(ExchangeBase): + def historical_rates(self, ccy): + query = '/0/public/OHLC?pair=XZC%s&interval=1440' % ccy + json = self.get_json('api.kraken.com', query) + history = json['result']['XXZCZ'+ccy] + return dict([(time.strftime('%Y-%m-%d', time.localtime(t[0])), t[4]) + for t in history]) - def get_rates(self, ccy): - json = self.get_json('localbitcoins.com', - '/bitcoinaverage/ticker-all-currencies/') - return dict([(r, Decimal(json[r]['rates']['last'])) for r in json]) - -class MercadoBitcoin(ExchangeBase): +class OKCoin(ExchangeBase): def get_rates(self, ccy): - json = self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])} + json = self.get_json('www.okcoin.com', '/api/v1/ticker.do?symbol=xzc_usd') + return {'USD': Decimal(json['ticker']['last'])} -class NegocieCoins(ExchangeBase): +class MercadoBitcoin(ExchangeBase): def get_rates(self,ccy): - json = self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['exchanges']['NEG']['last'])} - - def history_ccys(self): - return ['BRL'] + json = self.get_json('www.mercadobitcoin.net', '/api/xzc/ticker/') + return {'BRL': Decimal(json['ticker']['last'])} -class Unocoin(ExchangeBase): +class QuadrigaCX(ExchangeBase): - def get_rates(self, ccy): - json = self.get_json('www.unocoin.com', 'trade?buy') - return {'INR': Decimal(json)} + def get_rates(self,ccy): + json = self.get_json('api.quadrigacx.com', '/v2/ticker?book=xzc_cad') + return {'CAD': Decimal(json['last'])} class WEX(ExchangeBase): def get_rates(self, ccy): - json_eur = self.get_json('wex.nz', '/api/3/ticker/btc_eur') - json_rub = self.get_json('wex.nz', '/api/3/ticker/btc_rur') - json_usd = self.get_json('wex.nz', '/api/3/ticker/btc_usd') - return {'EUR': Decimal(json_eur['btc_eur']['last']), - 'RUB': Decimal(json_rub['btc_rur']['last']), - 'USD': Decimal(json_usd['btc_usd']['last'])} - - -class Winkdex(ExchangeBase): - - def get_rates(self, ccy): - json = self.get_json('winkdex.com', '/api/v0/price') - return {'USD': Decimal(json['price'] / 100.0)} - - def history_ccys(self): - return ['USD'] - - def request_history(self, ccy): - json = self.get_json('winkdex.com', - "/api/v0/series?start_time=1342915200") - history = json['series'][0]['results'] - return dict([(h['timestamp'][:10], h['price'] / 100.0) - for h in history]) + json_eur = self.get_json('wex.nz', '/api/3/ticker/xzc_eur') + json_rub = self.get_json('wex.nz', '/api/3/ticker/xzc_rur') + json_usd = self.get_json('wex.nz', '/api/3/ticker/xzc_usd') + return {'EUR': Decimal(json_eur['xzc_eur']['last']), + 'RUB': Decimal(json_rub['xzc_rur']['last']), + 'USD': Decimal(json_usd['xzc_usd']['last'])} def dictinvert(d): @@ -376,9 +264,7 @@ def get_exchanges_and_currencies(): exchange = klass(None, None) try: d[name] = exchange.get_currencies() - print(name, "ok") except: - print(name, "error") continue with open(path, 'w') as f: f.write(json.dumps(d, indent=4, sort_keys=True)) @@ -409,10 +295,7 @@ def __init__(self, config, network): self.history_used_spot = False self.ccy_combo = None self.hist_checkbox = None - self.cache_dir = os.path.join(config.path, 'cache') self.set_exchange(self.config_exchange()) - if not os.path.exists(self.cache_dir): - os.mkdir(self.cache_dir) def get_currencies(self, h): d = get_exchanges_by_ccy(h) @@ -435,7 +318,7 @@ def run(self): # This runs from the plugins thread which catches exceptions if self.is_enabled(): if self.timeout ==0 and self.show_history(): - self.exchange.get_historical_rates(self.ccy, self.cache_dir) + self.exchange.get_historical_rates(self.ccy) if self.timeout <= time.time(): self.timeout = time.time() + 150 self.exchange.update(self.ccy) @@ -483,15 +366,12 @@ def set_exchange(self, name): # A new exchange means new fx quotes, initially empty. Force # a quote refresh self.timeout = 0 - self.exchange.read_historical_rates(self.ccy, self.cache_dir) def on_quotes(self): - if self.network: - self.network.trigger_callback('on_quotes') + self.network.trigger_callback('on_quotes') def on_history(self): - if self.network: - self.network.trigger_callback('on_history') + self.network.trigger_callback('on_history') def exchange_rate(self): '''Returns None, or the exchange rate as a Decimal''' @@ -509,38 +389,22 @@ def get_fiat_status_text(self, btc_balance, base_unit, decimal_point): self.value_str(COIN / (10**(8 - decimal_point)), rate), self.ccy) def value_str(self, satoshis, rate): - if satoshis is not None and rate is not None: + if satoshis is None: # Can happen with incomplete history + return _("Unknown") + if rate: value = Decimal(satoshis) / COIN * Decimal(rate) - else: - value = None - return self.format_fiat(value) - - def format_fiat(self, value): - if value is not None: return "%s" % (self.ccy_amount_str(value, True)) return _("No data") def history_rate(self, d_t): - if d_t is None: - return None rate = self.exchange.historical_rate(self.ccy, d_t) # Frequently there is no rate for today, until tomorrow :) # Use spot quotes in that case if rate is None and (datetime.today().date() - d_t.date()).days <= 2: rate = self.exchange.quotes.get(self.ccy) self.history_used_spot = True - return Decimal(rate) if rate is not None else None + return rate def historical_value_str(self, satoshis, d_t): rate = self.history_rate(d_t) return self.value_str(satoshis, rate) - - def historical_value(self, satoshis, d_t): - rate = self.history_rate(d_t) - if rate: - return Decimal(satoshis) / COIN * Decimal(rate) - - def timestamp_rate(self, timestamp): - from electrum.util import timestamp_to_datetime - date = timestamp_to_datetime(timestamp) - return self.history_rate(date) diff --git a/lib/i18n.py b/lib/i18n.py index 49adf87caf23..eed5174a0a5f 100644 --- a/lib/i18n.py +++ b/lib/i18n.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- # # Electrum - lightweight Bitcoin client # Copyright (C) 2012 thomasv@gitorious @@ -29,7 +30,13 @@ def _(x): global language - return language.gettext(x) + dic = [('Bitcoin', 'Zcoin'), ('bitcoin', 'zcoin'), ('比特币', '莱特币')] + for b, l in dic: + x = x.replace(l, b) + t = language.gettext(x) + for b, l in dic: + t = t.replace(b, l) + return t def set_language(x): global language diff --git a/lib/keystore.py b/lib/keystore.py index e3579958a285..5b6d1f0212d4 100644 --- a/lib/keystore.py +++ b/lib/keystore.py @@ -45,10 +45,6 @@ def is_watching_only(self): def can_import(self): return False - def may_have_password(self): - """Returns whether the keystore can be encrypted with a password.""" - raise NotImplementedError() - def get_tx_derivations(self, tx): keypairs = {} for txin in tx.inputs(): @@ -120,6 +116,9 @@ def __init__(self, d): def is_deterministic(self): return False + def can_change_password(self): + return True + def get_master_public_key(self): return None @@ -197,6 +196,9 @@ def has_seed(self): def is_watching_only(self): return not self.has_seed() + def can_change_password(self): + return not self.is_watching_only() + def add_seed(self, seed): if self.seed: raise Exception("a seed exists") @@ -520,13 +522,9 @@ def is_watching_only(self): assert not self.has_seed() return False - def get_password_for_storage_encryption(self): - from .storage import get_derivation_used_for_hw_device_encryption - client = self.plugin.get_client(self) - derivation = get_derivation_used_for_hw_device_encryption() - xpub = client.get_xpub(derivation, "standard") - password = self.get_pubkey_from_xpub(xpub, ()) - return password + def can_change_password(self): + return False + def bip39_normalize_passphrase(passphrase): @@ -685,7 +683,7 @@ def is_private_key_list(text): def bip44_derivation(account_id, bip43_purpose=44): - coin = 1 if bitcoin.NetworkConstants.TESTNET else 0 + coin = 1 if bitcoin.NetworkConstants.TESTNET else 2 return "m/%d'/%d'/%d'" % (bip43_purpose, coin, int(account_id)) def from_seed(seed, passphrase, is_p2sh): diff --git a/lib/network.py b/lib/network.py index bf7d4eb415c1..4855c0fcb5c1 100644 --- a/lib/network.py +++ b/lib/network.py @@ -321,10 +321,8 @@ def send_subscriptions(self): self.queue_request('blockchain.scripthash.subscribe', [h]) def request_fee_estimates(self): - from .simple_config import FEE_ETA_TARGETS self.config.requested_fee_estimates() - self.queue_request('mempool.get_fee_histogram', []) - for i in FEE_ETA_TARGETS: + for i in bitcoin.FEE_TARGETS: self.queue_request('blockchain.estimatefee', [i]) def get_status_value(self, key): @@ -334,8 +332,6 @@ def get_status_value(self, key): value = self.banner elif key == 'fee': value = self.config.fee_estimates - elif key == 'fee_histogram': - value = self.config.mempool_fees elif key == 'updated': value = (self.get_local_height(), self.get_server_height()) elif key == 'servers': @@ -547,11 +543,6 @@ def process_response(self, interface, response, callbacks): elif method == 'server.donation_address': if error is None: self.donation_address = result - elif method == 'mempool.get_fee_histogram': - if error is None: - self.print_error(result) - self.config.mempool_fees = result - self.notify('fee_histogram') elif method == 'blockchain.estimatefee': if error is None and result > 0: i = params[0] diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py index c1e25441ac61..a6d64b40ab95 100644 --- a/lib/paymentrequest.py +++ b/lib/paymentrequest.py @@ -40,15 +40,14 @@ from . import bitcoin from . import util from .util import print_error, bh2u, bfh -from .util import FileImportFailed, FileImportFailedEncrypted from . import transaction from . import x509 from . import rsakey from .bitcoin import TYPE_ADDRESS -REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'} -ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'} +REQUEST_HEADERS = {'Accept': 'application/zcoin-paymentrequest', 'User-Agent': 'Electrum'} +ACK_HEADERS = {'Content-Type':'application/zcoin-payment','Accept':'application/zcoin-paymentack','User-Agent':'Electrum'} ca_path = requests.certs.where() ca_list = None @@ -78,7 +77,7 @@ def get_payment_request(url): response.raise_for_status() # Guard against `bitcoin:`-URIs with invalid payment request URLs if "Content-Type" not in response.headers \ - or response.headers["Content-Type"] != "application/bitcoin-paymentrequest": + or response.headers["Content-Type"] != "application/zcoin-paymentrequest": data = None error = "payment URL not pointing to a payment request handling server" else: @@ -153,7 +152,7 @@ def verify(self, contacts): return True if pr.pki_type in ["x509+sha256", "x509+sha1"]: return self.verify_x509(pr) - elif pr.pki_type in ["dnssec+btc", "dnssec+ecdsa"]: + elif pr.pki_type in ["dnssec+xzc", "dnssec+ecdsa"]: return self.verify_dnssec(pr, contacts) else: self.error = "ERROR: Unsupported PKI Type for Message Signature" @@ -203,7 +202,7 @@ def verify_dnssec(self, pr, contacts): if info.get('validated') is not True: self.error = "Alias verification failed (DNSSEC)" return False - if pr.pki_type == "dnssec+btc": + if pr.pki_type == "dnssec+xzc": self.requestor = alias address = info.get('address') pr.signature = '' @@ -318,7 +317,7 @@ def make_unsigned_request(req): def sign_request_with_alias(pr, alias, alias_privkey): - pr.pki_type = 'dnssec+btc' + pr.pki_type = 'dnssec+xzc' pr.pki_data = str(alias) message = pr.SerializeToString() ec_key = bitcoin.regenerate_key(alias_privkey) @@ -427,7 +426,7 @@ def serialize_request(req): requestor = req.get('name') if requestor and signature: pr.signature = bfh(signature) - pr.pki_type = 'dnssec+btc' + pr.pki_type = 'dnssec+xzc' pr.pki_data = str(requestor) return pr @@ -472,12 +471,9 @@ def import_file(self, path): with open(path, 'r') as f: d = json.loads(f.read()) self.load(d) - except json.decoder.JSONDecodeError: + except: traceback.print_exc(file=sys.stderr) - raise FileImportFailedEncrypted() - except BaseException: - traceback.print_exc(file=sys.stdout) - raise FileImportFailed() + return self.save() def save(self): diff --git a/lib/paymentrequest_pb2.py b/lib/paymentrequest_pb2.py index f596128c1569..0e90d9af0857 100644 --- a/lib/paymentrequest_pb2.py +++ b/lib/paymentrequest_pb2.py @@ -18,9 +18,9 @@ DESCRIPTOR = _descriptor.FileDescriptor( name='paymentrequest.proto', package='payments', + syntax='proto2', serialized_pb=_b('\n\x14paymentrequest.proto\x12\x08payments\"+\n\x06Output\x12\x11\n\x06\x61mount\x18\x01 \x01(\x04:\x01\x30\x12\x0e\n\x06script\x18\x02 \x02(\x0c\"\xa3\x01\n\x0ePaymentDetails\x12\x15\n\x07network\x18\x01 \x01(\t:\x04main\x12!\n\x07outputs\x18\x02 \x03(\x0b\x32\x10.payments.Output\x12\x0c\n\x04time\x18\x03 \x02(\x04\x12\x0f\n\x07\x65xpires\x18\x04 \x01(\x04\x12\x0c\n\x04memo\x18\x05 \x01(\t\x12\x13\n\x0bpayment_url\x18\x06 \x01(\t\x12\x15\n\rmerchant_data\x18\x07 \x01(\x0c\"\x95\x01\n\x0ePaymentRequest\x12\"\n\x17payment_details_version\x18\x01 \x01(\r:\x01\x31\x12\x16\n\x08pki_type\x18\x02 \x01(\t:\x04none\x12\x10\n\x08pki_data\x18\x03 \x01(\x0c\x12\"\n\x1aserialized_payment_details\x18\x04 \x02(\x0c\x12\x11\n\tsignature\x18\x05 \x01(\x0c\"\'\n\x10X509Certificates\x12\x13\n\x0b\x63\x65rtificate\x18\x01 \x03(\x0c\"i\n\x07Payment\x12\x15\n\rmerchant_data\x18\x01 \x01(\x0c\x12\x14\n\x0ctransactions\x18\x02 \x03(\x0c\x12#\n\trefund_to\x18\x03 \x03(\x0b\x32\x10.payments.Output\x12\x0c\n\x04memo\x18\x04 \x01(\t\">\n\nPaymentACK\x12\"\n\x07payment\x18\x01 \x02(\x0b\x32\x11.payments.Payment\x12\x0c\n\x04memo\x18\x02 \x01(\tB(\n\x1eorg.bitcoin.protocols.paymentsB\x06Protos') ) -_sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -54,6 +54,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -126,6 +127,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -184,6 +186,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -214,6 +217,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -265,6 +269,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -302,6 +307,7 @@ ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -318,6 +324,7 @@ DESCRIPTOR.message_types_by_name['X509Certificates'] = _X509CERTIFICATES DESCRIPTOR.message_types_by_name['Payment'] = _PAYMENT DESCRIPTOR.message_types_by_name['PaymentACK'] = _PAYMENTACK +_sym_db.RegisterFileDescriptor(DESCRIPTOR) Output = _reflection.GeneratedProtocolMessageType('Output', (_message.Message,), dict( DESCRIPTOR = _OUTPUT, diff --git a/lib/plot.py b/lib/plot.py index 06f8edd75697..18b32c71e1f1 100644 --- a/lib/plot.py +++ b/lib/plot.py @@ -1,10 +1,10 @@ from PyQt5.QtGui import * -from electrum.i18n import _ +from electrum_xzc.i18n import _ import datetime from collections import defaultdict -from electrum.bitcoin import COIN +from electrum_xzc.bitcoin import COIN import matplotlib matplotlib.use('Qt5Agg') @@ -35,7 +35,7 @@ def plot_history(wallet, history): plt.subplots_adjust(bottom=0.2) plt.xticks( rotation=25 ) ax = plt.gca() - plt.ylabel('BTC') + plt.ylabel('XZC') plt.xlabel('Month') xfmt = md.DateFormatter('%Y-%m-%d') ax.xaxis.set_major_formatter(xfmt) diff --git a/lib/plugins.py b/lib/plugins.py index b3611c167432..883afe167828 100644 --- a/lib/plugins.py +++ b/lib/plugins.py @@ -48,9 +48,9 @@ def __init__(self, config, is_local, gui_name): DaemonThread.__init__(self) if is_local: find = imp.find_module('plugins') - plugins = imp.load_module('electrum_plugins', *find) + plugins = imp.load_module('electrum_xzc_plugins', *find) else: - plugins = __import__('electrum_plugins') + plugins = __import__('electrum_xzc_plugins') self.pkgpath = os.path.dirname(plugins.__file__) self.config = config self.hw_wallets = {} @@ -95,7 +95,7 @@ def count(self): def load_plugin(self, name): if name in self.plugins: return self.plugins[name] - full_name = 'electrum_plugins.' + name + '.' + self.gui_name + full_name = 'electrum_xzc_plugins.' + name + '.' + self.gui_name loader = pkgutil.find_loader(full_name) if not loader: raise RuntimeError("%s implementation for %s plugin not found" @@ -312,8 +312,6 @@ def __init__(self, config): # What we recognise. Each entry is a (vendor_id, product_id) # pair. self.recognised_hardware = set() - # Custom enumerate functions for devices we don't know about. - self.enumerate_func = set() # For synchronization self.lock = threading.RLock() self.hid_lock = threading.RLock() @@ -336,9 +334,6 @@ def register_devices(self, device_pairs): for pair in device_pairs: self.recognised_hardware.add(pair) - def register_enumerate_func(self, func): - self.enumerate_func.add(func) - def create_client(self, device, handler, plugin): # Get from cache first client = self.client_lookup(device.id_) @@ -367,20 +362,15 @@ def unpair_xpub(self, xpub): if not xpub in self.xpub_ids: return _id = self.xpub_ids.pop(xpub) - self._close_client(_id) + client = self.client_lookup(_id) + self.clients.pop(client, None) + if client: + client.close() def unpair_id(self, id_): xpub = self.xpub_by_id(id_) if xpub: self.unpair_xpub(xpub) - else: - self._close_client(id_) - - def _close_client(self, id_): - client = self.client_lookup(id_) - self.clients.pop(client, None) - if client: - client.close() def pair_xpub(self, xpub, id_): with self.lock: @@ -452,11 +442,11 @@ def force_pair_xpub(self, plugin, handler, info, xpub, derivation, devices): # The user input has wrong PIN or passphrase, or cancelled input, # or it is not pairable raise DeviceUnpairableError( - _('Electrum cannot pair with your {}.\n\n' - 'Before you request bitcoins to be sent to addresses in this ' + _('Electrum cannot pair with your %s.\n\n' + 'Before you request zcoins to be sent to addresses in this ' 'wallet, ensure you can pair with your device, or that you have ' - 'its seed (and passphrase, if any). Otherwise all bitcoins you ' - 'receive will be unspendable.').format(plugin.device)) + 'its seed (and passphrase, if any). Otherwise all zcoins you ' + 'receive will be unspendable.') % plugin.device) def unpaired_device_infos(self, handler, plugin, devices=None): '''Returns a list of DeviceInfo objects: one for each connected, @@ -482,9 +472,9 @@ def select_device(self, plugin, handler, keystore, devices=None): infos = self.unpaired_device_infos(handler, plugin, devices) if infos: break - msg = _('Please insert your {}. Verify the cable is ' + msg = _('Please insert your %s. Verify the cable is ' 'connected and that no other application is using it.\n\n' - 'Try to connect again?').format(plugin.device) + 'Try to connect again?') % plugin.device if not handler.yes_no_question(msg): raise UserCancelled() devices = None @@ -494,7 +484,7 @@ def select_device(self, plugin, handler, keystore, devices=None): for info in infos: if info.label == keystore.label: return info - msg = _("Please select which {} device to use:").format(plugin.device) + msg = _("Please select which %s device to use:") % plugin.device descriptions = [info.label + ' (%s)'%(_("initialized") if info.initialized else _("wiped")) for info in infos] c = handler.query_choice(msg, descriptions) if c is None: @@ -514,7 +504,6 @@ def scan_devices(self): self.print_error("scanning devices...") with self.hid_lock: hid_list = hid.enumerate(0, 0) - # First see what's connected that we know about devices = [] for d in hid_list: @@ -530,10 +519,6 @@ def scan_devices(self): devices.append(Device(d['path'], interface_number, id_, product_key, usage_page)) - # Let plugin handlers enumerate devices we don't know about - for f in self.enumerate_func: - devices.extend(f()) - # Now find out what was disconnected pairs = [(dev.path, dev.id_) for dev in devices] disconnected_ids = [] diff --git a/lib/scrypt.py b/lib/scrypt.py new file mode 100644 index 000000000000..67572d50d5e0 --- /dev/null +++ b/lib/scrypt.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +# +# scrypt.py - basic implementation of Litecoin's proof-of-work algorithm +# Copyright (C) 2014, 2017 pooler@litecoinpool.org +# +# 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 . + +import hashlib +import hmac + +def scrypt_1024_1_1_80(header): + if not isinstance(header, bytes) or len(header) != 80: + raise ValueError('header must be 80 bytes') + + mac = hmac.new(header, digestmod=hashlib.sha256) + + V = [0]*32*1024 + X = [0]*32 + + B = list(header[:]) + [0]*4 + for i in range(4): + B[83] = i + 1 + m = mac.copy() + m.update(bytes(B)) + H = m.digest() + for j in range(8): + X[i*8 + j] = (H[j*4 + 0] << 0 | H[j*4 + 1] << 8 | + H[j*4 + 2] << 16 | H[j*4 + 3] << 24) + + for i in range(1024): + V[i*32:i*32+32] = X + _xor_salsa8_2(X) + + for i in range(1024): + k = (X[16] & 1023) * 32 + for j in range(32): + X[j] ^= V[k+j] + _xor_salsa8_2(X) + + B = [0]*(128+3) + [1] + for i in range(32): + B[i*4 + 0] = X[i] >> 0 & 0xff + B[i*4 + 1] = X[i] >> 8 & 0xff + B[i*4 + 2] = X[i] >> 16 & 0xff + B[i*4 + 3] = X[i] >> 24 & 0xff + + mac.update(bytes(B)) + return mac.digest() + +def _xor_salsa8_2(X): + [ + x00, x01, x02, x03, x04, x05, x06, x07, + x08, x09, x10, x11, x12, x13, x14, x15, + x16, x17, x18, x19, x20, x21, x22, x23, + x24, x25, x26, x27, x28, x29, x30, x31 + ] = X + + x00 ^= x16 + x01 ^= x17 + x02 ^= x18 + x03 ^= x19 + x04 ^= x20 + x05 ^= x21 + x06 ^= x22 + x07 ^= x23 + x08 ^= x24 + x09 ^= x25 + x10 ^= x26 + x11 ^= x27 + x12 ^= x28 + x13 ^= x29 + x14 ^= x30 + x15 ^= x31 + + t00 = x00 + t01 = x01 + t02 = x02 + t03 = x03 + t04 = x04 + t05 = x05 + t06 = x06 + t07 = x07 + t08 = x08 + t09 = x09 + t10 = x10 + t11 = x11 + t12 = x12 + t13 = x13 + t14 = x14 + t15 = x15 + + for j in range(4): + t = t00+t12 & 0xffffffff; t04 ^= (t >> 25) | (t << 7) + t = t04+t00 & 0xffffffff; t08 ^= (t >> 23) | (t << 9) + t = t08+t04 & 0xffffffff; t12 ^= (t >> 19) | (t << 13) + t = t12+t08 & 0xffffffff; t00 ^= (t >> 14) | (t << 18) + t = t05+t01 & 0xffffffff; t09 ^= (t >> 25) | (t << 7) + t = t09+t05 & 0xffffffff; t13 ^= (t >> 23) | (t << 9) + t = t13+t09 & 0xffffffff; t01 ^= (t >> 19) | (t << 13) + t = t01+t13 & 0xffffffff; t05 ^= (t >> 14) | (t << 18) + t = t10+t06 & 0xffffffff; t14 ^= (t >> 25) | (t << 7) + t = t14+t10 & 0xffffffff; t02 ^= (t >> 23) | (t << 9) + t = t02+t14 & 0xffffffff; t06 ^= (t >> 19) | (t << 13) + t = t06+t02 & 0xffffffff; t10 ^= (t >> 14) | (t << 18) + t = t15+t11 & 0xffffffff; t03 ^= (t >> 25) | (t << 7) + t = t03+t15 & 0xffffffff; t07 ^= (t >> 23) | (t << 9) + t = t07+t03 & 0xffffffff; t11 ^= (t >> 19) | (t << 13) + t = t11+t07 & 0xffffffff; t15 ^= (t >> 14) | (t << 18) + t = t00+t03 & 0xffffffff; t01 ^= (t >> 25) | (t << 7) + t = t01+t00 & 0xffffffff; t02 ^= (t >> 23) | (t << 9) + t = t02+t01 & 0xffffffff; t03 ^= (t >> 19) | (t << 13) + t = t03+t02 & 0xffffffff; t00 ^= (t >> 14) | (t << 18) + t = t05+t04 & 0xffffffff; t06 ^= (t >> 25) | (t << 7) + t = t06+t05 & 0xffffffff; t07 ^= (t >> 23) | (t << 9) + t = t07+t06 & 0xffffffff; t04 ^= (t >> 19) | (t << 13) + t = t04+t07 & 0xffffffff; t05 ^= (t >> 14) | (t << 18) + t = t10+t09 & 0xffffffff; t11 ^= (t >> 25) | (t << 7) + t = t11+t10 & 0xffffffff; t08 ^= (t >> 23) | (t << 9) + t = t08+t11 & 0xffffffff; t09 ^= (t >> 19) | (t << 13) + t = t09+t08 & 0xffffffff; t10 ^= (t >> 14) | (t << 18) + t = t15+t14 & 0xffffffff; t12 ^= (t >> 25) | (t << 7) + t = t12+t15 & 0xffffffff; t13 ^= (t >> 23) | (t << 9) + t = t13+t12 & 0xffffffff; t14 ^= (t >> 19) | (t << 13) + t = t14+t13 & 0xffffffff; t15 ^= (t >> 14) | (t << 18) + + x00 = x00+t00 & 0xffffffff + x01 = x01+t01 & 0xffffffff + x02 = x02+t02 & 0xffffffff + x03 = x03+t03 & 0xffffffff + x04 = x04+t04 & 0xffffffff + x05 = x05+t05 & 0xffffffff + x06 = x06+t06 & 0xffffffff + x07 = x07+t07 & 0xffffffff + x08 = x08+t08 & 0xffffffff + x09 = x09+t09 & 0xffffffff + x10 = x10+t10 & 0xffffffff + x11 = x11+t11 & 0xffffffff + x12 = x12+t12 & 0xffffffff + x13 = x13+t13 & 0xffffffff + x14 = x14+t14 & 0xffffffff + x15 = x15+t15 & 0xffffffff + + x16 ^= x00 + x17 ^= x01 + x18 ^= x02 + x19 ^= x03 + x20 ^= x04 + x21 ^= x05 + x22 ^= x06 + x23 ^= x07 + x24 ^= x08 + x25 ^= x09 + x26 ^= x10 + x27 ^= x11 + x28 ^= x12 + x29 ^= x13 + x30 ^= x14 + x31 ^= x15 + + t00 = x16 + t01 = x17 + t02 = x18 + t03 = x19 + t04 = x20 + t05 = x21 + t06 = x22 + t07 = x23 + t08 = x24 + t09 = x25 + t10 = x26 + t11 = x27 + t12 = x28 + t13 = x29 + t14 = x30 + t15 = x31 + + for j in range(4): + t = t00+t12 & 0xffffffff; t04 ^= (t >> 25) | (t << 7) + t = t04+t00 & 0xffffffff; t08 ^= (t >> 23) | (t << 9) + t = t08+t04 & 0xffffffff; t12 ^= (t >> 19) | (t << 13) + t = t12+t08 & 0xffffffff; t00 ^= (t >> 14) | (t << 18) + t = t05+t01 & 0xffffffff; t09 ^= (t >> 25) | (t << 7) + t = t09+t05 & 0xffffffff; t13 ^= (t >> 23) | (t << 9) + t = t13+t09 & 0xffffffff; t01 ^= (t >> 19) | (t << 13) + t = t01+t13 & 0xffffffff; t05 ^= (t >> 14) | (t << 18) + t = t10+t06 & 0xffffffff; t14 ^= (t >> 25) | (t << 7) + t = t14+t10 & 0xffffffff; t02 ^= (t >> 23) | (t << 9) + t = t02+t14 & 0xffffffff; t06 ^= (t >> 19) | (t << 13) + t = t06+t02 & 0xffffffff; t10 ^= (t >> 14) | (t << 18) + t = t15+t11 & 0xffffffff; t03 ^= (t >> 25) | (t << 7) + t = t03+t15 & 0xffffffff; t07 ^= (t >> 23) | (t << 9) + t = t07+t03 & 0xffffffff; t11 ^= (t >> 19) | (t << 13) + t = t11+t07 & 0xffffffff; t15 ^= (t >> 14) | (t << 18) + t = t00+t03 & 0xffffffff; t01 ^= (t >> 25) | (t << 7) + t = t01+t00 & 0xffffffff; t02 ^= (t >> 23) | (t << 9) + t = t02+t01 & 0xffffffff; t03 ^= (t >> 19) | (t << 13) + t = t03+t02 & 0xffffffff; t00 ^= (t >> 14) | (t << 18) + t = t05+t04 & 0xffffffff; t06 ^= (t >> 25) | (t << 7) + t = t06+t05 & 0xffffffff; t07 ^= (t >> 23) | (t << 9) + t = t07+t06 & 0xffffffff; t04 ^= (t >> 19) | (t << 13) + t = t04+t07 & 0xffffffff; t05 ^= (t >> 14) | (t << 18) + t = t10+t09 & 0xffffffff; t11 ^= (t >> 25) | (t << 7) + t = t11+t10 & 0xffffffff; t08 ^= (t >> 23) | (t << 9) + t = t08+t11 & 0xffffffff; t09 ^= (t >> 19) | (t << 13) + t = t09+t08 & 0xffffffff; t10 ^= (t >> 14) | (t << 18) + t = t15+t14 & 0xffffffff; t12 ^= (t >> 25) | (t << 7) + t = t12+t15 & 0xffffffff; t13 ^= (t >> 23) | (t << 9) + t = t13+t12 & 0xffffffff; t14 ^= (t >> 19) | (t << 13) + t = t14+t13 & 0xffffffff; t15 ^= (t >> 14) | (t << 18) + + x16 = x16+t00 & 0xffffffff + x17 = x17+t01 & 0xffffffff + x18 = x18+t02 & 0xffffffff + x19 = x19+t03 & 0xffffffff + x20 = x20+t04 & 0xffffffff + x21 = x21+t05 & 0xffffffff + x22 = x22+t06 & 0xffffffff + x23 = x23+t07 & 0xffffffff + x24 = x24+t08 & 0xffffffff + x25 = x25+t09 & 0xffffffff + x26 = x26+t10 & 0xffffffff + x27 = x27+t11 & 0xffffffff + x28 = x28+t12 & 0xffffffff + x29 = x29+t13 & 0xffffffff + x30 = x30+t14 & 0xffffffff + x31 = x31+t15 & 0xffffffff + + X[:] = [ + x00, x01, x02, x03, x04, x05, x06, x07, + x08, x09, x10, x11, x12, x13, x14, x15, + x16, x17, x18, x19, x20, x21, x22, x23, + x24, x25, x26, x27, x28, x29, x30, x31 + ] + + + +if __name__ == '__main__': + from binascii import unhexlify + + vectors = [ + ("00"*80, "161d0876f3b93b1048cda1bdeaa7332ee210f7131b42013cb43913a6553a4b69"), + ("ff"*80, "5253069c14ecedf978745486375ee37415e977f55cdbedac31ebee8bf33dd127"), + ("010000000000000000000000000000000000000000000000000000000000000000000000d9ced4ed1130f7b7faad9be25323ffafa33232a17c3edf6cfd97bee6bafbdd97b9aa8e4ef0ff0f1ecd513f7c", "001e67b013726fd7382e9acb69165b4b6316227fb3156b5b414ba6340c050000"), + ("01000000ae178934851bfa0e83ccb6a3fc4bfddff3641e104b6c4680c31509074e699be2bd672d8d2199ef37a59678f92443083e3b85edef8b45c71759371f823bab59a97126614f44d5001d45920180", "01796dae1f78a72dfb09356db6f027cd884ba0201e6365b72aa54b3b00000000"), + ("020000008f49e5fd7ef50db9a2a1bff5d3e93717a096329a8ac802a248463ef366ceea1099b1fd0db4ce8f4728251711f759081d0b5b4da015fb78421d8ffbfda1105a2abda1db521b64101b00e60cd0", "461ae94540dc88c9bffbf42bb47e46a2416280adbeeb1d883c18090000000000"), + ] + + from timeit import default_timer + t0 = default_timer() + + for header, hash in vectors: + assert scrypt_1024_1_1_80(unhexlify(header)) == unhexlify(hash) + + dt = (default_timer() - t0) / len(vectors) + print("%.1f ms/hash" % (dt*1000)) + print("%.2f hash/s" % (1.0 / dt)) diff --git a/lib/servers.json b/lib/servers.json index 1f6398584f18..8c9da79c4906 100644 --- a/lib/servers.json +++ b/lib/servers.json @@ -1,228 +1,5 @@ { - "E-X.not.fyi": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "ELECTRUMX.not.fyi": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "ELEX01.blackpole.online": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "VPS.hsmiths.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "bitcoin.freedomnode.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "btc.smsys.me": { - "pruning": "-", - "s": "995", - "version": "1.1" - }, - "currentlane.lovebitco.in": { - "pruning": "-", - "t": "50001", - "version": "1.1" - }, - "daedalus.bauerj.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "de01.hamster.science": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "ecdsa.net": { - "pruning": "-", - "s": "110", - "t": "50001", - "version": "1.1" - }, - "elec.luggs.co": { - "pruning": "-", - "s": "443", - "version": "1.1" - }, - "electrum.akinbo.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.antumbra.se": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.be": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.coinucopia.io": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.cutie.ga": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.festivaldelhumor.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.hsmiths.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.qtornado.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum.vom-stausee.de": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrum3.hachre.de": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrumx.bot.nu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "electrumx.westeurope.cloudapp.azure.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "elx01.knas.systems": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "ex-btc.server-on.net": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "helicarrier.bauerj.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "mooo.not.fyi": { - "pruning": "-", - "s": "50012", - "t": "50011", - "version": "1.1" - }, - "ndnd.selfhost.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "node.arihanc.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "node.xbt.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "node1.volatilevictory.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "noserver4u.de": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "qmebr.spdns.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "raspi.hsmiths.com": { - "pruning": "-", - "s": "51002", - "t": "51001", - "version": "1.1" - }, - "s2.noip.pl": { - "pruning": "-", - "s": "50102", - "version": "1.1" - }, - "s5.noip.pl": { - "pruning": "-", - "s": "50105", - "version": "1.1" - }, - "songbird.bauerj.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "us.electrum.be": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.1" - }, - "us01.hamster.science": { + "45.63.92.224": { "pruning": "-", "s": "50002", "t": "50001", diff --git a/lib/servers_testnet.json b/lib/servers_testnet.json index 4ec92007f2fe..08464002860e 100644 --- a/lib/servers_testnet.json +++ b/lib/servers_testnet.json @@ -1,8 +1,4 @@ { - "testnetnode.arihanc.com": {"t":"51001", "s":"51002"}, - "testnet1.bauerj.eu": {"t":"51001", "s":"51002"}, - "14.3.140.101": {"t":"51001", "s":"51002"}, - "testnet.hsmiths.com": {"t":"53011", "s":"53012"}, - "electrum.akinbo.org": {"t":"51001", "s":"51002"}, - "ELEX05.blackpole.online": {"t":"52011", "s":"52002"} + "electrum1.zcoin.io": {"t":"51001", "s":"51002"}, + "electrum2.zcoin.io": {"t":"51001", "s":"51002"} } diff --git a/lib/simple_config.py b/lib/simple_config.py index 072edccd0e05..979bbe1ca316 100644 --- a/lib/simple_config.py +++ b/lib/simple_config.py @@ -6,12 +6,9 @@ from copy import deepcopy from .util import (user_dir, print_error, PrintError, - NoDynamicFeeEstimates, format_satoshis) + NoDynamicFeeEstimates) -from .bitcoin import MAX_FEE_RATE - -FEE_ETA_TARGETS = [25, 10, 5, 2] -FEE_DEPTH_TARGETS = [10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000] +from .bitcoin import MAX_FEE_RATE, FEE_TARGETS config = None @@ -39,7 +36,7 @@ class SimpleConfig(PrintError): 2. User configuration (in the user's config directory) They are taken in order (1. overrides config options set in 2.) """ - fee_rates = [5000, 10000, 20000, 30000, 50000, 70000, 100000, 150000, 200000, 300000] + fee_rates = [100000, 125000, 150000, 200000, 250000, 300000, 400000, 500000, 700000, 1000000] def __init__(self, options=None, read_user_config_function=None, read_user_dir_function=None): @@ -51,7 +48,6 @@ def __init__(self, options=None, read_user_config_function=None, # a thread-safe way. self.lock = threading.RLock() - self.mempool_fees = {} self.fee_estimates = {} self.fee_estimates_last_updated = {} self.last_time_fee_estimates_requested = 0 # zero ensures immediate fees @@ -231,7 +227,7 @@ def get_wallet_path(self): new_path = os.path.join(self.path, "wallets", "default_wallet") # default path in pre 1.9 versions - old_path = os.path.join(self.path, "electrum.dat") + old_path = os.path.join(self.path, "electrum-xzc.dat") if os.path.exists(old_path) and not os.path.exists(new_path): os.rename(old_path, new_path) @@ -267,9 +263,9 @@ def max_fee_rate(self): f = MAX_FEE_RATE return f - def eta_to_fee(self, i): + def dynfee(self, i): if i < 4: - j = FEE_ETA_TARGETS[i] + j = FEE_TARGETS[i] fee = self.fee_estimates.get(j) else: assert i == 4 @@ -280,107 +276,18 @@ def eta_to_fee(self, i): fee = min(5*MAX_FEE_RATE, fee) return fee - def fee_to_depth(self, target_fee): - depth = 0 - for fee, s in self.mempool_fees: - depth += s - if fee <= target_fee: - break - else: - return 0 - return depth - - def depth_to_fee(self, i): - target = self.depth_target(i) - depth = 0 - for fee, s in self.mempool_fees: - depth += s - if depth > target: - break - else: - return 0 - return fee * 1000 - - def depth_target(self, i): - return FEE_DEPTH_TARGETS[i] - - def eta_target(self, i): - return FEE_ETA_TARGETS[i] - - def fee_to_eta(self, fee_per_kb): + def reverse_dynfee(self, fee_per_kb): import operator - l = list(self.fee_estimates.items()) + [(1, self.eta_to_fee(4))] + l = list(self.fee_estimates.items()) + [(1, self.dynfee(4))] + for i in range(len(l)-1, 0, -1): + if l[i][1] == l[i-1][1]: + del l[i-1] dist = map(lambda x: (x[0], abs(x[1] - fee_per_kb)), l) min_target, min_value = min(dist, key=operator.itemgetter(1)) if fee_per_kb < self.fee_estimates.get(25)/2: min_target = -1 return min_target - def depth_tooltip(self, depth): - return "%.1f MB from tip"%(depth/1000000) - - def eta_tooltip(self, x): - return 'Low fee' if x < 0 else 'Within %d blocks'%x - - def get_fee_status(self): - dyn = self.is_dynfee() - mempool = self.use_mempool_fees() - pos = self.get_depth_level() if mempool else self.get_fee_level() - fee_rate = self.fee_per_kb() - target, tooltip = self.get_fee_text(pos, dyn, mempool, fee_rate) - return target - - def get_fee_text(self, pos, dyn, mempool, fee_rate): - rate_str = (format_satoshis(fee_rate/1000, False, 0, 0, False) + ' sat/byte') if fee_rate is not None else 'unknown' - if dyn: - if mempool: - depth = self.depth_target(pos) - text = self.depth_tooltip(depth) - else: - eta = self.eta_target(pos) - text = self.eta_tooltip(eta) - tooltip = rate_str - else: - text = rate_str - if mempool: - if self.has_fee_mempool(): - depth = self.fee_to_depth(fee_rate) - tooltip = self.depth_tooltip(depth) - else: - tooltip = '' - else: - if self.has_fee_etas(): - eta = self.fee_to_eta(fee_rate) - tooltip = self.eta_tooltip(eta) - else: - tooltip = '' - return text, tooltip - - def get_depth_level(self): - maxp = len(FEE_DEPTH_TARGETS) - 1 - return min(maxp, self.get('depth_level', 2)) - - def get_fee_level(self): - maxp = len(FEE_ETA_TARGETS) - 1 - return min(maxp, self.get('fee_level', 2)) - - def get_fee_slider(self, dyn, mempool): - if dyn: - if mempool: - pos = self.get_depth_level() - maxp = len(FEE_DEPTH_TARGETS) - 1 - fee_rate = self.depth_to_fee(pos) - else: - pos = self.get_fee_level() - maxp = len(FEE_ETA_TARGETS) - 1 - fee_rate = self.eta_to_fee(pos) - else: - fee_rate = self.fee_per_kb() - pos = self.static_fee_index(fee_rate) - maxp = 9 - return maxp, pos, fee_rate - - def static_fee(self, i): return self.fee_rates[i] @@ -388,29 +295,21 @@ def static_fee_index(self, value): dist = list(map(lambda x: abs(x - value), self.fee_rates)) return min(range(len(dist)), key=dist.__getitem__) - def has_fee_etas(self): - return len(self.fee_estimates) == 4 - - def has_fee_mempool(self): - return bool(self.mempool_fees) + def has_fee_estimates(self): + return len(self.fee_estimates)==4 def is_dynfee(self): - return bool(self.get('dynamic_fees', True)) - - def use_mempool_fees(self): - return bool(self.get('mempool_fees', False)) + return self.get('dynamic_fees', False) def fee_per_kb(self): """Returns sat/kvB fee to pay for a txn. Note: might return None. """ - if self.is_dynfee(): - if self.use_mempool_fees(): - fee_rate = self.depth_to_fee(self.get_depth_level()) - else: - fee_rate = self.eta_to_fee(self.get_fee_level()) + dyn = self.is_dynfee() + if dyn: + fee_rate = self.dynfee(self.get('fee_level', 2)) else: - fee_rate = self.get('fee_per_kb', self.max_fee_rate()/2) + fee_rate = self.get('fee_per_kb', self.max_fee_rate()/10) return fee_rate def fee_per_byte(self): @@ -428,12 +327,7 @@ def estimate_fee(self, size): @classmethod def estimate_fee_for_feerate(cls, fee_per_kb, size): - # note: We only allow integer sat/byte values atm. - # The GUI for simplicity reasons only displays integer sat/byte, - # and for the sake of consistency, we thus only use integer sat/byte in - # the backend too. - fee_per_byte = int(fee_per_kb / 1000) - return int(fee_per_byte * size) + return int(fee_per_kb * size / 1000.) def update_fee_estimates(self, key, value): self.fee_estimates[key] = value @@ -461,7 +355,7 @@ def get_video_device(self): def read_user_config(path): - """Parse and store the user config settings in electrum.conf into user_config[].""" + """Parse and store the user config settings in electrum-xzc.conf into user_config[].""" if not path: return {} config_path = os.path.join(path, "config") diff --git a/lib/storage.py b/lib/storage.py index d87a339a8344..fa9911149d1e 100644 --- a/lib/storage.py +++ b/lib/storage.py @@ -33,7 +33,7 @@ import base64 import zlib -from .util import PrintError, profiler, InvalidPassword +from .util import PrintError, profiler from .plugins import run_hook, plugin_loaders from .keystore import bip44_derivation from . import bitcoin @@ -56,13 +56,6 @@ def multisig_type(wallet_type): match = [int(x) for x in match.group(1, 2)] return match -def get_derivation_used_for_hw_device_encryption(): - return ("m" - "/4541509'" # ascii 'ELE' as decimal ("BIP43 purpose") - "/1112098098'") # ascii 'BIE2' as decimal - -# storage encryption version -STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW = range(0, 3) class WalletStorage(PrintError): @@ -77,11 +70,9 @@ def __init__(self, path, manual_upgrades=False): if self.file_exists(): with open(self.path, "r") as f: self.raw = f.read() - self._encryption_version = self._init_encryption_version() if not self.is_encrypted(): self.load_data(self.raw) else: - self._encryption_version = STO_EV_PLAINTEXT # avoid new wallets getting 'upgraded' self.put('seed_version', FINAL_SEED_VERSION) @@ -115,47 +106,11 @@ def load_data(self, s): if self.requires_upgrade(): self.upgrade() - def is_past_initial_decryption(self): - """Return if storage is in a usable state for normal operations. - - The value is True exactly - if encryption is disabled completely (self.is_encrypted() == False), - or if encryption is enabled but the contents have already been decrypted. - """ - return bool(self.data) - def is_encrypted(self): - """Return if storage encryption is currently enabled.""" - return self.get_encryption_version() != STO_EV_PLAINTEXT - - def is_encrypted_with_user_pw(self): - return self.get_encryption_version() == STO_EV_USER_PW - - def is_encrypted_with_hw_device(self): - return self.get_encryption_version() == STO_EV_XPUB_PW - - def get_encryption_version(self): - """Return the version of encryption used for this storage. - - 0: plaintext / no encryption - - ECIES, private key derived from a password, - 1: password is provided by user - 2: password is derived from an xpub; used with hw wallets - """ - return self._encryption_version - - def _init_encryption_version(self): try: - magic = base64.b64decode(self.raw)[0:4] - if magic == b'BIE1': - return STO_EV_USER_PW - elif magic == b'BIE2': - return STO_EV_XPUB_PW - else: - return STO_EV_PLAINTEXT + return base64.b64decode(self.raw)[0:4] == b'BIE1' except: - return STO_EV_PLAINTEXT + return False def file_exists(self): return self.path and os.path.exists(self.path) @@ -165,50 +120,20 @@ def get_key(self, password): ec_key = bitcoin.EC_KEY(secret) return ec_key - def _get_encryption_magic(self): - v = self._encryption_version - if v == STO_EV_USER_PW: - return b'BIE1' - elif v == STO_EV_XPUB_PW: - return b'BIE2' - else: - raise Exception('no encryption magic for version: %s' % v) - def decrypt(self, password): ec_key = self.get_key(password) - if self.raw: - enc_magic = self._get_encryption_magic() - s = zlib.decompress(ec_key.decrypt_message(self.raw, enc_magic)) - else: - s = None + s = zlib.decompress(ec_key.decrypt_message(self.raw)) if self.raw else None self.pubkey = ec_key.get_public_key() s = s.decode('utf8') self.load_data(s) - def check_password(self, password): - """Raises an InvalidPassword exception on invalid password""" - if not self.is_encrypted(): - return - if self.pubkey and self.pubkey != self.get_key(password).get_public_key(): - raise InvalidPassword() - - def set_keystore_encryption(self, enable): - self.put('use_encryption', enable) - - def set_password(self, password, enc_version=None): - """Set a password to be used for encrypting this storage.""" - if enc_version is None: - enc_version = self._encryption_version - if password and enc_version != STO_EV_PLAINTEXT: + def set_password(self, password, encrypt): + self.put('use_encryption', bool(password)) + if encrypt and password: ec_key = self.get_key(password) self.pubkey = ec_key.get_public_key() - self._encryption_version = enc_version else: self.pubkey = None - self._encryption_version = STO_EV_PLAINTEXT - # make sure next storage.write() saves changes - with self.lock: - self.modified = True def get(self, key, default=None): with self.lock: @@ -250,8 +175,7 @@ def _write(self): if self.pubkey: s = bytes(s, 'utf8') c = zlib.compress(s) - enc_magic = self._get_encryption_magic() - s = bitcoin.encrypt_message(c, self.pubkey, enc_magic) + s = bitcoin.encrypt_message(c, self.pubkey) s = s.decode('utf8') temp_path = "%s.tmp.%s" % (self.path, os.getpid()) @@ -339,9 +263,6 @@ def upgrade(self): self.write() def convert_wallet_type(self): - if not self._is_upgrade_method_needed(0, 13): - return - wallet_type = self.get('wallet_type') if wallet_type == 'btchip': wallet_type = 'ledger' if self.get('keystore') or self.get('x1/') or wallet_type=='imported': @@ -525,9 +446,6 @@ def remove_from_list(list_name): self.put('seed_version', 16) def convert_imported(self): - if not self._is_upgrade_method_needed(0, 13): - return - # '/x' is the internal ID for imported accounts d = self.get('accounts', {}).get('/x', {}).get('imported',{}) if not d: @@ -554,9 +472,6 @@ def convert_imported(self): raise BaseException('no addresses or privkeys') def convert_account(self): - if not self._is_upgrade_method_needed(0, 13): - return - self.put('accounts', None) def _is_upgrade_method_needed(self, min_version, max_version): diff --git a/lib/tests/test_bitcoin.py b/lib/tests/test_bitcoin.py index dbae5005da4b..cb6b7fc6b759 100644 --- a/lib/tests/test_bitcoin.py +++ b/lib/tests/test_bitcoin.py @@ -63,17 +63,17 @@ def sign_message_with_wif_privkey(wif_privkey, msg): return key.sign_message(msg, compressed) sig1 = sign_message_with_wif_privkey( - 'L1TnU2zbNaAqMoVh65Cyvmcjzbrj41Gs9iTLcWbpJCMynXuap6UN', msg1) - addr1 = '15hETetDmcXm1mM4sEf7U2KXC9hDHFMSzz' + 'T7J3unHmmx9S8e8Zdi9r98A7wTW386HkxvMbUKEMsAY9JRWfbSe6', msg1) + addr1 = 'LPvBisC3rGmpGa3E3NeQk3PHQN4VS237y2' sig2 = sign_message_with_wif_privkey( - '5Hxn5C4SQuiV6e62A1MtZmbSeQyrLFhu5uYks62pU5VBUygK2KD', msg2) - addr2 = '1GPHVTY8UD9my6jyP4tb2TYJwUbDetyNC6' + '6uGWYKbyKLBMa1ysfq9rMANcbtYKY49vrawvaH3rBXooApLq6t2', msg2) + addr2 = 'LacEkfqxYsPqDuS8ZCstJUc59gxVm2DQaT' sig1_b64 = base64.b64encode(sig1) sig2_b64 = base64.b64encode(sig2) - self.assertEqual(sig1_b64, b'H/9jMOnj4MFbH3d7t4yCQ9i7DgZU/VZ278w3+ySv2F4yIsdqjsc5ng3kmN8OZAThgyfCZOQxZCWza9V5XzlVY0Y=') - self.assertEqual(sig2_b64, b'G84dmJ8TKIDKMT9qBRhpX2sNmR0y5t+POcYnFFJCs66lJmAs3T8A6Sbpx7KA6yTQ9djQMabwQXRrDomOkIKGn18=') + self.assertEqual(sig1_b64, b'IHGAMaPxjrn3CD19S7J5KAq4xF6mdLznsSL8SrqhNwficUHlK5wSth6/JiZ/pEyo92nkUoA+kL9VJpjLnKJKTmM=') + self.assertEqual(sig2_b64, b'G14KtfFZQYjyhz4PUzX/yz8eEC1BFHsaEKZOJGLeTWJoNp/umpi5zPeCvhUcgSoMtAkmw3pATrM2bcDdYi1tqIs=') self.assertTrue(verify_message(addr1, sig1, msg1)) self.assertTrue(verify_message(addr2, sig2, msg2)) @@ -149,18 +149,18 @@ def test_op_push(self): def test_address_to_script(self): # bech32 native segwit # test vectors from BIP-0173 - self.assertEqual(address_to_script('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4'), '0014751e76e8199196d454941c45d1b3a323f1433bd6') - self.assertEqual(address_to_script('bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx'), '5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6') - self.assertEqual(address_to_script('BC1SW50QA3JX3S'), '6002751e') - self.assertEqual(address_to_script('bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj'), '5210751e76e8199196d454941c45d1b3a323') + self.assertEqual(address_to_script('XZC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KGMN4N9'), '0014751e76e8199196d454941c45d1b3a323f1433bd6') + self.assertEqual(address_to_script('xzc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k0tul4w'), '5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6') + self.assertEqual(address_to_script('XZC1SW50QZGYDF5'), '6002751e') + self.assertEqual(address_to_script('xzc1zw508d6qejxtdg4y5r3zarvaryvdzur3w'), '5210751e76e8199196d454941c45d1b3a323') # base58 P2PKH - self.assertEqual(address_to_script('14gcRovpkCoGkCNBivQBvw7eso7eiNAbxG'), '76a91428662c67561b95c79d2257d2a93d9d151c977e9188ac') - self.assertEqual(address_to_script('1BEqfzh4Y3zzLosfGhw1AsqbEKVW6e1qHv'), '76a914704f4b81cadb7bf7e68c08cd3657220f680f863c88ac') + self.assertEqual(address_to_script('LNuZh2Eeps3L114Lu4PVCxBR61UvqcAb8p'), '76a91428662c67561b95c79d2257d2a93d9d151c977e9188ac') + self.assertEqual(address_to_script('LVTnwCztciF3bcZpSqvJStuMSXrnDt1pUU'), '76a914704f4b81cadb7bf7e68c08cd3657220f680f863c88ac') # base58 P2SH - self.assertEqual(address_to_script('35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT'), 'a9142a84cf00d47f699ee7bbc1dea5ec1bdecb4ac15487') - self.assertEqual(address_to_script('3PyjzJ3im7f7bcV724GR57edKDqoZvH7Ji'), 'a914f47c8954e421031ad04ecd8e7752c9479206b9d387') + self.assertEqual(address_to_script('MBmyiC29MUQSfPC2gKtdrazbSWHvGqJCnU'), 'a9142a84cf00d47f699ee7bbc1dea5ec1bdecb4ac15487') + self.assertEqual(address_to_script('MWBtJBTgiEWYQ7m17wFktku2dvSFZXqhWZ'), 'a914f47c8954e421031ad04ecd8e7752c9479206b9d387') class Test_bitcoin_testnet(unittest.TestCase): @@ -178,16 +178,16 @@ def tearDownClass(cls): def test_address_to_script(self): # bech32 native segwit # test vectors from BIP-0173 - self.assertEqual(address_to_script('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7'), '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262') - self.assertEqual(address_to_script('tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy'), '0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433') + self.assertEqual(address_to_script('txzc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qsnr4fp'), '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262') + self.assertEqual(address_to_script('txzc1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesu9tmgm'), '0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433') # base58 P2PKH self.assertEqual(address_to_script('mutXcGt1CJdkRvXuN2xoz2quAAQYQ59bRX'), '76a9149da64e300c5e4eb4aaffc9c2fd465348d5618ad488ac') self.assertEqual(address_to_script('miqtaRTkU3U8rzwKbEHx3g8FSz8GJtPS3K'), '76a914247d2d5b6334bdfa2038e85b20fc15264f8e5d2788ac') # base58 P2SH - self.assertEqual(address_to_script('2N3LSvr3hv5EVdfcrxg2Yzecf3SRvqyBE4p'), 'a9146eae23d8c4a941316017946fc761a7a6c85561fb87') - self.assertEqual(address_to_script('2NE4ZdmxFmUgwu5wtfoN2gVniyMgRDYq1kk'), 'a914e4567743d378957cd2ee7072da74b1203c1a7a0b87') + self.assertEqual(address_to_script('QWhD3ruwwBHamrNuan4a5M46BpskgXmWih'), 'a9146eae23d8c4a941316017946fc761a7a6c85561fb87') + self.assertEqual(address_to_script('QhRKknpVnak33GhwHuQ3mCEA7k8F4zxDXG'), 'a914e4567743d378957cd2ee7072da74b1203c1a7a0b87') class Test_xprv_xpub(unittest.TestCase): @@ -270,17 +270,17 @@ def test_is_bip32_derivation(self): class Test_keyImport(unittest.TestCase): priv_pub_addr = ( - {'priv': 'KzMFjMC2MPadjvX5Cd7b8AKKjjpBSoRKUTpoAtN6B3J9ezWYyXS6', + {'priv': 'T6BXB6VCkmZEWm9wkG4TLWrhgbTVWtSDHfj42gzdk1UKAt3qZMPk', 'pub': '02c6467b7e621144105ed3e4835b0b4ab7e35266a2ae1c4f8baa19e9ca93452997', - 'address': '17azqT8T16coRmWKYFj3UjzJuxiYrYFRBR', + 'address': 'LRox6fSH5krrgaCUiPiLkm458B5pyG8vxq', 'minikey' : False, 'txin_type': 'p2pkh', 'compressed': True, 'addr_encoding': 'base58', 'scripthash': 'c9aecd1fef8d661a42c560bf75c8163e337099800b8face5ca3d1393a30508a7'}, - {'priv': '5Hxn5C4SQuiV6e62A1MtZmbSeQyrLFhu5uYks62pU5VBUygK2KD', + {'priv': '6uGWYKbyKLBMa1ysfq9rMANcbtYKY49vrawvaH3rBXooApLq6t2', 'pub': '04e5fe91a20fac945845a5518450d23405ff3e3e1ce39827b47ee6d5db020a9075422d56a59195ada0035e4a52a238849f68e7a325ba5b2247013e0481c5c7cb3f', - 'address': '1GPHVTY8UD9my6jyP4tb2TYJwUbDetyNC6', + 'address': 'LacEkfqxYsPqDuS8ZCstJUc59gxVm2DQaT', 'minikey': False, 'txin_type': 'p2pkh', 'compressed': False, @@ -288,7 +288,7 @@ class Test_keyImport(unittest.TestCase): 'scripthash': 'f5914651408417e1166f725a5829ff9576d0dbf05237055bf13abd2af7f79473'}, {'priv': 'LHJnnvRzsdrTX2j5QeWVsaBkabK7gfMNqNNqxnbBVRaJYfk24iJz', 'pub': '0279ad237ca0d812fb503ab86f25e15ebd5fa5dd95c193639a8a738dcd1acbad81', - 'address': '3GeVJB3oKr7psgKR6BTXSxKtWUkfsHHhk7', + 'address': 'MNrdc4TmGxyFgBbKC4SsGbaHqBM7uzsjTf', 'minikey': False, 'txin_type': 'p2wpkh-p2sh', 'compressed': True, @@ -296,7 +296,7 @@ class Test_keyImport(unittest.TestCase): 'scripthash': 'd7b04e882fa6b13246829ac552a2b21461d9152eb00f0a6adb58457a3e63d7c5'}, {'priv': 'L8g5V8kFFeg2WbecahRSdobARbHz2w2STH9S8ePHVSY4fmia7Rsj', 'pub': '03e9f948421aaa89415dc5f281a61b60dde12aae3181b3a76cd2d849b164fc6d0b', - 'address': 'bc1qqmpt7u5e9hfznljta5gnvhyvfd2kdd0r90hwue', + 'address': 'xzc1qqmpt7u5e9hfznljta5gnvhyvfd2kdd0rpnd2yf', 'minikey': False, 'txin_type': 'p2wpkh', 'compressed': True, @@ -305,7 +305,7 @@ class Test_keyImport(unittest.TestCase): # from http://bitscan.com/articles/security/spotlight-on-mini-private-keys {'priv': 'SzavMBLoXU6kDrqtUVmffv', 'pub': '02588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc9', - 'address': '19GuvDvMMUZ8vq84wT79fvnvhMd5MnfTkR', + 'address': 'LTVsBSEBS8oCBdpE7b6SwwrguZzMUnjsWr', 'minikey': True, 'txin_type': 'p2pkh', 'compressed': True, # this is actually ambiguous... issue #2748 diff --git a/lib/tests/test_storage_upgrade.py b/lib/tests/test_storage_upgrade.py index a91b881739fe..845cf9e253d4 100644 --- a/lib/tests/test_storage_upgrade.py +++ b/lib/tests/test_storage_upgrade.py @@ -12,12 +12,12 @@ class TestStorageUpgrade(WalletTestCase): def test_upgrade_from_client_1_9_8_seeded(self): - wallet_str = "{'addr_history':{'177hEYTccmuYH8u68pYfaLteTxwJrVgvJj':[],'15V7MsQK2vjF5aEXLVG11qi2eZPZsXdnYc':[],'1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf':[],'1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs':[],'1DjtUCcQwwzA3GSPA7Kd79PMnri7tLDPYC':[],'1PGEgaPG1XJqmuSj68GouotWeYkCtwo4wm':[],'1PAgpPxnL42Hp3cWxmSfdChPqqGiM8g7zj':[],'1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa':[]},'accounts_expanded':{},'master_public_key':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb','use_encryption':False,'seed':'2605aafe50a45bdf2eb155302437e678','accounts':{0:{0:['1DjtUCcQwwzA3GSPA7Kd79PMnri7tLDPYC','1PAgpPxnL42Hp3cWxmSfdChPqqGiM8g7zj','177hEYTccmuYH8u68pYfaLteTxwJrVgvJj','1PGEgaPG1XJqmuSj68GouotWeYkCtwo4wm','15V7MsQK2vjF5aEXLVG11qi2eZPZsXdnYc'],1:['1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs','1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa','1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf']}},'seed_version':4}" + wallet_str = "{'addr_history':{'LRLeVkmShS9bXwbFJxXxrMxQgBJb1CxRW4':[],'LPi4d5i97ayJLNvgWdFJHrmnrmkr3BAgdS':[],'LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2':[],'LbGiejb64pNXrjPZfiauVkchFQksBnFjrz':[],'LXxqjQvF2cEDJ58YLFJvPAT8155Q4q6D63':[],'LhVBwnh66BYu2i8tGGG7BpxGrm7Uz9RSMq':[],'LhPe5cGcQiGM4rJg8uRxuDmA43dzQUckM4':[],'Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy':[]},'accounts_expanded':{},'master_public_key':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb','use_encryption':False,'seed':'2605aafe50a45bdf2eb155302437e678','accounts':{0:{0:['LXxqjQvF2cEDJ58YLFJvPAT8155Q4q6D63','LhPe5cGcQiGM4rJg8uRxuDmA43dzQUckM4','LRLeVkmShS9bXwbFJxXxrMxQgBJb1CxRW4','LhVBwnh66BYu2i8tGGG7BpxGrm7Uz9RSMq','LPi4d5i97ayJLNvgWdFJHrmnrmkr3BAgdS'],1:['LbGiejb64pNXrjPZfiauVkchFQksBnFjrz','Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy','LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2']}},'seed_version':4}" self._upgrade_storage(wallet_str) # TODO pre-2.0 mixed wallets are not split currently #def test_upgrade_from_client_1_9_8_mixed(self): - # wallet_str = "{'addr_history':{'15V7MsQK2vjF5aEXLVG11qi2eZPZsXdnYc':[],'177hEYTccmuYH8u68pYfaLteTxwJrVgvJj':[],'1DjtUCcQwwzA3GSPA7Kd79PMnri7tLDPYC':[],'1PGEgaPG1XJqmuSj68GouotWeYkCtwo4wm':[],'1PAgpPxnL42Hp3cWxmSfdChPqqGiM8g7zj':[],'1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf':[],'1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs':[],'1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa':[]},'accounts_expanded':{},'master_public_key':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb','use_encryption':False,'seed':'2605aafe50a45bdf2eb155302437e678','accounts':{0:{0:['1DjtUCcQwwzA3GSPA7Kd79PMnri7tLDPYC','1PAgpPxnL42Hp3cWxmSfdChPqqGiM8g7zj','177hEYTccmuYH8u68pYfaLteTxwJrVgvJj','1PGEgaPG1XJqmuSj68GouotWeYkCtwo4wm','15V7MsQK2vjF5aEXLVG11qi2eZPZsXdnYc'],1:['1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs','1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa','1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf'],'mpk':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb'}},'imported_keys':{'15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA':'5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq','1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6':'L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U','1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr':'L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM'},'seed_version':4}" + # wallet_str = "{'addr_history':{'LPi4d5i97ayJLNvgWdFJHrmnrmkr3BAgdS':[],'LRLeVkmShS9bXwbFJxXxrMxQgBJb1CxRW4':[],'LXxqjQvF2cEDJ58YLFJvPAT8155Q4q6D63':[],'LhVBwnh66BYu2i8tGGG7BpxGrm7Uz9RSMq':[],'LhPe5cGcQiGM4rJg8uRxuDmA43dzQUckM4':[],'LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2':[],'LbGiejb64pNXrjPZfiauVkchFQksBnFjrz':[],'Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy':[]},'accounts_expanded':{},'master_public_key':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb','use_encryption':False,'seed':'2605aafe50a45bdf2eb155302437e678','accounts':{0:{0:['LXxqjQvF2cEDJ58YLFJvPAT8155Q4q6D63','LhPe5cGcQiGM4rJg8uRxuDmA43dzQUckM4','LRLeVkmShS9bXwbFJxXxrMxQgBJb1CxRW4','LhVBwnh66BYu2i8tGGG7BpxGrm7Uz9RSMq','LPi4d5i97ayJLNvgWdFJHrmnrmkr3BAgdS'],1:['LbGiejb64pNXrjPZfiauVkchFQksBnFjrz','Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy','LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2'],'mpk':'756d1fe6ded28d43d4fea902a9695feb785447514d6e6c3bdf369f7c3432fdde4409e4efbffbcf10084d57c5a98d1f34d20ac1f133bdb64fa02abf4f7bde1dfb'}},'imported_keys':{'LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM':'6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY','LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb':'T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5','LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY':'T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1'},'seed_version':4}" # self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_0_4_seeded(self): @@ -25,19 +25,19 @@ def test_upgrade_from_client_2_0_4_seeded(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_0_4_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"use_encryption":false,"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"use_encryption":false,"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_0_4_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_0_4_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_0_4_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]]},"labels":{"0":"Main account","1":"acc1"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]]},"labels":{"0":"Main account","1":"acc1"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_0_4_multisig(self): @@ -49,19 +49,19 @@ def test_upgrade_from_client_2_1_1_seeded(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_1_1_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_1_1_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_1_1_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"pruned_txo":{},"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_1_1_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"pruned_txo":{},"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"pruned_txo":{},"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_1_1_multisig(self): @@ -73,19 +73,19 @@ def test_upgrade_from_client_2_2_0_seeded(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_2_0_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":489714,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":489714,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_2_0_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_2_0_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_2_0_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"pruned_txo":{},"stored_height":490006,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"pruned_txo":{},"stored_height":490006,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_2_0_multisig(self): @@ -97,19 +97,19 @@ def test_upgrade_from_client_2_3_2_seeded(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_3_2_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":489715,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":489715,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_3_2_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_3_2_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"pruned_txo":{},"stored_height":0,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_3_2_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"pruned_txo":{},"stored_height":490008,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"labels":{},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"pruned_txo":{},"stored_height":490008,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_3_2_multisig(self): @@ -121,19 +121,19 @@ def test_upgrade_from_client_2_4_3_seeded(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_4_3_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"stored_height":477636,"use_encryption":false,"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"stored_height":477636,"use_encryption":false,"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_4_3_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported"}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_4_3_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"pruned_txo":{},"stored_height":485855,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"pruned_txo":{},"stored_height":485855,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_4_3_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]]},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"pruned_txo":{},"stored_height":490009,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]]},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"pruned_txo":{},"stored_height":490009,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor"}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_4_3_multisig(self): @@ -141,63 +141,63 @@ def test_upgrade_from_client_2_4_3_multisig(self): self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_5_4_seeded(self): - wallet_str = '{"accounts":{"0":{"change":["0253e61683b66ebf5a4916334adf1409ffe031016717868c9600d313e87538e745","021762e47578385ecedc03c7055da1713971c82df242920e7079afaf153cc37570","0303a8d6a35956c228aa95a17aab3dee0bca255e8b4f7e8155b23acef15cf4a974","02e881bc60018f9a6c566e2eb081a670f48d89b4a6615466788a4e2ce20246d4c6","02f0090e29817ef64c17f27bf6cdebc1222f7e11d7112073f45708e8d218340777","035b9c53b85fd0c2b434682675ac862bfcc7c5bb6993aee8e542f01d96ff485d67"],"receiving":["024fbc610bd51391794c40a7e04b0e4d4adeb6b0c0cc84ac0b3dad90544e428c47","024a2832afb0a366b149b6a64b648f0df0d28c15caa77f7bbf62881111d6915fe9","028cd24716179906bee99851a9062c6055ec298a3956b74631e30f5239a50cb328","039761647d7584ba83386a27875fe3d7715043c2817f4baca91e7a0c81d164d73d","02606fc2f0ce90edc495a617329b3c5c5cc46e36d36e6c66015b1615137278eabd","02191cc2986e33554e7b155f9eddcc3904fdba43a5a3638499d3b7b5452692b740","024b5bf755b2f65cab1f7e5505febc1db8b91781e5aac352902e79bc96ad7d9ad0","0309816cb047402b84133f4f3c5e56c215e860204513278beef54a87254e44c14a","03f53d34337c12ddb94950b1fee9e4a9cf06ad591db66194871d31a17ec7b59ac7","0325ede4b08073d7f288741c2c577878919fd5d832a9e6e04c9eac5563ae13aa83","02eca43081b04f68d6c8b81781acd59e5b8d2ba44dba195369afc40790fd9edef7","029a8ca96c64d3a98345be1594208908f2be5e6af6bcc6ff3681f271e75fcf232e","02fbe0804980750163a216cc91cfe86e907addf0e80797a8ea5067977eb4897c1b","0344f32fc1ee8b2eb08f419325529f495d77a3b5ea683bbce7a44178705ab59302","021dd62bdf18256bd5316ce3cbcca58785378058a41ba2d1c58f4cc76449b3c424","035e61cdbdb4306e58a816a19ad92c7ca3a392b67ac6d7257646868ffe512068c5","0326a4db82f21787d0246f8144abe6cda124383b7d93a6536f36c05af530ea262a","02b352a27a8f9c57b8e5c89b357ba9d0b5cb18bf623509b34cd881fcf8b89a819a","02a59188edef1ed29c158a0adb970588d2031cfe53e72e83d35b7e8dd0c0c77525","02e8b9e42a54d072c8887542c405f6c99cfabf41bdde639944b44ba7408837afd1"],"xpub":"xpub661MyMwAqRbcGh7ywNf1BYoFCs8mht2YnvkMYUJTazrAWbnbvkrisvSvrKGjRTDtw324xzprbDgphsmPv2pB6K5Sux3YNHC8pnJANCBY6vG"}},"accounts_expanded":{},"addr_history":{"12LXoVHUnAXn6BVBpshjwd7sSTwp5nsd7W":[],"12iXPYBErR6ZMESB9Nv74S4pVxdGMNLiW2":[],"13jmb5Vc2qh29tPhg637BwCJN7hStGWYXE":[],"14dHBBbwFVC7niSCqrb5HCHRK5K8rrgaW6":[],"14xsHuYGs4gKpRK3deuYwhMBTAwUeu2dpB":[],"15MpWMUasNVPTpzC5hK2AuVFwQ3AHd8fkv":[],"17nmvao3F84ebPrcv1LUxPUSS94U9EvCUt":[],"17yotEc8oUgJVQUnkjZSQjcqqZEbFFnXx8":[],"1A3c1rCCS2MYYobffyUHwPqkqE5ZpvG8Um":[],"1AtCzmcth79q6HgeyDnM3NLfr29hBHcfcg":[],"1AufJhUsMbqwbLK9JzUGQ9tTwphCQiVCwD":[],"1B77DkhJ8qHcwPQC2c1HyuNcYu5TzxxaJ7":[],"1D4bgjc4MDtEPWNTVfqG5bAodVu3D1Gjft":[],"1DefMPXdeCSQC5ieu8kR7hNGAXykNzWXpm":[],"1E673RESY1SvTWwUr5hQ1E7dGiRiSgkYFP":[],"1Ex6hnmpgp3FQrpR5aYvp9zpXemFiH7vky":[],"1FH2iAc5YgJKj1KcpJ1djuW3wJ2GbQezAv":[],"1GpjShJMGrLQGP6nZFDEswU7qUUgJbNRKi":[],"1H4BtV4Grfq2azQgHSNziN7MViQMDR9wxd":[],"1HnWq29dPuDRA7gx9HQLySGdwGWiNx4UP1":[],"1LMuebyhm8vnuw5qX3tqU2BhbacegeaFuE":[],"1LTJK8ffwJzRaNR5dDEKqJt6T8b4oVbaZx":[],"1LtXYvRr4j1WpLLA398nbmKhzhqq4abKi8":[],"1NfsUmibBxnuA3ir8GJvPUtY5czuiCfuYK":[],"1Q3cZjzADnnx5pcc1NN2ekJjLijNjXMXfr":[],"1okpBWorqo5WsBf5KmocsfhBCEDhNstW2":[]},"master_private_keys":{"x/":"xprv9s21ZrQH143K4D3WqM7zpQrWeqJHJRJhRhpkk5tr2fKBdoTTPDYUL88T12Ad9RHwViugcMbngkMDY626vD5syaFDoUB2cpLeraBaHvZHWFn"},"master_public_keys":{"x/":"xpub661MyMwAqRbcGh7ywNf1BYoFCs8mht2YnvkMYUJTazrAWbnbvkrisvSvrKGjRTDtw324xzprbDgphsmPv2pB6K5Sux3YNHC8pnJANCBY6vG"},"pruned_txo":{},"seed":"tent alien genius panic stage below spoon swap merge hammer gorilla squeeze ability","seed_version":11,"stored_height":489715,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"standard","winpos-qt":[100,100,840,400]}' + wallet_str = '{"accounts":{"0":{"change":["0253e61683b66ebf5a4916334adf1409ffe031016717868c9600d313e87538e745","021762e47578385ecedc03c7055da1713971c82df242920e7079afaf153cc37570","0303a8d6a35956c228aa95a17aab3dee0bca255e8b4f7e8155b23acef15cf4a974","02e881bc60018f9a6c566e2eb081a670f48d89b4a6615466788a4e2ce20246d4c6","02f0090e29817ef64c17f27bf6cdebc1222f7e11d7112073f45708e8d218340777","035b9c53b85fd0c2b434682675ac862bfcc7c5bb6993aee8e542f01d96ff485d67"],"receiving":["024fbc610bd51391794c40a7e04b0e4d4adeb6b0c0cc84ac0b3dad90544e428c47","024a2832afb0a366b149b6a64b648f0df0d28c15caa77f7bbf62881111d6915fe9","028cd24716179906bee99851a9062c6055ec298a3956b74631e30f5239a50cb328","039761647d7584ba83386a27875fe3d7715043c2817f4baca91e7a0c81d164d73d","02606fc2f0ce90edc495a617329b3c5c5cc46e36d36e6c66015b1615137278eabd","02191cc2986e33554e7b155f9eddcc3904fdba43a5a3638499d3b7b5452692b740","024b5bf755b2f65cab1f7e5505febc1db8b91781e5aac352902e79bc96ad7d9ad0","0309816cb047402b84133f4f3c5e56c215e860204513278beef54a87254e44c14a","03f53d34337c12ddb94950b1fee9e4a9cf06ad591db66194871d31a17ec7b59ac7","0325ede4b08073d7f288741c2c577878919fd5d832a9e6e04c9eac5563ae13aa83","02eca43081b04f68d6c8b81781acd59e5b8d2ba44dba195369afc40790fd9edef7","029a8ca96c64d3a98345be1594208908f2be5e6af6bcc6ff3681f271e75fcf232e","02fbe0804980750163a216cc91cfe86e907addf0e80797a8ea5067977eb4897c1b","0344f32fc1ee8b2eb08f419325529f495d77a3b5ea683bbce7a44178705ab59302","021dd62bdf18256bd5316ce3cbcca58785378058a41ba2d1c58f4cc76449b3c424","035e61cdbdb4306e58a816a19ad92c7ca3a392b67ac6d7257646868ffe512068c5","0326a4db82f21787d0246f8144abe6cda124383b7d93a6536f36c05af530ea262a","02b352a27a8f9c57b8e5c89b357ba9d0b5cb18bf623509b34cd881fcf8b89a819a","02a59188edef1ed29c158a0adb970588d2031cfe53e72e83d35b7e8dd0c0c77525","02e8b9e42a54d072c8887542c405f6c99cfabf41bdde639944b44ba7408837afd1"],"xpub":"xpub661MyMwAqRbcGh7ywNf1BYoFCs8mht2YnvkMYUJTazrAWbnbvkrisvSvrKGjRTDtw324xzprbDgphsmPv2pB6K5Sux3YNHC8pnJANCBY6vG"}},"accounts_expanded":{},"addr_history":{"LLZV4hbJrpmqLzBM11h3DeBdegK69wQPAW":[],"LLwUekV4w5Lcc38LKWuQLT8aiAzYUt6rV6":[],"LMxirHoS7Vw5Qh5rrE2QTxG4aL4j21r9LX":[],"LNrESPumL9SB3X8N1zaNZDMBXHgQybaGTT":[],"LPBpZ7r6wivP5E1ContrDiQwfPJkhWTbrF":[],"LPammZnQx2jSidgMFqJKSvZ29cQSNfc17S":[],"LS1jBo6sKnJhrCYn69KnEQYCeMRkDtkqkX":[],"LSCm9Suxt8vMkDAwvsYjgkgc3mbsQRfEne":[],"LUGZH4W2WgbbocHpr7TbDQuX3SSqxPLXLZ":[],"LV7AFyvimmPtM6Np9MmeKPQS4EWyG1kwBq":[],"LV8cZunhSG5zr91JV8TZgAxEA34UU4yR6h":[],"LVL4Uy18DVXgCC6MCjzbFvSNm7Sk6LpGsa":[],"LXHYwwutRt8HeK4cfopZMcEZqiGKLDy663":[],"LXsccbqTirgTStQp5GjiPiS2NkM2TDKFtF":[],"LYK4JdYGcfgyiKde2DghHFBPUvnzYgZLQp":[],"LZB3y15emUHJffWaFiYE6B4ajs8Xs23Lc1":[],"LZVyyNuudLYNyp1mzRzw1vZp9WPYobqd43":[],"Lb3ghucBMWaTXBnwjPCY9xXt3gqxSwt4GG":[],"LbH99hN6wL55qo6qTaNHzPB7hvmdKowJMY":[],"Lc1U6ETTUZTUQvP7KRPeFTLQ9UszVBUyZi":[],"LearupHXqoArAjmzhBt8k3FTonyvouya2f":[],"LegFaLyW1yEUqB7EoMDd7KwrfLxLrS7Yv6":[],"Lf7Up8jg9PFa592KDH85snPUCvD7CwMncF":[],"Lgtpjz2RGd2xQrR1JQJDfVxJHqNBtXWemb":[],"LiGZpxHzJT31LdJmBWMKvmNVYw6eunGpTP":[],"LL2i5PpdwW38mfspFTm6ttjTPQbVktGudJ":[]},"master_private_keys":{"x/":"xprv9s21ZrQH143K4D3WqM7zpQrWeqJHJRJhRhpkk5tr2fKBdoTTPDYUL88T12Ad9RHwViugcMbngkMDY626vD5syaFDoUB2cpLeraBaHvZHWFn"},"master_public_keys":{"x/":"xpub661MyMwAqRbcGh7ywNf1BYoFCs8mht2YnvkMYUJTazrAWbnbvkrisvSvrKGjRTDtw324xzprbDgphsmPv2pB6K5Sux3YNHC8pnJANCBY6vG"},"pruned_txo":{},"seed":"tent alien genius panic stage below spoon swap merge hammer gorilla squeeze ability","seed_version":11,"stored_height":489715,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"standard","winpos-qt":[100,100,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_5_4_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported","winpos-qt":[595,261,840,400]}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported","winpos-qt":[595,261,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_5_4_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported","winpos-qt":[406,393,840,400]}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported","winpos-qt":[406,393,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_5_4_trezor_singleacc(self): - wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"addr_history":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","18i2zqeCh6Gjto81KvVaeSM8YBUAkmgjRG"],"pruned_txo":{},"stored_height":490046,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor","winpos-qt":[522,328,840,400]}''' + wallet_str = '''{"accounts":{"0":{"change":["033608f89d381bcb9964df9da428d706d3eb30c14433af8de21bee2601e7392a80","0295c3905730d987ae9a9c09ad85c9c22c28aa414448f9d3450d8afb3da0d78890","038cf10bcf2bd3384f05974295fc83fc4e9cb48c0105995ad86d3ea237edb7e1d1","029b76e98f87c537165f016cf6840fe40c172ca0dba10278fb10e49a2b718cd156","034f08127c3651e5c5a65803e22dcbb1be10a90a79b699173ed0de82e0ceae862e","036013206a41aa6f782955b5a3b0e67f9a508ecd451796a2aa4ee7a02edef9fb7e"],"receiving":["020be78fa1a35e44fb1ee3141b40bd8d68330f12f98fdef5ba249b4d8c52a6a1ae","03f23e9a3b5337f322f720f533653349f6e97228d1c4a6feca36d4d1554aa19f74","03d3e7cfde0117561856e6e43d87852480c512910bfd1988c2ff1e6f6d795f7046","02ec56fc0bfe6a1466a783737919edbe83c8907af29a5ae672919ffcb1bb96303f","031b1d151f6584f9926614a7c335ee61606ff7a9769ca6e175ad99f9c7b5e9fb4d","03d782be0ace089e02529029b08ca9107b0e58302306de30bd9f9a3a1ed40c3717","0325784a4290eeeea1f99a928cf6c75c33417659dbd50a3a2850136dc3138ba631","035b7c1176926a54cdeb0342df5ecc7bb3fe1820fce99491fb50c091e3093f200f","02e0a2d615bff26a57754afa0e8ac8b692a79b399f6d04647398f377dcac4116be","026c7cee5bce1ae9e2fa930001ece81c35442a461fc9ef1266ac3d41b9f13e3bd5","0217b1d5066708e0cdaee99087c407db684131e34578adc7800dc66f329576c457","03ec0ed891b0ead00f1eaca7a4736d6816e348731d995bd4e77acbc8c582f68429","028cb4c682dde9692de47f71f3b16755cc440d722b84eed68db2b3d80bce83d50a","03d5d770a58d32b5d59b12861bbda37560fe7b789181b3349abf56223ea61b39c4","0250b6aee8338ac0497f2106b0ed014f5a2419c7bf429eb2b17a70bec77e6ff482","02565da9be6fc66a1e354638dcd8a4244e8733f38599c91c4f1ab0fb8d5d94fd2f","02e6c88509ff676b686afc2326370684bbc6edc0b31e09f312df4f7a17fe379e31","02224fef0921e61adcb2cd14ef45dbe4b859f1fcdc62eba26c6a7ce386c0a8f4b1","034c63da9c2a20132d9fd1088028de18f7ccd72458f9eb07a72452bd9994d28b1f","032bfe2fc88a55e19ba2338155b79e67b7d061d5fd1844bc8edc1808d998f8ba2c"],"xpub":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9"}},"accounts_expanded":{},"addr_history":{},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6D77dkWgEcSNBq7xDA1RUysGvD64QNy2TykC9UuRK6fEzqy3512HR2p2spstKCybkhDqkNStPWZKcnhwdD6kDYWJxsTQJhg9RCwifzcfJN9","x/1'":"xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG"},"next_account2":["1","xpub6D77dkWgEcSNFtXV2CQgsbfG33VyGMaUtUdpbdfMMHsS4WDzLtRapchQWcVBMFFjdRYjhkvQwGnJeKWPP3C2e1DevATAEUzL258Lhfkd7KG","03571f041921078b153a496638d703dfd1cee75e73c42653bbe0650ab6168d6a5b","LSvzG3x2mkWo9bpAW4UsvTQtkPqSoUkJop"],"pruned_txo":{},"stored_height":490046,"transactions":{},"txi":{},"txo":{},"wallet_type":"trezor","winpos-qt":[522,328,840,400]}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_5_4_trezor_multiacc(self): - wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"12bBPWWDwvtXrR9ntSgaQ7AnGyVJr16m5q":[],"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"13853om3ye5c8x6K1LfT3uCWEnG14Z82ML":[],"13BGVmizH8fk3qNm1biNZxAaQY3vPwurjZ":[],"13Tvp2DLQFpUxvc7JxAD3TXfAUWvjhwUiL":[],"15EQcTGzduGXSaRihKy1FY99EQQco8k2UW":[],"15paDwtQ33jJmJhjoBJhpWYGJDFCZppEF9":[],"17X8K766zBYLTjSNvHB9hA6SWRPMTcT556":[],"17zSo4aveNaE5DiTmwNZtxrJmS5ymzvwqj":[],"19BRVkUFfrAcxW9poaBSEUA2yv7SwN3SXh":[],"19gPT2mb9FQCiiPdAmMAaberShzNRiAtTB":[],"1A3vopoUcrWn7JbiAzGZactQz8HbnC1MoD":[],"1D1bn2Jzcx4D2GXbxzrJ1GwP4eNq98Q948":[],"1DvytpRGLJujPtSLYTRABzpy2r6hKJBYQd":[],"1EGg2acXNhJfv1bU3ixrbrmgxFtAUWpdY":[],"1Ev3S9YWxS7KWT8kyLmEuKV5sexNKcMUKV":[],"1FfpRnukxbfBnoudWvw9sdmc86YbVs7eGb":[],"1GBxNE82WLgd38CzoFTEkz6QS9EwLj1ym7":[],"1JFDe97zENNUiKeizcFUHss13vS2AcrVdE":[],"1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ":[],"1JQqX3yg6VYxL6unuRArDQaBZYo3ktSCCP":[],"1JUbrr4grE71ZgWNqm9z9ZHHJDcCzFYM4V":[],"1JuHUVbYfBLDUhTHx5tkDDyDbCnMsF8C9w":[],"1KZu7p244ETkdB5turRP4vhG2QJskARYWS":[],"1LE7jioE7y24m3MMZayRKpvdCy2Dz2LQae":[],"1LVr2pTU7LPQu8o8DqsxcGrvwu5rZADxfi":[],"1LmugnVryiuMbgdUAv3LucnRMLvqg8AstU":[],"1MPN5vptDZCXc11fZjpW1pvAgUZ5Ksh3ky":[]},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","1JGek3B8b3Nt3p39x27QK5UnFtNnZ2ZdGJ"],"pruned_txo":{},"stored_height":490009,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"12vWPzJtGLKRZjnYVtWSufjRuoE8pHLpmi":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor","winpos-qt":[757,469,840,400]}''' + wallet_str = '''{"accounts":{"0":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"],"xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"1":{"change":["03b0df486b4e1baa03ad565622820d692089b059c8f9fefa3567c3fa26d0cbaa34","0294c76c062c865873dccab84d51682f880e0197b64789c61bff85e1be2506925e","036f900d0c6bafbbcac0fbc95bed44954007faa182655cf69dc84d50c22e6edce8","03d1be74f1360ecede61ad1a294b2e53d64d44def67848e407ec835f6639d825ff","03a6a526cfadd510a47da95b074be250f5bb659b857b8432a6d317e978994c30b7","022216da9e351ae57174f93a972b0b09d788f5b240b5d29985174fbd2119a981a9"],"receiving":["02106878f6aefd9a81e1ca4a5f30ea0e1851aa36404fb62d19bd2325e180112b58","039e95f369e8d65aa7a7bf6a5d7d3259b827c1549c77c9b502b75a18f7708a9aa9","0273197861097be131542f8b7e03bc912934da51bc957d425be5bc7c1b69fb44ec","02b4c829b6a20815c5e1eef7ffd5d55c99505a7afeac5135ec2c97cfaae3483604","0312b1285272f1005c5834de2eec830ce9f9163c842d728c3921ae790716d8503f","0354059948c709c777a49a37e150271a3377f7aaee17798253d5240e4119f2a1c6","03800d87cc3878912d22a42a79db7ddbff3efec727d29ae1c0165730e5314483cd","03cafa35ad9adb41cff39e3bc2e0592d88c8b91981e73f068397e6c863c42c7b00","028668f734a4927e03621e319ab385919e891d248c86aea07ab922492d3d414ad3","02e42d46823893978ae7be9e032be21ce3e613cecb5ffe687b534795f90dc8ef85","03b86914af797e7b68940bc4ee2dec134036781a8e23ffaf4189ca7637e0afe898","021221ae9be51a9747aa7ebc2213a42a2364ce790ee86255277dc5f9beeb0bf6b4","03c8d58183f5d8102f8eb5f6db0f60add0a51ec6737097c46fc8a6b7c840d7571f","0304de0806b299cef4be3a162bac78f811d4adacc6a229ffdaeb7333bce72d88ff","03e08262e18616a3a9b9aecbfb8a860ccee147820a3c60050695ef72ff2cedc4a7","02caf4d61bb5deec29a39e5a1cc6d5987ec71d61d57c57bb5c2a47dd9266130bec","0252d429002d9c06f0befbef6c389bdd021969b416dd83d220394e414bd5d83c0a","024e23ce58533163df3e1d5766295144beb8f9729b1ac41e80ba485f39c483dfe6","026de9e7e6b11fbecd88b7b49915b5df64d672ef900aa043a8cac3bc79eb414089","02aaac08fc100014ec692efa0f3b408bf741e1dc68ebe28ce41837662810f40986","03e0d2b426705dcc5cb62c6113b10153f10624c926a3fe86142fd9020e7d6a2129"],"xpub":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH"}},"accounts_expanded":{},"addr_history":{"LLp8eip42b8b7Dqx4afsg8EYVBrb3XoDhJ":[],"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[["a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837",490002]],"LMM2K24t4JKfPknUBUekKvGGSzdHCEmtER":[],"LMQDkz2pMnuoJe4vBjhfqyELckRCXv6Joe":[],"LMgt5EXAUv4YDjJGV69WKUbRNgtCm3u6cc":[],"LPTMsfapiZWahP7ssTxJXZCuScmtxuRRmB":[],"LQ3XVACE7hyN27PtyKJ16Xc2WRcUcbzv5t":[],"LRk5aKPw4qnPiY8Y6RASyBACidkddJuXmS":[],"LSDQ4Gtkj2pHL2Qcx5MsAyv4yeTFzwuQ9P":[],"LTQNkxn5kWQgDJqyyiAjWVDoC8Uizu2sAX":[],"LTuLiF5RDueFyX5nLuLTrcicevMeaMTyUA":[],"LUGt537JhWkqN7HsM8FrrdxBCLestA2JqB":[],"LXEZ3EcphcJGH5Dm98qbHJ19Grk7AzFrW3":[],"LY9wA2j6Qy9neh8VibQTU1tjF4TyXiqHyg":[],"LKTDwEtSc2wMvihkeBiG8cvXuAdAEo5pWQ":[],"LZ8zhMrM36MNmFpv9UkYBLYr5sKeTwBMuz":[],"LZtmh1Db3FuF3cbnh4vT9eqNLJusZXGJG1":[],"LaQudSRrazvgHvu9yPSY31AAeMcDX3Wkoo":[],"LcUAuMRpK2cXy8LtAkEmZtvmG8oJGfEbV5":[],"LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT":[],"LcdnnGHWB9o1aubx5ZA9VRdwmmAKzT3F6W":[],"LchZ84NWvtM4pVCY1u9HRaM3WRyV7Wtpaq":[],"Ld8EjhuNjqaGjW9T8Dt3VF2yoR9dyUCK8Q":[],"LdnrP2Kt8thosyn45zQgLwm2Ecg9tRyzZ8":[],"LeT4zw74CdG81r3WjixibqzPRBPWBvuKeg":[],"LeioJ2mJBzdU9wVHPysFtHvhA7T8ejJbav":[],"Lezrwzoh4P9QrVKdM42eBdrBZZJ7jP6Amz":[],"LfcKM98iJDSarohpjsooHqyvtgvMW6sc61":[]},"labels":{"0":"Main account"},"master_public_keys":{"x/0'":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y","x/1'":"xpub6BycoSLDNcWjFs4B6T82q4zCbJBJdzQLwburAtBAwTLPyDPtkotGUWbef1t8D6XuCs6Yz5FUgFaL2hNzCTGe8F1bf9vNyXFMgLyKV65C9BH","x/2'":"xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa"},"next_account2":["2","xpub6BycoSLDNcWjHWrJyJJYmq9dDwBxSkFbWeaFFcrB6zBH9JTvyRVbAoWcmbPRmxicUkiutGQWqfsom9CbKSVG8Zh5HqHyR25xHE1xxmHeNYa","031b68cff8114df7677c4fe80619b701ea966428ecbeba55c9224cd8149cc5f05e","LcVc1FUxfhcwJcjK8A6hb6YYU6k4e4MLdT"],"pruned_txo":{},"stored_height":490009,"transactions":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":"01000000018394dfaba83ca6f510f622ecf95b445e856eab3193cb0dad53e1262841149d5f00000000da0047304402207761cdbf009c0bd3864c6a457288cadfa565601f782cc09f0046926d54a1b68b022060b73a7babb5dfd5188c4697cfcab6c15c4dd3de8507d39722e3a6b728f697dc01483045022100a540921229b02c4cfbf2d57222a455cbb4a5bd09bff063749fb71292f720850a02204dd18369213ec4cb033cbf222e8439eb8a9dd0a1b864bfeefa44cfe0c0066ee401475221025966a0193194a071e71501f9f8987111f7364bd8105a006f908b1f743da8d353210397c83f4963bdf333f129ab8000d89536bfea0971fc7578fdff5c2104b296c4d252aefdffffff0288130000000000001976a9141516b5e9653ab1fb09180186077fc2d7dfa07e5788aca0ba09000000000017a9148132c19d6b9abba9ec978ca5269d577ae104541e8700000000"},"txi":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{}},"txo":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":{"LM9TfCciLzZUpYUhg2VkBgoC81bQwrav4C":[[0,5000,false]]}},"verified_tx3":{"a242aeff746aa481c5d8a496111039262f2a3fbde6038124301522539fa06837":[490002,1508090436,607]},"wallet_type":"trezor","winpos-qt":[757,469,840,400]}''' self._upgrade_storage(wallet_str, accounts=2) def test_upgrade_from_client_2_5_4_multisig(self): - wallet_str = '{"accounts":{"0":{"change":[["02a63209b49df0bb98d8a262e9891fe266ffdce4be09d5e1ffaf269a10d7e7a17c","02a074035006ed8ee8f200859c004c073b687140f7d40bd333cdbbe43bad1e50bc"],["0280e2367142669e08e27fb9fd476076a7f34f596e130af761aef54ec54954a64d","02719a66c59f76c36921cf7b330fca7aaa4d863ee367828e7d89cd2f1aad98c3ac"],["0332083e80df509d3bd8a06538ca20030086c9ed3313300f7313ed98421482020f","032f336744f53843d8a007990fa909e35e42e1e32460fae2e0fc1aef7c2cff2180"],["03fe014e5816497f9e27d26ce3ae8d374edadec410227b2351e9e65eb4c5d32ab7","0226edd8c3af9e339631145fd8a9f6d321fdc52fe0dc8e30503541c348399dd52a"],["03e6717b18d7cbe264c6f5d0ad80f915163f6f6c08c121ac144a7664b95aedfdf3","03d69a074eba3bc2c1c7b1f6f85822be39aee20341923e406c2b445c255545394a"],["023112f87a5b9b2eadc73b8d5657c137b50609cd83f128d130172a0ed9e3fea9bc","029a81fd5ba57a2c2c6cfbcb34f369d87af8759b66364d5411eddd28e8a65f67fa"]],"m":2,"receiving":[["03c35c3da2c864ee3192a847ffd3f67fa59c095d8c2c0f182ed9556308ec37231e","03cfcb6d1774bfd916bd261232645f6c765da3401bf794ab74e84a6931d8318786"],["03973c83f84a4cf5d7b21d1e8b29d6cbd4cb40d7460166835cd1e1fd2418cfcf2e","03596801e66976959ac1bdb4025d65a412d95d320ed9d1280ac3e89b041e663cf4"],["02b78ac89bfdf90559f24313d7393af272092827efc33ba3a0d716ee8b75fd08ff","038e21fae8a033459e15a700551c1980131eb555bbb8b23774f8851aa10dcac6b8"],["0288e9695bb24f336421d5dcf16efb799e7d1f8284413fe08e9569588bc116567e","027123ba3314f77a8eb8bb57ba1015dd6d61b709420f6a3320ba4571b728ef2d91"],["0312e1483f7f558aef1a14728cc125bb4ee5cff0e7fa916ba8edd25e3ebceb05e9","02dad92a9893ad95d3be5ebc40828cef080e4317e3a47af732127c3fee41451356"],["03a694e428a74d37194edc9e231e68399767fdb38a20eca7b72caf81b7414916a8","03129a0cef4ed428031972050f00682974b3d9f30a571dc3917377595923ac41d8"],["026ed41491a6d0fb3507f3ca7de7fb2fbfdfb28463ae2b91f2ab782830d8d5b32c","03211b3c30c41d54734b3f13b8c9354dac238d82d012839ee0199b2493d7e7b6fc"],["03480e87ffa55a96596be0af1d97bca86987741eb5809675952a854d59f5e8adc2","0215f04df467d411e2a9ed8883a21860071ab721314503019a10ed30e225e522e7"],["0389fce63841e9231d5890b1a0c19479f8f40f4f463ef8e54ef306641abe545ac8","02396961d498c2dcb3c7081b50c5a4df15fda31300285a4c779a59c9abc98ea20d"],["03d4a3053e9e08dc21a334106b5f7d9ac93e42c9251ceb136b83f1a614925eb1fb","025533963c22b4f5fbfe75e6ee5ad7ee1c7bff113155a7695a408049e0b16f1c52"],["038a07c8d2024b9118651474bd881527e8b9eb85fc90fdcb04c1e38688d498de4b","03164b188eb06a3ea96039047d0db1c8f9be34bfd454e35471b1c2f429acd40afb"],["0214070cd393f39c062ce1e982a8225e5548dbbbd654aeba6d36bfcc7a685c7b12","029c6a9fb61705cc39bef34b09c684a362d4862b16a3b0b39ca4f94d75cd72290c"],["027b3497f72f581fea0a678bc20482b6fc7b4b507f7263d588001d73fdf5fe314e","021b80b159d19b6978a41c2a6bf7d3448bc73001885f933f7854f450b5873091f3"],["0303e9d76e4fe7336397c760f6fdfd5fb7500f83e491efb604fa2442db6e1da417","03a8d1b22a73d4c181aecd8cfe8bb2ee30c5dd386249d2a5a3b071b7a25b9da73a"],["0298e472b74832af856fb68eed02ff00a235fd0424d833bc305613e9f44087d0ee","03bb9bc2e4aaa9b022b35c8d122dfccb6c28ae8f0996a8fb4a021af8ec96a7beaf"],["02e933a4afb354500da03373514247e1be12e67cc4683e0cb82f508878cc3cc048","02c07a57b071bc449a95dd80308e53b26e4ebf4d523f620eecb17f96ae3aa814e9"],["03f73476951078b3ccc549bc7e6362797aaaacb1ea0edc81404b4d16cb321255a3","03b3a825fb9fc497e568fba69f70e2c3dcdc793637e242fce578546fcbd33cb312"],["03bbdf99fddeea64a96bbb9d1e6d7ced571c9c7757045dcbd8c40137125b017dc5","03aedf4452afefb1c3da25e698f621cb3a3a0130aa299488e018b93a45b5e6c21d"],["03b85891edb147d43c0a5935a20d6bbf8d32c542bfecccf3ae0158b65bd639b34e","03b34713c636a1c103b82d6cec917d442c59522ddc5a60bf7412266dd9790e7760"],["028ddf53b85f6c01122a96bd6c181ee17ca222ee9eca85bdeeb25c4b5315005e3b","02f4821995bfd5d0adb7a78d6e3a967ac72ace9d9a4f9392aff2711533893e017b"]],"xpubs":["xpub661MyMwAqRbcGHtCYBSGGVgMSihroMkuyE25GPyzfQvS2vSFG7SgJYf7rtXJjMh7srBJj8WddLtjapHnUQLwJ7kxsy5HiNZnGvF9pm2du7b","xpub661MyMwAqRbcEdd7bzA86LbhMoTv8NeyqcNP5z1Tiz9ajCRQDzdeXHw3h5ucDNGWr6mPFCZBcBE31VNKyR3vWM7WEeisu5m4VsCyuA6H8fp"]}},"accounts_expanded":{},"addr_history":{"32JvbwfEGJwZHGm3nwYiXyfsnGCb3L8hMX":[],"32pWy5sKkQsjyDz45tog47cA8vQyzC3UUZ":[],"334yqX1WtS6mY2vize7znTaL64HspwVkGF":[],"33GY9w6a4XmLAWxNgNFFRXTTRxbu3Nz8ip":[],"33geBcyW8Bw53EgAv3qwMVkVnvxZWj5J1X":[],"35BneogkCNxSiSN1YLmhKLP8giDbGkZiTX":[],"37U4J5b9B7rQnQXYstMoQnb6i9aWpptnLi":[],"37gqbHdbrCcGyrNF21AiDkofVCie5LpFmQ":[],"37t1Q5R92co4by2aagtLcqdWTDEzFuAuwZ":[],"37z3ruAHCxnzeJeLz96ZpkbwS3CLbtXtPc":[],"39qePsKaeviFEMC6CWX37DqaQda4jA2E6A":[],"3A5eratrDWu4SqsoHpuqswNsQmp9k8TXR2":[],"3B1N3PG5dNPYsTAuHFbVfkwXeZqqNS1CuP":[],"3BABbvd3eAuwiqJwppm54dJauKnRUieQU8":[],"3CAsH7BJnNT4kmwrbG8XZMMwW6ue8w4auJ":[],"3CX2GLCTfpFHSgAmbGRmuDKGHMbWY8tCp7":[],"3CrLUTVHuG1Y3swny9YDmkfJ89iHHU93NB":[],"3CxRa6yAQ2N2rpDHyUTaViGG4XVASAqwAN":[],"3DLTrsdYabso7QpxoLSW5ZFjLxBwrLEqqW":[],"3GG3APgrdDCTmC9tTwWu3sNV9aAnpFcddA":[],"3JDWpTxnsKoKut9WdG4k933qmPE5iJ8hRR":[],"3LdHoahj7rHRrQVe38D4iN43ySBpW5HQRZ":[],"3Lt56BqiJwZ1um1FtXJXzbY5uk32GVBa8K":[],"3MM9417myjN7ubMDkaK1wQ9RbjEc1zHCRH":[],"3NTivFVXva4DCjPmsf5p5Gt1dmuV39qD2v":[],"3QCwtjMywMtT3Vg6BwS146LcQjJnZPAPHZ":[]},"master_private_keys":{"x1/":"xprv9s21ZrQH143K29YeVxd7jCexomdRiuw8UPSnHbbrAecbrQ6FgTKPyVcZqp2256L5DSTdb8UepPVaDwJecswTrEhdyZiaNGERJpfzWV5FcN5"},"master_public_keys":{"x1/":"xpub661MyMwAqRbcEdd7bzA86LbhMoTv8NeyqcNP5z1Tiz9ajCRQDzdeXHw3h5ucDNGWr6mPFCZBcBE31VNKyR3vWM7WEeisu5m4VsCyuA6H8fp","x2/":"xpub661MyMwAqRbcGHtCYBSGGVgMSihroMkuyE25GPyzfQvS2vSFG7SgJYf7rtXJjMh7srBJj8WddLtjapHnUQLwJ7kxsy5HiNZnGvF9pm2du7b"},"pruned_txo":{},"seed":"park dash merit trend life field acid wrap dinosaur kit bar hotel abuse","seed_version":11,"stored_height":490034,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"2of2","winpos-qt":[564,329,840,400]}' + wallet_str = '{"accounts":{"0":{"change":[["02a63209b49df0bb98d8a262e9891fe266ffdce4be09d5e1ffaf269a10d7e7a17c","02a074035006ed8ee8f200859c004c073b687140f7d40bd333cdbbe43bad1e50bc"],["0280e2367142669e08e27fb9fd476076a7f34f596e130af761aef54ec54954a64d","02719a66c59f76c36921cf7b330fca7aaa4d863ee367828e7d89cd2f1aad98c3ac"],["0332083e80df509d3bd8a06538ca20030086c9ed3313300f7313ed98421482020f","032f336744f53843d8a007990fa909e35e42e1e32460fae2e0fc1aef7c2cff2180"],["03fe014e5816497f9e27d26ce3ae8d374edadec410227b2351e9e65eb4c5d32ab7","0226edd8c3af9e339631145fd8a9f6d321fdc52fe0dc8e30503541c348399dd52a"],["03e6717b18d7cbe264c6f5d0ad80f915163f6f6c08c121ac144a7664b95aedfdf3","03d69a074eba3bc2c1c7b1f6f85822be39aee20341923e406c2b445c255545394a"],["023112f87a5b9b2eadc73b8d5657c137b50609cd83f128d130172a0ed9e3fea9bc","029a81fd5ba57a2c2c6cfbcb34f369d87af8759b66364d5411eddd28e8a65f67fa"]],"m":2,"receiving":[["03c35c3da2c864ee3192a847ffd3f67fa59c095d8c2c0f182ed9556308ec37231e","03cfcb6d1774bfd916bd261232645f6c765da3401bf794ab74e84a6931d8318786"],["03973c83f84a4cf5d7b21d1e8b29d6cbd4cb40d7460166835cd1e1fd2418cfcf2e","03596801e66976959ac1bdb4025d65a412d95d320ed9d1280ac3e89b041e663cf4"],["02b78ac89bfdf90559f24313d7393af272092827efc33ba3a0d716ee8b75fd08ff","038e21fae8a033459e15a700551c1980131eb555bbb8b23774f8851aa10dcac6b8"],["0288e9695bb24f336421d5dcf16efb799e7d1f8284413fe08e9569588bc116567e","027123ba3314f77a8eb8bb57ba1015dd6d61b709420f6a3320ba4571b728ef2d91"],["0312e1483f7f558aef1a14728cc125bb4ee5cff0e7fa916ba8edd25e3ebceb05e9","02dad92a9893ad95d3be5ebc40828cef080e4317e3a47af732127c3fee41451356"],["03a694e428a74d37194edc9e231e68399767fdb38a20eca7b72caf81b7414916a8","03129a0cef4ed428031972050f00682974b3d9f30a571dc3917377595923ac41d8"],["026ed41491a6d0fb3507f3ca7de7fb2fbfdfb28463ae2b91f2ab782830d8d5b32c","03211b3c30c41d54734b3f13b8c9354dac238d82d012839ee0199b2493d7e7b6fc"],["03480e87ffa55a96596be0af1d97bca86987741eb5809675952a854d59f5e8adc2","0215f04df467d411e2a9ed8883a21860071ab721314503019a10ed30e225e522e7"],["0389fce63841e9231d5890b1a0c19479f8f40f4f463ef8e54ef306641abe545ac8","02396961d498c2dcb3c7081b50c5a4df15fda31300285a4c779a59c9abc98ea20d"],["03d4a3053e9e08dc21a334106b5f7d9ac93e42c9251ceb136b83f1a614925eb1fb","025533963c22b4f5fbfe75e6ee5ad7ee1c7bff113155a7695a408049e0b16f1c52"],["038a07c8d2024b9118651474bd881527e8b9eb85fc90fdcb04c1e38688d498de4b","03164b188eb06a3ea96039047d0db1c8f9be34bfd454e35471b1c2f429acd40afb"],["0214070cd393f39c062ce1e982a8225e5548dbbbd654aeba6d36bfcc7a685c7b12","029c6a9fb61705cc39bef34b09c684a362d4862b16a3b0b39ca4f94d75cd72290c"],["027b3497f72f581fea0a678bc20482b6fc7b4b507f7263d588001d73fdf5fe314e","021b80b159d19b6978a41c2a6bf7d3448bc73001885f933f7854f450b5873091f3"],["0303e9d76e4fe7336397c760f6fdfd5fb7500f83e491efb604fa2442db6e1da417","03a8d1b22a73d4c181aecd8cfe8bb2ee30c5dd386249d2a5a3b071b7a25b9da73a"],["0298e472b74832af856fb68eed02ff00a235fd0424d833bc305613e9f44087d0ee","03bb9bc2e4aaa9b022b35c8d122dfccb6c28ae8f0996a8fb4a021af8ec96a7beaf"],["02e933a4afb354500da03373514247e1be12e67cc4683e0cb82f508878cc3cc048","02c07a57b071bc449a95dd80308e53b26e4ebf4d523f620eecb17f96ae3aa814e9"],["03f73476951078b3ccc549bc7e6362797aaaacb1ea0edc81404b4d16cb321255a3","03b3a825fb9fc497e568fba69f70e2c3dcdc793637e242fce578546fcbd33cb312"],["03bbdf99fddeea64a96bbb9d1e6d7ced571c9c7757045dcbd8c40137125b017dc5","03aedf4452afefb1c3da25e698f621cb3a3a0130aa299488e018b93a45b5e6c21d"],["03b85891edb147d43c0a5935a20d6bbf8d32c542bfecccf3ae0158b65bd639b34e","03b34713c636a1c103b82d6cec917d442c59522ddc5a60bf7412266dd9790e7760"],["028ddf53b85f6c01122a96bd6c181ee17ca222ee9eca85bdeeb25c4b5315005e3b","02f4821995bfd5d0adb7a78d6e3a967ac72ace9d9a4f9392aff2711533893e017b"]],"xpubs":["xpub661MyMwAqRbcGHtCYBSGGVgMSihroMkuyE25GPyzfQvS2vSFG7SgJYf7rtXJjMh7srBJj8WddLtjapHnUQLwJ7kxsy5HiNZnGvF9pm2du7b","xpub661MyMwAqRbcEdd7bzA86LbhMoTv8NeyqcNP5z1Tiz9ajCRQDzdeXHw3h5ucDNGWr6mPFCZBcBE31VNKyR3vWM7WEeisu5m4VsCyuA6H8fp"]}},"accounts_expanded":{},"addr_history":{"M8X4uq5CDRnz5n2wtpY4McvH6xo33JVsfg":[],"M92fGyHHhXjAmjFxBmo1skrZTd1RztaTtf":[],"M9H89QRUqYxCLYCd6X7Lc6pjQktKmgrz8M":[],"M9UgTpWY1ecky2EGnFEbFAhrkfCM2sDC9t":[],"M9tnVWPU5JnVqjx51vqHB8zu7dZ1REXSe3":[],"MBPvxh6i9VosWwdueDm38ydY1Qp3K6vm5S":[],"MDgCby178EhqauoSymM9ERqW2rAxomV5Jr":[],"MDtyuB3ZoKThnMe97tA43Q44ouK66iw3L1":[],"ME69hxq6yjeVQUJUgZsgSUsumuqSJuoEny":[],"MECCAnaFA5eRSovF625uePrLkjnna9fnsn":[],"MG3nhkjYc3Zg2rTzJPWNvs5yjLAWjcrX7N":[],"MGHoAUJpAdkVFM9hPhuBhadGjUQbfFH2wF":[],"MHDWMGg3aVEyfxSoP8aqVQBvyGSHL8zghQ":[],"MHNKup31bHmNXLaqvhkQtGYzE2NsXxbVws":[],"MJP1azbGjVJVZHDkh97sNzcLpoW67isa8n":[],"MJjAaDcRcw6iFBSfh9R7irZfc4BxXrW1CT":[],"MK4UnLuFrNrxrPDh52XZbPuhSrJjE7Ypg5":[],"MKAZszP8M9DTfKVC5MSvKMWfPE5cTnbWpB":[],"MKYcAm3WXijDuv6ruDRquCW8fenPmHUuwy":[],"MNUBUH6paL3tZhRnZpWEsWctUGmEnrF7de":[],"MQRf8MNkpSekiPRQj945xgJF65pXggXx9e":[],"MSqS7U7h4y8reumY91CQY1JTJ8nGTFc6dr":[],"MT6DQ5FgG4QSiGH9zQHspEnVESdUKZhNci":[],"MTZHMtXjvrDYi6d7rTJMm3PpvRq427MwLM":[],"MUfsE8uVsgue1EffyY59tv8QxUVvwcdybA":[],"MWR6CcmwtUjsqzwzHpRLsjb1jRuEYktCTQ":[]},"master_private_keys":{"x1/":"xprv9s21ZrQH143K29YeVxd7jCexomdRiuw8UPSnHbbrAecbrQ6FgTKPyVcZqp2256L5DSTdb8UepPVaDwJecswTrEhdyZiaNGERJpfzWV5FcN5"},"master_public_keys":{"x1/":"xpub661MyMwAqRbcEdd7bzA86LbhMoTv8NeyqcNP5z1Tiz9ajCRQDzdeXHw3h5ucDNGWr6mPFCZBcBE31VNKyR3vWM7WEeisu5m4VsCyuA6H8fp","x2/":"xpub661MyMwAqRbcGHtCYBSGGVgMSihroMkuyE25GPyzfQvS2vSFG7SgJYf7rtXJjMh7srBJj8WddLtjapHnUQLwJ7kxsy5HiNZnGvF9pm2du7b"},"pruned_txo":{},"seed":"park dash merit trend life field acid wrap dinosaur kit bar hotel abuse","seed_version":11,"stored_height":490034,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"2of2","winpos-qt":[564,329,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_6_4_seeded(self): - wallet_str = '{"accounts":{"0":{"change":["03236a8ce6fd3d343358f92d3686b33fd6e7301bf9f635e94c21825780ab79c93d","0393e39f6b4a3651013fca3352b89f1ae31751d4268603f1423c71ff79cbb453a1","033d9722ecf50846527037295736708b20857b4dd7032fc02317f9780d6715e8ff","03f1d56d2ade1daae5706ea945cab2af719060a955c8ad78153693d8d08ed6b456","029260d935322dd3188c3c6b03a7b82e174f11ca7b4d332521740c842c34649137","0266e8431b49f129b892273ab4c8834a19c6432d5ed0a72f6e88be8c629c731ede"],"receiving":["0350f41cfac3fa92310bb4f36e4c9d45ec39f227a0c6e7555748dff17e7a127f67","02f997d3ed0e460961cdfa91dec4fa09f6a7217b2b14c91ed71d208375914782ba","029a498e2457744c02f4786ac5f0887619505c1dae99de24cf500407089d523414","03b15b06044de7935a0c1486566f0459f5e66c627b57d2cda14b418e8b9017aca1","026e9c73bdf2160630720baa3da2611b6e34044ad52519614d264fbf4adc5c229a","0205184703b5a8df9ae622ea0e8326134cbeb92e1f252698bc617c9598aff395a1","02af55f9af0e46631cb7fde6d1df6715dc6018df51c2370932507e3d6d41c19eec","0374e0c89aa4ecf1816f374f6de8750b9c6648d67fe0316a887a132c608af5e7c0","0321bb62f5b5c393aa82750c5512703e39f4824f4c487d1dc130f690360c0e5847","0338ea6ebb2ed80445f64b2094b290c81d0e085e6000367eb64b1dc5049f11c2e9","020c3371a9fd283977699c44a205621dea8abfc8ebc52692a590c60e22202fa49b","0395555e4646f94b10af7d9bc57e1816895ad2deddef9d93242d6d342cea3d753b","02ffa4495d020d17b54da83eaf8fbe489d81995577021ade3a340a39f5a0e2d45c","030f0e16b2d55c3b40b64835f87ab923d58bcdbb1195fadc2f05b6714d9331e837","02f70041fc4b1155785784a7c23f35d5d6490e300a7dd5b7053f88135fc1f14dfd","03b39508c6f9c7b8c3fb8a1b91e61a0850c3ac76ccd1a53fbc5b853a94979cffa8","03b02aa869aa14b0ec03c4935cc12f221c3f204f44d64146d468e07370c040bfe7","02b7d246a721e150aaf0e0e60a30ad562a32ef76a450101f3f772fef4d92b212d9","037cd5271b31466a75321d7c9e16f995fd0a2b320989c14bee82e161c83c714321","03d4ad77e15be312b29987630734d27ca6e9ee418faa6a8d6a50581eca40662829"],"xpub":"xpub661MyMwAqRbcGwHDovebbFy19vHfW2Cqtyf2TaJkAwhFWsLYfHHYcCnM7smpvntxJP1YMVT5triFbWiCGXPRPhqdCxFumA77MuQB1CeWHpE"}},"accounts_expanded":{},"addr_history":{"12qKnKuhCZ1Q9XBi1N6SnxYEUtb5XZXuY5":[],"1321ddunxShHmF4cjh3v5yqR7uatvSNndK":[],"13Ji3kGWn9qxLcWGhd46xjV6hg8SRw8x2P":[],"145q5ZDXuFi6v9dA2t8HyD8ysorfb81NRt":[],"14gB2wLy2DMkBVtuU6HHP3kQYNFYPzAguU":[],"16VGRwtZwp4yapQN5fS8CprK6mmnEicCEj":[],"16ahKVzCviRi24rwkoKgiSVSkvRNiQudE1":[],"16wjKZ1CWAMEzSR4UxQTWqXRm9jcJ9Dbuf":[],"18ReWGJBq1XkJaPAirVdT6RqDskcFeD5Ho":[],"1A1ECMMJU4NicWNwfMBn3XJriB4WHAcPUC":[],"1Bvxbfc2wXB8z8kyz2uyKw2Ps8JeGQM9FP":[],"1EDWUz4kPq8ZbCdQq8rLhFc3qSZ6Fpt1TD":[],"1EsvTarawMm5BfF44hpRtE4GfZFfZZ1JG3":[],"1JgaekD2ETMJm6oRNnwTWRK9ZxXeUcbi18":[],"1KHdLodsSWj1LrrD9d1RbApfqzpxRs5sxu":[],"1KgGwpKhruHWpMNtrpRExDWLLk5qHCHBdg":[],"1LFf8d3XD9atZvMVMAiq9ygaeZbphbKzSo":[],"1N3XncDQsWE2qff1EVyQEmR6JLLzD3mEL7":[],"1NUtLcVQNmY5TJCieM1cUmBmv18AafY1vq":[],"1NYFsm7PpneT65byRtm8niyvtzKsbEeuXA":[],"1NvEcSvfCe8LPvPkK4ZxhjzaUncTPqe9jX":[],"1PV8xdkYKxeMpnzeeA4eYEpL24j1G9ApV2":[],"1PdiGtznaW1mok6ETffeRvPP5f4ekBRAfq":[],"1QApNe4DtK7HAbJrn5kYkYxZMt86U5ChSb":[],"1QnH7F6RBXFe7LtszQ6KTRUPkQKRtXTnm":[],"1ekukhMNSWCfnRsmpkuTRuLMbz6cstkrq":[]},"master_private_keys":{"x/":"xprv9s21ZrQH143K4TCkhu7bE82GbtTB6ZUzXkjRfBu8ccAGe51Q7jyJ4QTsGbWxpHxnatKeYV7Ad83m7KC81THBm2xmyxA1q8BuuRXSGnmhhR8"},"master_public_keys":{"x/":"xpub661MyMwAqRbcGwHDovebbFy19vHfW2Cqtyf2TaJkAwhFWsLYfHHYcCnM7smpvntxJP1YMVT5triFbWiCGXPRPhqdCxFumA77MuQB1CeWHpE"},"pruned_txo":{},"seed":"heart cabbage scout rely square census satoshi home purpose legal replace move able","seed_version":11,"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"standard","winpos-qt":[582,394,840,400]}' + wallet_str = '{"accounts":{"0":{"change":["03236a8ce6fd3d343358f92d3686b33fd6e7301bf9f635e94c21825780ab79c93d","0393e39f6b4a3651013fca3352b89f1ae31751d4268603f1423c71ff79cbb453a1","033d9722ecf50846527037295736708b20857b4dd7032fc02317f9780d6715e8ff","03f1d56d2ade1daae5706ea945cab2af719060a955c8ad78153693d8d08ed6b456","029260d935322dd3188c3c6b03a7b82e174f11ca7b4d332521740c842c34649137","0266e8431b49f129b892273ab4c8834a19c6432d5ed0a72f6e88be8c629c731ede"],"receiving":["0350f41cfac3fa92310bb4f36e4c9d45ec39f227a0c6e7555748dff17e7a127f67","02f997d3ed0e460961cdfa91dec4fa09f6a7217b2b14c91ed71d208375914782ba","029a498e2457744c02f4786ac5f0887619505c1dae99de24cf500407089d523414","03b15b06044de7935a0c1486566f0459f5e66c627b57d2cda14b418e8b9017aca1","026e9c73bdf2160630720baa3da2611b6e34044ad52519614d264fbf4adc5c229a","0205184703b5a8df9ae622ea0e8326134cbeb92e1f252698bc617c9598aff395a1","02af55f9af0e46631cb7fde6d1df6715dc6018df51c2370932507e3d6d41c19eec","0374e0c89aa4ecf1816f374f6de8750b9c6648d67fe0316a887a132c608af5e7c0","0321bb62f5b5c393aa82750c5512703e39f4824f4c487d1dc130f690360c0e5847","0338ea6ebb2ed80445f64b2094b290c81d0e085e6000367eb64b1dc5049f11c2e9","020c3371a9fd283977699c44a205621dea8abfc8ebc52692a590c60e22202fa49b","0395555e4646f94b10af7d9bc57e1816895ad2deddef9d93242d6d342cea3d753b","02ffa4495d020d17b54da83eaf8fbe489d81995577021ade3a340a39f5a0e2d45c","030f0e16b2d55c3b40b64835f87ab923d58bcdbb1195fadc2f05b6714d9331e837","02f70041fc4b1155785784a7c23f35d5d6490e300a7dd5b7053f88135fc1f14dfd","03b39508c6f9c7b8c3fb8a1b91e61a0850c3ac76ccd1a53fbc5b853a94979cffa8","03b02aa869aa14b0ec03c4935cc12f221c3f204f44d64146d468e07370c040bfe7","02b7d246a721e150aaf0e0e60a30ad562a32ef76a450101f3f772fef4d92b212d9","037cd5271b31466a75321d7c9e16f995fd0a2b320989c14bee82e161c83c714321","03d4ad77e15be312b29987630734d27ca6e9ee418faa6a8d6a50581eca40662829"],"xpub":"xpub661MyMwAqRbcGwHDovebbFy19vHfW2Cqtyf2TaJkAwhFWsLYfHHYcCnM7smpvntxJP1YMVT5triFbWiCGXPRPhqdCxFumA77MuQB1CeWHpE"}},"accounts_expanded":{},"addr_history":{"LM4H3YDXHDFTQKssBW5k4ybzh6xMdNcL7D":[],"LMExtrDd36wM23kmuq3DMzuBL7xB3oaNwi":[],"LMXfJxaLrp61bRCRsm3QEkYrutVibsZPfS":[],"LNJnLmXMyuxAAxKKD27bFECk62DwcADxLY":[],"LNu8J9eo6sboSJb4eEGaf4pAkacpXQAdgw":[],"LQiDhACQ2UK2qd6XFoRRUqv5Jz94JWukNM":[],"LQoeaiJ31NfmGsZ6vwJyzTZCy8nerq6KbZ":[],"LRAgamK2apbJFF7Df6PknrbByN6tVWycjm":[],"LSebmUc1ufmoZP5KtzUvj7VbS67tQVhZSa":[],"LUEBTZf8YicmsK56qVB5KYNcvPRnLNKu4n":[],"LW9ursus2BRCEwT9AAuGbx6A5LfvJxZZer":[],"LYSTkCNaUVNcr1Ka1GqdyGfp3evNMBKcQQ":[],"LZ6sioAR2218STwDEqojAF82smcwg7LqhK":[],"LcuXuxWrK7bN1uVaYvvknSNunAtvdzG6pd":[],"LdWac1whXAy4bfYNKkzisBtS4DCEZ5J7CA":[],"LduED2dXwZXa5A542xQYEEa6YxT7TnV2ww":[],"LeUcPqMMHopwpj3eXJi8RzkLrmy6kxYyPj":[],"LgGV3pXExAU66UMAQdxhWnUrWYiGL6LZRp":[],"LghqbpoETRn8i6tspUzuknFY8DVSirGrAw":[],"LgmD8yRDuStWLtJ8c2kS4k3h7Ch9iBseQ8":[],"Lh9BsfEVHJNPej5uVCZFym4LgzyjXgFV7H":[],"Lhi6Dr4NQctR5bgopJ3wpFt6EH6HJc9uiu":[],"LhrfY7JcfAFq4YnPdoewhwT9HsRvr6pYRB":[],"LiPmdrN3xyMLRQ11xDjr2a2Ka6VNaKMuZ3":[],"LKdjYKYvVqmJtv3448PPbUVEbxmbWFYre1":[],"LKsiAy1BT6kFvb82wxkCjSy6ZpMNhJn2Gy":[]},"master_private_keys":{"x/":"xprv9s21ZrQH143K4TCkhu7bE82GbtTB6ZUzXkjRfBu8ccAGe51Q7jyJ4QTsGbWxpHxnatKeYV7Ad83m7KC81THBm2xmyxA1q8BuuRXSGnmhhR8"},"master_public_keys":{"x/":"xpub661MyMwAqRbcGwHDovebbFy19vHfW2Cqtyf2TaJkAwhFWsLYfHHYcCnM7smpvntxJP1YMVT5triFbWiCGXPRPhqdCxFumA77MuQB1CeWHpE"},"pruned_txo":{},"seed":"heart cabbage scout rely square census satoshi home purpose legal replace move able","seed_version":11,"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"standard","winpos-qt":[582,394,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_6_4_importedkeys(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM"],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U"]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported","winpos-qt":[510,338,840,400]}' + wallet_str = '{"accounts":{"/x":{"imported":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1"],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":["04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2","6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":["0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5"]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":489716,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"imported","winpos-qt":[510,338,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_6_4_watchaddresses(self): - wallet_str = '{"accounts":{"/x":{"imported":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[null,null],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[null,null],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[null,null]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported","winpos-qt":[582,425,840,400]}' + wallet_str = '{"accounts":{"/x":{"imported":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[null,null],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[null,null],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[null,null]}}},"accounts_expanded":{},"addr_history":{},"pruned_txo":{},"stored_height":490038,"transactions":{},"txi":{},"txo":{},"wallet_type":"imported","winpos-qt":[582,425,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_6_4_multisig(self): - wallet_str = '{"accounts":{"0":{"change":[["03d0bcdc86a64cc2024c84853e88985f6f30d3dc3f219b432680c338a3996a89ed","024f326d48aa0a62310590b10522b69d250a2439544aa4dc496f7ba6351e6ebbfe"],["03c0416928528a9aaaee558590447ee63fd33fa497deebefcf363b1af90d867762","03db7de16cd6f3dcd0329a088382652bc3e6b21ee1a732dd9655e192c887ed88a7"],["0291790656844c9d9c24daa344c0b426089eadd3952935c58ce6efe00ef1369828","02c2a5493893643102f77f91cba709f11aaab3e247863311d6fc3d3fc82624c3cc"],["023dc976bd1410a7e9f34c230051db58a3f487763f00df1f529b10f55ee85b931c","036c318a7530eedf3584fd8b24c4024656508e35057a0e7654f21e89e121d0bd30"],["02c8820711b39272e9730a1c5c5c78fe39a642b8097f8724b2592cc987017680ce","0380e3ebe0ea075e33acb3f796ad6548fde86d37c62fe8e4f6ab5d2073c1bb1d43"],["0369a32ddd213677a0509c85af514537d5ee04c68114da3bc720faeb3adb45e6f8","0370e85ac01af5e3fd5a5c3969c8bca3e4fc24efb9f82d34d5790e718a507cecb6"]],"m":2,"receiving":[["0207739a9ff4a643e1d4adb03736ec43d13ec897bdff76b40a25d3a16e19e464aa","02372ea4a291aeb1fadb26f36976348fc169fc70514797e53b789a87c9b27cc568"],["0248ae7671882ec87dd6bacf7eb2ff078558456cf5753952cddb5dde08f471f3d6","035bac54828b383545d7b70824a8be2f2d9584f656bfdc680298a38e9383ed9e51"],["02cb99ba41dfbd510cd25491c12bd0875fe8155b5a6694ab781b42bd949252ff26","03b520feba42149947f8b2bbc7e8c03f9376521f20ac7b7f122dd44ab27309d7c6"],["0395902d5ebb4905edd7c4aedecf17be0675a2ffeb27d85af25451659c05cc5198","02b4a01d4bd25cadcbf49900005e8d5060ed9cdc35eb33f2cd65cc45cc7ebc00c5"],["02f9d06c136f05acc94e4572399f17238bb56fa15271e3cb816ae7bb9be24b00b6","035516437612574b2b563929c49308911651205e7cebb621940742e570518f1c50"],["0376a7de3abaee6631bd4441658987c27e0c7eee2190a86d44841ae718a014ee43","03cb702364ffd59cb92b2e2128c18d8a5a255be2b95eb950641c5f17a5a900eecb"],["03240c5e868ecb02c4879ae5f5bad809439fdbd2825769d75be188e34f6e533a67","026b0d05784e4b4c8193443ce60bea162eee4d99f9dfa94a53ae3bc046a8574eeb"],["02d087cccb7dc457074aa9decc04de5a080757493c6aa12fa5d7d3d389cfdb5b8e","0293ab7d0d8bbb2d433e7521a1100a08d75a32a02be941f731d5809b22d86edb33"],["03d1b83ab13c5b35701129bed42c1f1fbe86dd503181ad66af3f4fb729f46a277e","0382ec5e920bc5c60afa6775952760668af42b67d36d369cd0e9acc17e6d0a930d"],["03f1737db45f3a42aebd813776f179d5724fce9985e715feb54d836020b8517bfe","0287a9dfb8ee2adab81ef98d52acd27c25f558d2a888539f7d583ef8c00c34d6dc"],["038eb8804e433023324c1d439cd5fbbd641ca85eadcfc5a8b038cb833a755dac21","0361a7c80f0d9483c416bc63d62506c3c8d34f6233b6d100bb43b6fe8ec39388b9"],["0336437ada4cd35bec65469afce298fe49e846085949d93ef59bf77e1a1d804e4a","0321898ed89df11fcfb1be44bb326e4bb3272464f000a9e51fb21d25548619d377"],["0260f0e59d6a80c49314d5b5b857d1df64d474aba48a37c95322292786397f3dc6","03acd6c9aeac54c9510304c2c97b7e206bbf5320c1e268a2757d400356a30c627b"],["0373dc423d6ee57fac3b9de5e2b87cf36c21f2469f17f32f5496e9e7454598ba8e","031ddc1f40c8b8bf68117e790e2d18675b57166e9521dff1da44ba368be76555b3"],["031878b39bc6e35b33ceac396b429babd02d15632e4a926be0220ccbd710c7d7b9","025a71cc5009ae07e3e991f78212e99dd5be7adf941766d011197f331ce8c1bed0"],["032d3b42ed4913a134145f004cf105b66ae97a9914c35fb73d37170d37271acfcd","0322adeb83151937ddcd32d5bf2d3ed07c245811d0f7152716f82120f21fb25426"],["0312759ff0441c59cb477b5ec1b22e76a794cd821c13b8900d72e34e9848f088c2","02d868626604046887d128388e86c595483085f86a395d68920e244013b544ef3b"],["038c4d5f49ab08be619d4fed7161c339ea37317f92d36d4b3487f7934794b79df4","03f4afb40ae7f4a886f9b469a81168ad549ad341390ff91ebf043c4e4bfa05ecc1"],["02378b36e9f84ba387f0605a738288c159a5c277bbea2ea70191ade359bc597dbb","029fd6f0ee075a08308c0ccda7ace4ad9107573d2def988c2e207ac1d69df13355"],["02cfecde7f415b0931fc1ec06055ff127e9c3bec82af5e3affb15191bf995ffc1a","02abb7481504173a7aa1b9860915ef62d09a323425f680d71746be6516f0bb4acf"]],"xpubs":["xpub661MyMwAqRbcF4mZnFnBRYGBaiD9aQRp9w2jaPUrDg3Eery5gywV7eFMzQKmNyY1W4m4fUwsinMw1tFhMNEZ9KjNtkUSBHPXdcXBwCg5ctV","xpub661MyMwAqRbcGHU5H41miJ2wXBLYYk4psK7pB5pWyxK6m5EARwLrKtmpnMzP52qGsKZEtjJCyohVEaZTFXbohjVdfpDFifgMBT82EvkFpsW"]}},"accounts_expanded":{},"addr_history":{"329Ju5tiAr4vHZExAT4KydYEkfKiHraY2N":[],"32HJ13iTVh3sCWyXzipcGb1e78ZxcHrQ7v":[],"32cAdiAapUzNVRYXmDud5J5vEDcGsPHjD8":[],"33fKLmoCo8oFfeV987P6KrNTghSHjJM251":[],"34cE6ZcgXvHEyKbEP2Jpz5C3aEWhvPoPG2":[],"36xsnTKKBojYRHEApVR6bCFbDLp9oqNAxU":[],"372PG6D3chr8tWF3J811dKSpPS84MPU6SE":[],"378nVF8daT4r3jfX1ebKRheUVZX5zaa9wd":[],"392ZtXKp2THrk5VtbandXxFLB8yr2g14aA":[],"39cCrU3Zz3SsHiQUDiyPS1Qd5ZL3Rh1GhQ":[],"3A2cRoBdem5tdRjq514Pp7ZvaxydgZiaNG":[],"3Ceoi3MKdh2xiziHDAzmriwjDx4dvxxLzm":[],"3FcXdG8mh1YeQCYVib8Aw7zwnKpComimLH":[],"3J4b31yAbQkKhejSW7Qz54qNJDEy3t9uSe":[],"3JpJrSxE1GP1X5h82zvLA2TbMZ8nUsGW6z":[],"3K1dzpbcop1MotuqyFQyEuXbvQehaKnGVM":[],"3L8Us8SN22Hj6GnZPRCLaowA1ZtbptXxxL":[],"3LANyoJyShQ8w55tvopoGiZ2BTVjLfChiP":[],"3LoJGQdXTzVaDYudUguP4jNJYy4gNDaRpN":[],"3MD8jVH7Crp5ucFomDnWqB6kQrEQ9VF5xv":[],"3ME8DemkFJSn2tHS23yuk2WfaMP86rd3s7":[],"3MFNr17oSZpFtH16hGPgXz2em2hJkd3SZn":[],"3QHRTYnW2HWCWoeisVcy3xsAFC5xb6UYAK":[],"3QKwygVezHFBthudRUh8V7wwtWjZk3whpB":[],"3QNPY3dznFwRv6VMcKgmn8FGJdsuSRRjco":[],"3QNwwD8dp6kvS8Fys4ZxVJYZAwCXdXQBKo":[]},"master_private_keys":{"x1/":"xprv9s21ZrQH143K3oPcB2UmMA6Cy9W49HLyW6CDNhQuRcn7tGu1tQ2bn6TLw8HFWbu5oP38Z2fFCo5Q4n3fog4DTqywYqfSDWhYbDgVD1TGZoP"},"master_public_keys":{"x1/":"xpub661MyMwAqRbcGHU5H41miJ2wXBLYYk4psK7pB5pWyxK6m5EARwLrKtmpnMzP52qGsKZEtjJCyohVEaZTFXbohjVdfpDFifgMBT82EvkFpsW","x2/":"xpub661MyMwAqRbcF4mZnFnBRYGBaiD9aQRp9w2jaPUrDg3Eery5gywV7eFMzQKmNyY1W4m4fUwsinMw1tFhMNEZ9KjNtkUSBHPXdcXBwCg5ctV"},"pruned_txo":{},"seed":"turkey weapon legend tower style multiply tomorrow wet like frame leave cash achieve","seed_version":11,"stored_height":490035,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"2of2","winpos-qt":[610,418,840,400]}' + wallet_str = '{"accounts":{"0":{"change":[["03d0bcdc86a64cc2024c84853e88985f6f30d3dc3f219b432680c338a3996a89ed","024f326d48aa0a62310590b10522b69d250a2439544aa4dc496f7ba6351e6ebbfe"],["03c0416928528a9aaaee558590447ee63fd33fa497deebefcf363b1af90d867762","03db7de16cd6f3dcd0329a088382652bc3e6b21ee1a732dd9655e192c887ed88a7"],["0291790656844c9d9c24daa344c0b426089eadd3952935c58ce6efe00ef1369828","02c2a5493893643102f77f91cba709f11aaab3e247863311d6fc3d3fc82624c3cc"],["023dc976bd1410a7e9f34c230051db58a3f487763f00df1f529b10f55ee85b931c","036c318a7530eedf3584fd8b24c4024656508e35057a0e7654f21e89e121d0bd30"],["02c8820711b39272e9730a1c5c5c78fe39a642b8097f8724b2592cc987017680ce","0380e3ebe0ea075e33acb3f796ad6548fde86d37c62fe8e4f6ab5d2073c1bb1d43"],["0369a32ddd213677a0509c85af514537d5ee04c68114da3bc720faeb3adb45e6f8","0370e85ac01af5e3fd5a5c3969c8bca3e4fc24efb9f82d34d5790e718a507cecb6"]],"m":2,"receiving":[["0207739a9ff4a643e1d4adb03736ec43d13ec897bdff76b40a25d3a16e19e464aa","02372ea4a291aeb1fadb26f36976348fc169fc70514797e53b789a87c9b27cc568"],["0248ae7671882ec87dd6bacf7eb2ff078558456cf5753952cddb5dde08f471f3d6","035bac54828b383545d7b70824a8be2f2d9584f656bfdc680298a38e9383ed9e51"],["02cb99ba41dfbd510cd25491c12bd0875fe8155b5a6694ab781b42bd949252ff26","03b520feba42149947f8b2bbc7e8c03f9376521f20ac7b7f122dd44ab27309d7c6"],["0395902d5ebb4905edd7c4aedecf17be0675a2ffeb27d85af25451659c05cc5198","02b4a01d4bd25cadcbf49900005e8d5060ed9cdc35eb33f2cd65cc45cc7ebc00c5"],["02f9d06c136f05acc94e4572399f17238bb56fa15271e3cb816ae7bb9be24b00b6","035516437612574b2b563929c49308911651205e7cebb621940742e570518f1c50"],["0376a7de3abaee6631bd4441658987c27e0c7eee2190a86d44841ae718a014ee43","03cb702364ffd59cb92b2e2128c18d8a5a255be2b95eb950641c5f17a5a900eecb"],["03240c5e868ecb02c4879ae5f5bad809439fdbd2825769d75be188e34f6e533a67","026b0d05784e4b4c8193443ce60bea162eee4d99f9dfa94a53ae3bc046a8574eeb"],["02d087cccb7dc457074aa9decc04de5a080757493c6aa12fa5d7d3d389cfdb5b8e","0293ab7d0d8bbb2d433e7521a1100a08d75a32a02be941f731d5809b22d86edb33"],["03d1b83ab13c5b35701129bed42c1f1fbe86dd503181ad66af3f4fb729f46a277e","0382ec5e920bc5c60afa6775952760668af42b67d36d369cd0e9acc17e6d0a930d"],["03f1737db45f3a42aebd813776f179d5724fce9985e715feb54d836020b8517bfe","0287a9dfb8ee2adab81ef98d52acd27c25f558d2a888539f7d583ef8c00c34d6dc"],["038eb8804e433023324c1d439cd5fbbd641ca85eadcfc5a8b038cb833a755dac21","0361a7c80f0d9483c416bc63d62506c3c8d34f6233b6d100bb43b6fe8ec39388b9"],["0336437ada4cd35bec65469afce298fe49e846085949d93ef59bf77e1a1d804e4a","0321898ed89df11fcfb1be44bb326e4bb3272464f000a9e51fb21d25548619d377"],["0260f0e59d6a80c49314d5b5b857d1df64d474aba48a37c95322292786397f3dc6","03acd6c9aeac54c9510304c2c97b7e206bbf5320c1e268a2757d400356a30c627b"],["0373dc423d6ee57fac3b9de5e2b87cf36c21f2469f17f32f5496e9e7454598ba8e","031ddc1f40c8b8bf68117e790e2d18675b57166e9521dff1da44ba368be76555b3"],["031878b39bc6e35b33ceac396b429babd02d15632e4a926be0220ccbd710c7d7b9","025a71cc5009ae07e3e991f78212e99dd5be7adf941766d011197f331ce8c1bed0"],["032d3b42ed4913a134145f004cf105b66ae97a9914c35fb73d37170d37271acfcd","0322adeb83151937ddcd32d5bf2d3ed07c245811d0f7152716f82120f21fb25426"],["0312759ff0441c59cb477b5ec1b22e76a794cd821c13b8900d72e34e9848f088c2","02d868626604046887d128388e86c595483085f86a395d68920e244013b544ef3b"],["038c4d5f49ab08be619d4fed7161c339ea37317f92d36d4b3487f7934794b79df4","03f4afb40ae7f4a886f9b469a81168ad549ad341390ff91ebf043c4e4bfa05ecc1"],["02378b36e9f84ba387f0605a738288c159a5c277bbea2ea70191ade359bc597dbb","029fd6f0ee075a08308c0ccda7ace4ad9107573d2def988c2e207ac1d69df13355"],["02cfecde7f415b0931fc1ec06055ff127e9c3bec82af5e3affb15191bf995ffc1a","02abb7481504173a7aa1b9860915ef62d09a323425f680d71746be6516f0bb4acf"]],"xpubs":["xpub661MyMwAqRbcF4mZnFnBRYGBaiD9aQRp9w2jaPUrDg3Eery5gywV7eFMzQKmNyY1W4m4fUwsinMw1tFhMNEZ9KjNtkUSBHPXdcXBwCg5ctV","xpub661MyMwAqRbcGHU5H41miJ2wXBLYYk4psK7pB5pWyxK6m5EARwLrKtmpnMzP52qGsKZEtjJCyohVEaZTFXbohjVdfpDFifgMBT82EvkFpsW"]}},"accounts_expanded":{},"addr_history":{"M8MTCyJg7xvM64WrGL3foGne5MvAF75N27":[],"M8VSJw8RSouJ12FS6box6EG3RqAQZS9jqj":[],"M8pJwbaYmbqoHvpRs6txtwLKYvCisBKHLx":[],"M9sTefDAkFegU9m3DzNS9Vcs1Q2jgh5HWZ":[],"MApNQT2eV38fmps8UuJAoiSStw79zS33PS":[],"MDB26LjH8vayDnW4vNQSQqVzY3QbkxT8yH":[],"MDEXZyd1ZphZh1WwPzzMSxhDi8iWMui1Uy":[],"MDLvo8YbXZvGrEwR7XafFLtspG7Xx3w18t":[],"MFEiCQjmya9HYamnhTmyMbVjVqaJ2AndJA":[],"MFpMAMTXwAJJ6DgNKbxjFef2QFvVXSdTQQ":[],"MGEkjgbbbswKRw1jAt3jdkpKufa5iREArH":[],"MJrx1vmHaotPXVzBK3z7gNC8Yef61QKkdA":[],"MMpfw9Yje8Q5ChpPpU7WkmFM72Qertt3HS":[],"MQGjLuP8YXbkWA1LbzQKti5mcuqQzGNfH4":[],"MR2TALNBxPESKay28sufyfhzgFjEWLiRqi":[],"MRDnJi1akvrncQBk58QK4Yn1F7F9Xajs3e":[],"MSLdB1rKy999tn4TVJBgQTBZLGV3puZJ9N":[],"MSNXHgiwPpFZjaMo2gp96MoRWA6BJx3XCz":[],"MT1SaJ3VR7M124BXaZtitNchsff8Na2LpH":[],"MTRH3Nh59yfWi7Xhs6mrepM9jYpr8bUVVA":[],"MTSGXYBiCRJCqPZL7vyFZfm4u3ya6E5hyy":[],"MTTX9tXmPgfggnGzo9P2MdH45jHknLnsDu":[],"MWVZmSCTyQMdKJvcyNcJsc7ZZtgQf7FokC":[],"MWY6HZucwQ6chDBXXMgUJmCMDDL1kRkUvG":[],"MWaXqw3xjNnribmFiCg7bmVfdLUMPqjY48":[],"MWb6F6YbmDcMEdXsxwZJJwnxVdnye8V4Rv":[]},"master_private_keys":{"x1/":"xprv9s21ZrQH143K3oPcB2UmMA6Cy9W49HLyW6CDNhQuRcn7tGu1tQ2bn6TLw8HFWbu5oP38Z2fFCo5Q4n3fog4DTqywYqfSDWhYbDgVD1TGZoP"},"master_public_keys":{"x1/":"xpub661MyMwAqRbcGHU5H41miJ2wXBLYYk4psK7pB5pWyxK6m5EARwLrKtmpnMzP52qGsKZEtjJCyohVEaZTFXbohjVdfpDFifgMBT82EvkFpsW","x2/":"xpub661MyMwAqRbcF4mZnFnBRYGBaiD9aQRp9w2jaPUrDg3Eery5gywV7eFMzQKmNyY1W4m4fUwsinMw1tFhMNEZ9KjNtkUSBHPXdcXBwCg5ctV"},"pruned_txo":{},"seed":"turkey weapon legend tower style multiply tomorrow wet like frame leave cash achieve","seed_version":11,"stored_height":490035,"transactions":{},"txi":{},"txo":{},"use_encryption":false,"wallet_type":"2of2","winpos-qt":[610,418,840,400]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_7_18_seeded(self): - wallet_str = '{"addr_history":{"12nzqpb4vxiFmcvypswSWK1f4cvGwhYAE8":[],"13sapXcP5Wq25PiXh5Zr9mLhyjdfrppWyi":[],"14EzC5y5eFCXg4T7cH4hXoivzysEpGXBTM":[],"15PUQBi2eEzprCZrS8dkfXuoNv8TuqwoBm":[],"16NvXzjxHbiNAULoRRTBjSmecMgF87FAtb":[],"16oyPjLM4R96aZCnSHqBBkDMgbE2ehDWFe":[],"1BfhL8ZPcaZkXTZKASQYcFJsPfXNwCwVMV":[],"1Bn3vun14mDWBDkx4PvK2SyWK1nqB9MSmM":[],"1BrCEnhf763JhVNcZsjGcNmmisBfRkrdcn":[],"1BvXCwXAdaSTES4ENALv3Tw6TJcZbMzu5o":[],"1C2vzgDyPqtvzFRYUgavoLvk3KGujkUUjg":[],"1CN22zUHuX5SxGTmGvPTa2X6qiCJZjDUAW":[],"1CUT9Su42c4MFxrfbrouoniuhVuvRjsKYS":[],"1DLaXDPng4wWXW7AdDG3cLkuKXgEUpjFHq":[],"1DTLcXN6xPUVXP1ZQmt2heXe2KHDSdvRNv":[],"1F1zYJag8yXVnDgGGy7waQT3Sdyp7wLZm3":[],"1Fim67c46NHTcSUu329uF8brTmkoiz6Ej8":[],"1Go6JcgkfZuA7fyQFKuLddee9hzpo31uvL":[],"1J6mhetXo9Eokq7NGjwbKnHryxUCpgbCDn":[],"1K9sFmS7qM2P5JpVGQhHMqQgAnNiujS5jZ":[],"1KBdFn9tGPYEqXnHyJAHxBfCQFF9v3mq95":[],"1LRWRLWHE2pdMviVeTeJBa8nFbUTWSCvrg":[],"1LpXAktoSKbRx7QFkyb2KkSNJXSGLtTg9T":[],"1LtxCQLTqD1q5Q5BReP932t5D7pKx5wiap":[],"1MX5AS3pA5jBhmg4DDuDQEuNhPGS4cGU4F":[],"1Pz9bYFMeqZkXahx9yPjXtJwL69zB3xCp2":[]},"keystore":{"seed":"giraffe tuition frog desk airport rural since dizzy regular victory mind coconut","type":"bip32","xprv":"xprv9s21ZrQH143K28Jvnpm7hU3xPt18neaDpcpoMKTyi9ewNRg6puJ2RAE5gZNPQ73bbmU9WsagxLQ3a6i2t1M9W289HY9Q5sEzFsLaYq3ZQf3","xpub":"xpub661MyMwAqRbcEcPPtrJ84bzgwuqdC7J5BqkQ9hsbGVBvFE1FNScGxxYZXpC9ncowEe7EZVbAerSypw3wCjrmLmsHeG3RzySw5iEJhAfZaZT"},"pruned_txo":{},"pubkeys":{"change":["033e860b0823ed2bf143594b07031d9d95d35f6e4ad6093ddc3071b8d2760f133f","03f51e8798a1a46266dee899bada3e1517a7a57a8402deeef30300a8918c81889a","0308168b05810f62e3d08c61e3c545ccbdce9af603adbdf23dcc366c47f1c5634c","03d7eddff48be72310347efa93f6022ac261cc33ee0704cdad7b6e376e9f90f574","0287e34a1d3fd51efdc83f946f2060f13065e39e587c347b65a579b95ef2307d45","02df34e258a320a11590eca5f0cb0246110399de28186011e8398ce99dd806854a"],"receiving":["031082ff400cbe517cc2ae37492a6811d129b8fb0a8c6bd083313f234e221527ae","03fac4d7402c0d8b290423a05e09a323b51afebd4b5917964ba115f48ab280ef07","03c0a8c4ab604634256d3cfa350c4b6ca294a4374193055195a46626a6adea920f","03b0bc3112231a9bea6f5382f4324f23b4e2deb5f01a90b0fe006b816367e43958","03a59c08c8e2d66523c888416e89fa1aaec679f7043aa5a9145925c7a80568e752","0346fefc07ab2f38b16c8d979a8ffe05bc9f31dd33291b4130797fa7d78f6e4a35","025eb34724546b3c6db2ee8b59fbc4731bafadac5df51bd9bbb20b456d550ef56e","02b79c26e2eac48401d8a278c63eec84dc5bef7a71fa7ce01a6e333902495272e2","03a3a212462a2b12dc33a89a3e85684f3a02a647db3d7eaae18c029a6277c4f8ac","02d13fc5b57c4d057accf42cc918912221c528907a1474b2c6e1b9ca24c9655c1a","023c87c3ca86f25c282d9e6b8583b0856a4888f46666b413622d72baad90a25221","030710e320e9911ebfc89a6b377a5c2e5ae0ab16b9a3df54baa9dbd3eb710bf03c","03406b5199d34be50725db2fcd440e487d13d1f7611e604db81bb06cdd9077ffa5","0378139461735db84ff4d838eb408b9c124e556cfb6bac571ed6b2d0ec671abd0c","030538379532c476f664d8795c0d8e5d29aea924d964c685ea5c2343087f055a82","02d1b93fa37b824b4842c46ef36e5c50aadbac024a6f066b482be382bec6b41e5a","02d64e92d12666cde831eb21e00079ecfc3c4f64728415cc38f899aca32f1a5558","0347480bf4d321f5dce2fcd496598fbdce19825de6ed5b06f602d66de7155ac1c0","03242e3dfd8c4b6947b0fbb0b314620c0c3758600bb842f0848f991e9a2520a81c","021acadf6300cb7f2cca11c6e1c7e59e3cf923a786f6371c3b85dd6f8b65c68470"]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[709,314,840,405]}' + wallet_str = '{"addr_history":{"LM1x72tu1cxK2Rd911vjnL5RGqHZ4SxXm2":[],"LN6Y5jvDAB55LCQgsDZ9RnQUBwzwxLa1wz":[],"LNTwTJGuiuSavs9GnR3zopnhDCEWrmAAEM":[],"LPcRfQ1riuEt71G1cGd3wYyZb8Vk1EgZSk":[],"LQbsoD3nNFxRRH2xbZSV1TqQpa3XAtaF7u":[],"LR2veweB95P9qMtwcRpUTmH7tobJnSJMV6":[],"LVtebLsDhEoonGFULaPqtGNdbstf2g3w6U":[],"LW11C85q9RTZS2T7EXucJU3GXEA7McE6ca":[],"LW59W11VBkHMxJ4mk1iZtPqXw5YwYoLhp4":[],"LW9UU9pziEgWVEkPYJLDKUzrfWyqhZgpud":[],"LWFtFtXoUW8zF47hepaE5MzWFXeBwyRsNu":[],"LWayJCn7zBKWD59vT4Nkr3as3vZad9y6qu":[],"LWhQQfCt7GJQWmYpmzoD5onfuiHCZmMBf1":[],"LXZXnRhckjBZnJoKoMFLtMpfXk3WgXnAvY":[],"LXgHsjfw33iYnBhiausKyfbQEXeVdJUTsD":[],"LZEwoWtWDdmZ32NRT77ErRWoerM6EvCTAZ":[],"LZwiMKutB2XWsFB4DA9CX9fcfz85mfh39T":[],"Lb23ZpzakE9DNUfZRTtdueiQMvN711HvJq":[],"LcKixsCMsoUs1doXSsvtboMdCAqUwKJwsC":[],"LdNpWyjwv1GSL7WeSYgadrUSNzjzxxeh7g":[],"LdQaWzTiM3nJ6LUT9S9bECixcTcRyhFTPX":[],"LeeTgYp7Jh4gcjQepbdbTbCYToqjbtvEgA":[],"Lf3URyCdWyqVCv6Qw7aKbmW8WjoYRnFjAG":[],"Lf7uTceHusFtLCmLbnNSK3wqRLBc7U6gar":[],"Lfk2ReMeEjyExaNDPMtWgFy8ubdiEURyAV":[],"LiD6rkZBjVoonPQ7L7P2ouNhYJXGJ726Nb":[]},"keystore":{"seed":"giraffe tuition frog desk airport rural since dizzy regular victory mind coconut","type":"bip32","xprv":"xprv9s21ZrQH143K28Jvnpm7hU3xPt18neaDpcpoMKTyi9ewNRg6puJ2RAE5gZNPQ73bbmU9WsagxLQ3a6i2t1M9W289HY9Q5sEzFsLaYq3ZQf3","xpub":"xpub661MyMwAqRbcEcPPtrJ84bzgwuqdC7J5BqkQ9hsbGVBvFE1FNScGxxYZXpC9ncowEe7EZVbAerSypw3wCjrmLmsHeG3RzySw5iEJhAfZaZT"},"pruned_txo":{},"pubkeys":{"change":["033e860b0823ed2bf143594b07031d9d95d35f6e4ad6093ddc3071b8d2760f133f","03f51e8798a1a46266dee899bada3e1517a7a57a8402deeef30300a8918c81889a","0308168b05810f62e3d08c61e3c545ccbdce9af603adbdf23dcc366c47f1c5634c","03d7eddff48be72310347efa93f6022ac261cc33ee0704cdad7b6e376e9f90f574","0287e34a1d3fd51efdc83f946f2060f13065e39e587c347b65a579b95ef2307d45","02df34e258a320a11590eca5f0cb0246110399de28186011e8398ce99dd806854a"],"receiving":["031082ff400cbe517cc2ae37492a6811d129b8fb0a8c6bd083313f234e221527ae","03fac4d7402c0d8b290423a05e09a323b51afebd4b5917964ba115f48ab280ef07","03c0a8c4ab604634256d3cfa350c4b6ca294a4374193055195a46626a6adea920f","03b0bc3112231a9bea6f5382f4324f23b4e2deb5f01a90b0fe006b816367e43958","03a59c08c8e2d66523c888416e89fa1aaec679f7043aa5a9145925c7a80568e752","0346fefc07ab2f38b16c8d979a8ffe05bc9f31dd33291b4130797fa7d78f6e4a35","025eb34724546b3c6db2ee8b59fbc4731bafadac5df51bd9bbb20b456d550ef56e","02b79c26e2eac48401d8a278c63eec84dc5bef7a71fa7ce01a6e333902495272e2","03a3a212462a2b12dc33a89a3e85684f3a02a647db3d7eaae18c029a6277c4f8ac","02d13fc5b57c4d057accf42cc918912221c528907a1474b2c6e1b9ca24c9655c1a","023c87c3ca86f25c282d9e6b8583b0856a4888f46666b413622d72baad90a25221","030710e320e9911ebfc89a6b377a5c2e5ae0ab16b9a3df54baa9dbd3eb710bf03c","03406b5199d34be50725db2fcd440e487d13d1f7611e604db81bb06cdd9077ffa5","0378139461735db84ff4d838eb408b9c124e556cfb6bac571ed6b2d0ec671abd0c","030538379532c476f664d8795c0d8e5d29aea924d964c685ea5c2343087f055a82","02d1b93fa37b824b4842c46ef36e5c50aadbac024a6f066b482be382bec6b41e5a","02d64e92d12666cde831eb21e00079ecfc3c4f64728415cc38f899aca32f1a5558","0347480bf4d321f5dce2fcd496598fbdce19825de6ed5b06f602d66de7155ac1c0","03242e3dfd8c4b6947b0fbb0b314620c0c3758600bb842f0848f991e9a2520a81c","021acadf6300cb7f2cca11c6e1c7e59e3cf923a786f6371c3b85dd6f8b65c68470"]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[709,314,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_7_18_importedkeys(self): - wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"pubkeys":{"change":[],"receiving":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2"]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[420,312,840,405]}' + wallet_str = '{"addr_history":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":[],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":[],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":[]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"},"type":"imported"},"pruned_txo":{},"pubkeys":{"change":[],"receiving":["0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2"]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[420,312,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_7_18_watchaddresses(self): - wallet_str = '{"addr_history":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[]},"addresses":["1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs","1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa","1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf"],"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[553,402,840,405]}' + wallet_str = '{"addr_history":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[]},"addresses":["LbGiejb64pNXrjPZfiauVkchFQksBnFjrz","Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy","LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2"],"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[553,402,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_7_18_trezor_singleacc(self): - wallet_str = '''{"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"pubkeys":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"]},"seed_version":13,"stored_height":490013,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[631,410,840,405]}''' + wallet_str = '''{"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"pubkeys":{"change":["03143bc04f007c454e03caf9d59b61e27f527b5e6723e167b50197ce45e2071902","03157710459a8213a79060e2f2003fe0eb7a7ed173ac3f846309de52269dd44740","028ec4bbbf4ac9edfabb704bd82acb0840f2166312929ce01af2b2e99059b16dee","021a9f1201968bd835029daf09ae98745a75bcb8c6143b80610cfc2eb2eee94dd8","031fe8323703fee4a1f6c59f27ceed4e227f5643b1cb387b39619b6b5499a971b4","033199fc62b72ce98e3780684e993f31d520f1da0bf2880ed26153b2efcc86ac1d"],"receiving":["03d27c0f5594d8df0616d64a735c909098eb867d01c6f1588f04ca2cf353837ec0","024d299f21e9ee9cc3eb425d04f45110eff46e45abcab24a3e594645860518fb97","03f6bc650e5f118ab4a63359a9cde4ab8382fe16e7d1b36b0a459145a79bef674b","028bed00a2fbd03f1ff43e0150ec1018458f7b39f3e4e602e089b1f47f8f607136","02108b15014d53f2e4e1b5b2d8f5eaf82006bbc4f273dbfbaef91eff08f9d10ea5","02a9a59a529818f3ba7a37ebe34454eac2bcbe4da0e8566b13f369e03bb020c4c4","023fde4ecf7fbdffb679d92f58381066cf2d840d34cb2d8bef63f7c5182d278d53","02ad8bf6dc0ff3c39bd20297d77fbd62073d7bf2fa44bf716cdd026db0819bb2b4","029c8352118800beaef1f3fa9c12afe30d329e7544bea9b136b717b88c24d95d92","02c42c251392674e2c2768ccd6224e04298bd5479436f02e9867ecc288dd2eb066","0316f3c82d9fce97e267b82147d56a4b170d39e6cf01bfaff6c2ae6bcc79a14447","0398554ee8e333061391b3e866505bbc5e130304ae09b198444bcd31c4ba7846ea","02e69d21aadb502e9bd93c5536866eff8ca6b19664545ccc4e77f3508e0cbe2027","0270fb334407a53a23ad449389e2cb055fae5017ca4d79ec8e082038db2d749c50","03d91a8f47453f9da51e0194e3aacff88bf79a625df82ceee73c71f3a7099a5459","0306b2d3fd06c4673cc90374b7db0c152ba7960be382440cecc4cdad7642e0537c","028020dd6062f080e1e2b49ca629faa1407978adab13b74875a9de93b16accf804","03907061c5f6fde367aafe27e1d53b39ff9c2babffe8ab7cf8c3023acba5c39736","029749462dba9af034455f5e0f170aac67fe9365ce7126092b4d24ced979b5381f","02f001d35308833881b3440670d25072256474c6c4061daf729055bf9563134105"]},"seed_version":13,"stored_height":490013,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[631,410,840,405]}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_7_18_multisig(self): - wallet_str = '{"addr_history":{"32WKXQ6BWtGJDVTpdcUMhtRZWzgk5eKnhD":[],"33rvo2pxaccCV7jLwvth36sdLkdEqhM8B8":[],"347kG9dzt2M1ZPTa2zzcmVrAE75LuZs9A2":[],"34BBeAVEe5AM6xkRebddFG8JH6Vx1M5hHH":[],"34MAGbxxCHPX8ASfKsyNkzpqPEUTZ5i1Kx":[],"36uNpoPSgUhN5Cc1wRQyL77aD1RL3a9X6f":[],"384xygkfYsSuXN478zhN4jmNcky1bPo7Cq":[],"39GBGaGpp1ePBsjjaw8NmbZNZkMzhfmZ3W":[],"3BRhw13g9ShGcuHbHExxtFfvhjrxiSiA7J":[],"3BboKZc2VgjKVxoC5gndLGpwEkPJuQrZah":[],"3C3gKJ2UQNNHY2SG4h43zRS1faSLhnqQEr":[],"3CEY1V5WvCTxjHEPG5BY4eXpcYhakTvULJ":[],"3DJyQ94H9g18PR6hfzZNxwwdU6773JaYHd":[],"3Djb7sWog5ANggPWHm4xT5JiTrTSCmVQ8N":[],"3EfgjpUeJBhp3DcgP9wz3EhHNdkCbiJe2L":[],"3FWgjvaL8xN6ne19WCEeD5xxryyKAQ5tn1":[],"3H4ZtDFovXxwWXCpRo8mrCczjTrtbT6eYL":[],"3HvnjPzpaE3VGWwGTALZBguT8p9fyAcfHS":[],"3JGuY9EpzuZkDLR7vVGhqK7zmX9jhYEfmD":[],"3JvrP4gpCUeQzqgPyDt2XePXn3kpqFTo9i":[],"3K3TVvsfo52gdwz7gk84hfP77gRmpc3hkf":[],"3K5uh5viV4Dac267Q3eNurQQBnpEbYck5G":[],"3KaoWE1m3QrtvxTQLFfvNs8gwQH8kQDpFM":[],"3Koo71MC4wBfiDKTsck7qCrRjtGx2SwZqT":[],"3L8XBt8KxwqNX1vJprp6C9YfNW4hkYrC6d":[],"3QmZjxPwcsHZgVUR2gQ6wdbGJBbFro8KLJ":[]},"pruned_txo":{},"pubkeys":{"change":[["031bfbbfb36b5e526bf4d94bfc59f170177b2c821f7d4d4c0e1ee945467fe031a0","03c4664d68e3948e2017c5c55f7c1aec72c1c15686b07875b0f20d5f856ebeb703"],["03c515314e4b695a809d3ba08c20bef00397a0e2df729eaf17b8e082825395e06b","032391d8ab8cad902e503492f1051129cee42dc389231d3cdba60541d70e163244"],["035934f55c09ecec3e8f2aa72407ee7ba3c2f077be08b92a27bc4e81b5e27643fe","0332b121ed13753a1f573feaf4d0a94bf5dd1839b94018844a30490dd501f5f5fb"],["02b1367f7f07cbe1ef2c75ac83845c173770e42518da20efde3239bf988dbff5ac","03f3a8b9033b3545fbe47cab10a6f42c51393ed6e525371e864109f0865a0af43c"],["02e7c25f25ecc17969a664d5225c37ec76184a8843f7a94655f5ed34b97c52445d","030ae4304923e6d8d6cd67324fa4c8bc44827918da24a05f9240df7c91c8e8db8f"],["02deb653a1d54372dbc8656fe0a461d91bcaec18add290ccaa742bdaefdb9ec69b","023c1384f90273e3fc8bc551e71ace8f34831d4a364e56a6e778cd802b7f7965a6"]],"receiving":[["02d978f23dc1493db4daf066201f25092d91d60c4b749ca438186764e6d80e6aa1","02912a8c05d16800589579f08263734957797d8e4bc32ad7411472d3625fd51f10"],["024a4b4f2553d7f4cc2229922387aad70e5944a5266b2feb15f453cedbb5859b13","03f8c6751ee93a0f4afb7b2263982b849b3d4d13c2e30b3f8318908ad148274b4b"],["03cd88a88aabc4b833b4631f4ffb4b9dc4a0845bb7bc3309fab0764d6aa08c4f25","03568901b1f3fb8db05dd5c2092afc90671c3eb8a34b03f08bcfb6b20adf98f1cd"],["030530ffe2e4a41312a41f708febab4408ca8e431ce382c1eedb837901839b550d","024d53412197fc609a6ca6997c6634771862f2808c155723fac03ea89a5379fdcc"],["02de503d2081b523087ca195dbae55bafb27031a918a1cfedbd2c4c0da7d519902","03f4a27a98e41bddb7543bf81a9c53313bf9cfb2c2ebdb6bf96551221d8aecb01a"],["03504bc595ac0d947299759871bfdcf46bcdd8a0590c44a78b8b69f1b152019418","0291f188301773dbc7c1d12e88e3aa86e6d4a88185a896f02852141e10e7e986ab"],["0389c3ab262b7994d2202e163632a264f49dd5f78517e01c9210b6d0a29f524cd4","034bdfa9cc0c6896cb9488329d14903cfe60a2879771c5568adfc452f8dba1b2cb"],["02c55a517c162aae2cb5b36eef78b51aa15040e7293033a5b55ba299e375da297d","027273faf29e922d95987a09c2554229becb857a68112bd139409eb111e7cdb45e"],["02401e62d645dc64d43f77ba1f360b529a4c644ed3fc15b35932edafbaf741e844","02c44cbffc13cb53134354acd18c54c59fa78ec61307e147fa0f6f536fb030a675"],["02194a538f37b388b2b138f73a37d7fbb9a3e62f6b5a00bad2420650adc4fb44d9","03e5cc15d47fcdcf815baa0e15227bc5e6bd8af6cae6add71f724e95bc29714ce5"],["037ebf7b2029c8ea0c1861f98e0952c544a38b9e7caebbf514ff58683063cd0e78","022850577856c810dead8d3d44f28a3b71aaf21cdc682db1beb8056408b1d57d52"],["02aea7537611754fdafd98f341c5a6827f8301eaf98f5710c02f17a07a8938a30e","032fa37659a8365fdae3b293a855c5a692faca687b0875e9720219f9adf4bdb6c2"],["0224b0b8d200238495c58e1bc83afd2b57f9dbb79f9a1fdb40747bebb51542c8d3","03b88cd2502e62b69185b989abb786a57de27431ece4eabb26c934848d8426cbd6"],["032802b0be2a00a1e28e1e29cfd2ad79d36ef936a0ef1c834b0bbe55c1b2673bff","032669b2d80f9110e49d49480acf696b74ecca28c21e7d9c1dd2743104c54a0b13"],["03fcfa90eac92950dd66058bbef0feb153e05a114af94b6843d15200ef7cf9ea4a","023246268fbe8b9a023d9a3fa413f666853bbf92c4c0af47731fdded51751e0c3a"],["020cf5fffe70b174e242f6193930d352c54109578024677c1a13ffce5e1f9e6a29","03cb996663b9c895c3e04689f0cf1473974023fa0d59416be2a0b01ccdaa3cc484"],["03467e4fff9b33c73b0140393bde3b35a3f804bce79eccf9c53a1f76c59b7452bd","03251c2a041e953c8007d9ee838569d6be9eacfbf65857e875d87c32a8123036d8"],["02192e19803bfa6f55748aada33f778f0ebb22a1c573e5e49cba14b6a431ef1c37","02224ce74f1ee47ba6eaaf75618ce2d4768a041a553ee5eb60b38895f3f6de11dc"],["032679be8a73fa5f72d438d6963857bd9e49aef6134041ca950c70b017c0c7d44f","025a8463f1c68e85753bd2d37a640ab586d8259f21024f6173aeed15a23ad4287b"],["03ab0355c95480f0157ae48126f893a6d434aa1341ad04c71517b104f3eda08d3d","02ba4aadba99ae8dc60515b15a087e8763496fcf4026f5a637d684d0d0f8a5f76c"]]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[523,230,840,405],"x1/":{"seed":"pudding sell evoke crystal try order supply chase fine drive nurse double","type":"bip32","xprv":"xprv9s21ZrQH143K2MK5erSSgeaPA1H7gENYS6grakohkaK2M4tzqo6XAjLoRPcBRW9NbGNpaZN3pdoSKLeiQJwmqdSi3GJWZLnK1Txpbn3zinV","xpub":"xpub661MyMwAqRbcEqPYksyT3nX7i37c5h6PoKcTP9DKJur1DsE9PLQmiXfHGe8RmN538Pj8t3qUQcZXCMrkS5z1uWJ6jf9EptAFbC4Z2nKaEQE"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcGYXvLgWjW91feK49GajmPdEarB3Ny8JDduUhzTcEThc8Xs1GyqMR4S7xPHvSq4sbDEFzQh3hjJJFEksUzvnjYnap5RX9o4j"}}' + wallet_str = '{"addr_history":{"M8iTqHW9U17j1zjijVThXXfxqhHBz7TQ4y":[],"MA556vEvXjTdHd1F3ot2rk82fTDgr8Rojg":[],"MAKta33xq9CSMtjU8syxb96ZYofnuELHoC":[],"MAPKx3uCbC1muU2KkUcy4uNhbo6Py5i8E2":[],"MAZJaVNv9QEwvfiZRkxiae5Ehw4uYAc6mY":[],"MD7X8goQdbYnshsv3JQK9kMyXi1n3PjF9m":[],"MEH7HaAdVzJLKsL1EsghtP1mwTZTYycTC9":[],"MFUKaTgnm8VozP1dgp7ibEomtSxSkZjj7h":[],"MHdrEtTe6ZYhRQZVP7xJhtvL2STQgSj9E4":[],"MHowdT1zSoakJU56BZmy9v5LZSykw8QTvW":[],"MJFpdBSSMVDiLXiAAa3Pp4gQzH2nkwAV9F":[],"MJSgKNVUsKKPXnWHMxAstHnDwFJ2iayuMr":[],"MKX7i2UF6nrZBvNbmsYinbC2nnhYxXcqkQ":[],"MKwjRkvmdC1oVBfQPe4JGiZ7nZ3tCeknKP":[],"MLsq3htcFJZEqitaV2wKrswghLLeeFXhyu":[],"MMiq3ozJ65DXb9H3c5Dz2jDNBgZm6NJsoQ":[],"MPGiC6fmsepNK2UiXg87fqsQ4ATLdwP9XA":[],"MQ8w3HQnXLtv52DAZ3Ku1L9rTWk7wyhL57":[],"MQV3r2enx2RB1qh22NG3exNQ6DkBfWTWi6":[],"MR8zgx6n9bVqoLxJ56sNMHdw6kMGngptYr":[],"MRFbopHdkBt7STG1nd7QXJdWSP2Dqv3LZa":[],"MRJ3zyLgSB51QXN1VvdijVeoWVQgXUEVEu":[],"MRnwp7RizXiKjTjJS8fGCWP6G6saigQKVZ":[],"MS1wQtmA2436WibMyVjTer6q4asQ3aST6e":[],"MSLfVmYHv4goKXCCvjoS1no4hCf9ghyXXT":[],"MWyi3qouZz8zUzkK8ZPSmGqfctBhoSW7ww":[]},"pruned_txo":{},"pubkeys":{"change":[["031bfbbfb36b5e526bf4d94bfc59f170177b2c821f7d4d4c0e1ee945467fe031a0","03c4664d68e3948e2017c5c55f7c1aec72c1c15686b07875b0f20d5f856ebeb703"],["03c515314e4b695a809d3ba08c20bef00397a0e2df729eaf17b8e082825395e06b","032391d8ab8cad902e503492f1051129cee42dc389231d3cdba60541d70e163244"],["035934f55c09ecec3e8f2aa72407ee7ba3c2f077be08b92a27bc4e81b5e27643fe","0332b121ed13753a1f573feaf4d0a94bf5dd1839b94018844a30490dd501f5f5fb"],["02b1367f7f07cbe1ef2c75ac83845c173770e42518da20efde3239bf988dbff5ac","03f3a8b9033b3545fbe47cab10a6f42c51393ed6e525371e864109f0865a0af43c"],["02e7c25f25ecc17969a664d5225c37ec76184a8843f7a94655f5ed34b97c52445d","030ae4304923e6d8d6cd67324fa4c8bc44827918da24a05f9240df7c91c8e8db8f"],["02deb653a1d54372dbc8656fe0a461d91bcaec18add290ccaa742bdaefdb9ec69b","023c1384f90273e3fc8bc551e71ace8f34831d4a364e56a6e778cd802b7f7965a6"]],"receiving":[["02d978f23dc1493db4daf066201f25092d91d60c4b749ca438186764e6d80e6aa1","02912a8c05d16800589579f08263734957797d8e4bc32ad7411472d3625fd51f10"],["024a4b4f2553d7f4cc2229922387aad70e5944a5266b2feb15f453cedbb5859b13","03f8c6751ee93a0f4afb7b2263982b849b3d4d13c2e30b3f8318908ad148274b4b"],["03cd88a88aabc4b833b4631f4ffb4b9dc4a0845bb7bc3309fab0764d6aa08c4f25","03568901b1f3fb8db05dd5c2092afc90671c3eb8a34b03f08bcfb6b20adf98f1cd"],["030530ffe2e4a41312a41f708febab4408ca8e431ce382c1eedb837901839b550d","024d53412197fc609a6ca6997c6634771862f2808c155723fac03ea89a5379fdcc"],["02de503d2081b523087ca195dbae55bafb27031a918a1cfedbd2c4c0da7d519902","03f4a27a98e41bddb7543bf81a9c53313bf9cfb2c2ebdb6bf96551221d8aecb01a"],["03504bc595ac0d947299759871bfdcf46bcdd8a0590c44a78b8b69f1b152019418","0291f188301773dbc7c1d12e88e3aa86e6d4a88185a896f02852141e10e7e986ab"],["0389c3ab262b7994d2202e163632a264f49dd5f78517e01c9210b6d0a29f524cd4","034bdfa9cc0c6896cb9488329d14903cfe60a2879771c5568adfc452f8dba1b2cb"],["02c55a517c162aae2cb5b36eef78b51aa15040e7293033a5b55ba299e375da297d","027273faf29e922d95987a09c2554229becb857a68112bd139409eb111e7cdb45e"],["02401e62d645dc64d43f77ba1f360b529a4c644ed3fc15b35932edafbaf741e844","02c44cbffc13cb53134354acd18c54c59fa78ec61307e147fa0f6f536fb030a675"],["02194a538f37b388b2b138f73a37d7fbb9a3e62f6b5a00bad2420650adc4fb44d9","03e5cc15d47fcdcf815baa0e15227bc5e6bd8af6cae6add71f724e95bc29714ce5"],["037ebf7b2029c8ea0c1861f98e0952c544a38b9e7caebbf514ff58683063cd0e78","022850577856c810dead8d3d44f28a3b71aaf21cdc682db1beb8056408b1d57d52"],["02aea7537611754fdafd98f341c5a6827f8301eaf98f5710c02f17a07a8938a30e","032fa37659a8365fdae3b293a855c5a692faca687b0875e9720219f9adf4bdb6c2"],["0224b0b8d200238495c58e1bc83afd2b57f9dbb79f9a1fdb40747bebb51542c8d3","03b88cd2502e62b69185b989abb786a57de27431ece4eabb26c934848d8426cbd6"],["032802b0be2a00a1e28e1e29cfd2ad79d36ef936a0ef1c834b0bbe55c1b2673bff","032669b2d80f9110e49d49480acf696b74ecca28c21e7d9c1dd2743104c54a0b13"],["03fcfa90eac92950dd66058bbef0feb153e05a114af94b6843d15200ef7cf9ea4a","023246268fbe8b9a023d9a3fa413f666853bbf92c4c0af47731fdded51751e0c3a"],["020cf5fffe70b174e242f6193930d352c54109578024677c1a13ffce5e1f9e6a29","03cb996663b9c895c3e04689f0cf1473974023fa0d59416be2a0b01ccdaa3cc484"],["03467e4fff9b33c73b0140393bde3b35a3f804bce79eccf9c53a1f76c59b7452bd","03251c2a041e953c8007d9ee838569d6be9eacfbf65857e875d87c32a8123036d8"],["02192e19803bfa6f55748aada33f778f0ebb22a1c573e5e49cba14b6a431ef1c37","02224ce74f1ee47ba6eaaf75618ce2d4768a041a553ee5eb60b38895f3f6de11dc"],["032679be8a73fa5f72d438d6963857bd9e49aef6134041ca950c70b017c0c7d44f","025a8463f1c68e85753bd2d37a640ab586d8259f21024f6173aeed15a23ad4287b"],["03ab0355c95480f0157ae48126f893a6d434aa1341ad04c71517b104f3eda08d3d","02ba4aadba99ae8dc60515b15a087e8763496fcf4026f5a637d684d0d0f8a5f76c"]]},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[523,230,840,405],"x1/":{"seed":"pudding sell evoke crystal try order supply chase fine drive nurse double","type":"bip32","xprv":"xprv9s21ZrQH143K2MK5erSSgeaPA1H7gENYS6grakohkaK2M4tzqo6XAjLoRPcBRW9NbGNpaZN3pdoSKLeiQJwmqdSi3GJWZLnK1Txpbn3zinV","xpub":"xpub661MyMwAqRbcEqPYksyT3nX7i37c5h6PoKcTP9DKJur1DsE9PLQmiXfHGe8RmN538Pj8t3qUQcZXCMrkS5z1uWJ6jf9EptAFbC4Z2nKaEQE"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcGYXvLgWjW91feK49GajmPdEarB3Ny8JDduUhzTcEThc8Xs1GyqMR4S7xPHvSq4sbDEFzQh3hjJJFEksUzvnjYnap5RX9o4j"}}' self._upgrade_storage(wallet_str) # seed_version 13 is ambiguous @@ -208,47 +208,47 @@ def test_upgrade_from_client_2_7_18_multisig(self): # then opened in 2.8.3, after which a few other new privkeys were imported # it's in some sense in an "inconsistent" state def test_upgrade_from_client_2_8_3_importedkeys_flawed_previous_upgrade_from_2_7_18(self): - wallet_str = '{"addr_history":{"15VBrfYwoXvDWyXHq1myxDv4h36qUmCHcE":[],"179vRrzjT9k7k5oCNCx6eodYCaLKPy9UQn":[],"18o6WCBWdAaM5kjKnyEL4HysoT324rvJu7":[],"1A9F6ZEqmfKeuLeEq5eWFxajgiJfGCc7ar":[],"1BTjGNUmeMSPBTuXTdwD3DLyCugAZaFb7w":[],"1CjW4KM38acCRw3spiFKiZsj7xmmQqqwd8":[],"1EaDNLPwHRraX1N3ecPWJ2mm7NRgdtvpCj":[],"1PYtQBkjXHQX6YtMzEgehN638o784pK3ce":[],"1yT2T4ha3i1GZoK2iP8EpcgSNG34R2ufM":[]},"addresses":{"change":[],"receiving":["1PYtQBkjXHQX6YtMzEgehN638o784pK3ce","1yT2T4ha3i1GZoK2iP8EpcgSNG34R2ufM","1CjW4KM38acCRw3spiFKiZsj7xmmQqqwd8","1A9F6ZEqmfKeuLeEq5eWFxajgiJfGCc7ar","18o6WCBWdAaM5kjKnyEL4HysoT324rvJu7","1EaDNLPwHRraX1N3ecPWJ2mm7NRgdtvpCj","179vRrzjT9k7k5oCNCx6eodYCaLKPy9UQn","1BTjGNUmeMSPBTuXTdwD3DLyCugAZaFb7w","15VBrfYwoXvDWyXHq1myxDv4h36qUmCHcE"]},"keystore":{"keypairs":{"0206b77fd06f212ad7d85f4a054c231ba4e7894b1773dcbb449671ee54618ff5e9":"L52LWS2hB5ev9JYiisFewJH9Q16U7yYcSNt3M8UKLmL5p1q3v2H2","028cda4a0f03cbcbc695d9cac0858081fd5458acfd29564127d329553245afca42":"KzRhkN9Psm9BobcPx3X3VykVA8yhCBrVvE4tTyq6NE283sL6uvYG","02ba4117a24d7e38ae14c429fce0d521aa1fb6bb97558a13f1ef2bc0a476a1741f":"KySXfvidmMBf8iw6m3R9WtdfKcQPWXenwMZtpno5XpfLMNHH8PMn","031bb44462038b97010624a8f8cb15a10fd0d277f12aba3ccf5ce0d36fc6df3112":"KxmcmCvNrZFgy2jyz9W353XbMwCYWHzYTQVzbaDfZM4FLxemgmKh","0339081c4a0ce22c01aa78a5d025e7a109100d1a35ef0f8f06a0d4c5f9ffefc042":"L53Ks569m3H1dRzua3nGzBE3AaEV8dMvBoHDeSJGnWEDeL775mJ5","0339ea71aba2805238e636c2f1b3e5a8308b1dbdbb335787c51f2f6bf3f6218643":"KwHDUpfvnSC58bs3nGy7YpducXkbmo6UUHrydBHy6sT1mRJcVvBo","04e7dc460c87267cf0958d6904d9cd99a4af0d64d61858636aec7a02e5f9a578d27c1329d5ddc45a937130ed4a59e4147cb4907724321baa6a976f9972a17f79ba":"5JECca5E7r1eNgME7NsPdE29XiVCVwXSzEihnhAQXuMdsJ4VL8S","04e9ad0bf70c51c06c2459961175c47cfec59d58ebef4ffcd9836904ef11230afce03ab5eaac5958b538382195b5aea9bf057c0486079869bb72ef9c958f33f1ed":"5Jt9rGLWgxoJUo4eoYEECskLmRA4BkZqHPHg7DdghKBaWarKuxW","04f8cbd67830ab37138c92898a64a4edf836a60aa5b36956547788bd205c635d6a3056fa6a079961384ae336e737d4c45835821c8915dbc5e18a7def88df83946b":"5KRjCNThRDP8aQTJ3Hq9HUSVNRNUB2e69xwLfMUsrXYLXT7U8b9"},"type":"imported"},"pruned_txo":{},"pubkeys":{"change":[],"receiving":["04e9ad0bf70c51c06c2459961175c47cfec59d58ebef4ffcd9836904ef11230afce03ab5eaac5958b538382195b5aea9bf057c0486079869bb72ef9c958f33f1ed","0339081c4a0ce22c01aa78a5d025e7a109100d1a35ef0f8f06a0d4c5f9ffefc042","0339ea71aba2805238e636c2f1b3e5a8308b1dbdbb335787c51f2f6bf3f6218643","02ba4117a24d7e38ae14c429fce0d521aa1fb6bb97558a13f1ef2bc0a476a1741f","028cda4a0f03cbcbc695d9cac0858081fd5458acfd29564127d329553245afca42","04e7dc460c87267cf0958d6904d9cd99a4af0d64d61858636aec7a02e5f9a578d27c1329d5ddc45a937130ed4a59e4147cb4907724321baa6a976f9972a17f79ba","04f8cbd67830ab37138c92898a64a4edf836a60aa5b36956547788bd205c635d6a3056fa6a079961384ae336e737d4c45835821c8915dbc5e18a7def88df83946b"]},"seed_version":13,"stored_height":492756,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' + wallet_str = '{"addr_history":{"LPi97srmtCAGmnDT19mHEEypuFU7ZPmHCt":[],"LRNsh5JZXozAztVMYLwPvphJQnhbVzYfgG":[],"LT23mQVLhppQLZRUy7DdLK3e1fQJFz4Vbt":[],"LUNCMmYfrKZiA9LQ1DdoXyeVtvfwJYQa8Y":[],"LVggXanbj1gSSGbgdmvWKEQjR83Si2W5e1":[],"LWxTKXesDErFgjk2zrEczawVLB93XBN17Z":[],"LYoAdYhmN66dmp4CpkNoa3qXKanxmSoSP4":[],"LhmqfQ4ZbweaMMaXANfwyP9oM1UQBhojhc":[],"LLCQHfNXehx4XNVUCrNRWqgSeadK8mKQWj":[]},"addresses":{"change":[],"receiving":["LhmqfQ4ZbweaMMaXANfwyP9oM1UQBhojhc","LLCQHfNXehx4XNVUCrNRWqgSeadK8mKQWj","LWxTKXesDErFgjk2zrEczawVLB93XBN17Z","LUNCMmYfrKZiA9LQ1DdoXyeVtvfwJYQa8Y","LT23mQVLhppQLZRUy7DdLK3e1fQJFz4Vbt","LYoAdYhmN66dmp4CpkNoa3qXKanxmSoSP4","LRNsh5JZXozAztVMYLwPvphJQnhbVzYfgG","LVggXanbj1gSSGbgdmvWKEQjR83Si2W5e1","LPi97srmtCAGmnDT19mHEEypuFU7ZPmHCt"]},"keystore":{"keypairs":{"0206b77fd06f212ad7d85f4a054c231ba4e7894b1773dcbb449671ee54618ff5e9":"TArbxBKsaTdWv9BbGWCX9epXLrjnC4ZWFanJCw6rujWFKuUey6VQ","028cda4a0f03cbcbc695d9cac0858081fd5458acfd29564127d329553245afca42":"T6FyC7SaH97naSFGVgTuiLHs6zd1GGsPjRy9KnTdwCCHZku7rQJr","02ba4117a24d7e38ae14c429fce0d521aa1fb6bb97558a13f1ef2bc0a476a1741f":"T5Go7g1pAjAFuZZyJgN1jFB3GU3hacfgkZU9gbRd6nqVsFmtPMio","031bb44462038b97010624a8f8cb15a10fd0d277f12aba3ccf5ce0d36fc6df3112":"T4btCxDZFwEHjsNrXnSuHQ4yJnqraP1SGcQFTNrD8KEQrrAersDu","0339081c4a0ce22c01aa78a5d025e7a109100d1a35ef0f8f06a0d4c5f9ffefc042":"TAsbJpPLARFcQGdn7gj9CXmR7RsoCiNp11BUWEvpMUQPADjCH2E4","0339ea71aba2805238e636c2f1b3e5a8308b1dbdbb335787c51f2f6bf3f6218643":"T37UvZy7BpAfuSVvKuuymBBHZPPuqt7NHVmEUyvWfqdBHJoxiKkw","04e7dc460c87267cf0958d6904d9cd99a4af0d64d61858636aec7a02e5f9a578d27c1329d5ddc45a937130ed4a59e4147cb4907724321baa6a976f9972a17f79ba":"6uXw5hcm2GUWr4F5dCfMQcoKVC3fhjyUkv7sVtBSFMgFZB63bNt","04e9ad0bf70c51c06c2459961175c47cfec59d58ebef4ffcd9836904ef11230afce03ab5eaac5958b538382195b5aea9bf057c0486079869bb72ef9c958f33f1ed":"6vBtKPt3bPGAxAxWKN2BzGXWitiXPZ1s44gqpQeiQmWCCQYsJeB","04f8cbd67830ab37138c92898a64a4edf836a60aa5b36956547788bd205c635d6a3056fa6a079961384ae336e737d4c45835821c8915dbc5e18a7def88df83946b":"6vjTfW1EKdr13nM9Z7d74sDfKtvwNq67veLWNYVuZyrxDHmTv51"},"type":"imported"},"pruned_txo":{},"pubkeys":{"change":[],"receiving":["04e9ad0bf70c51c06c2459961175c47cfec59d58ebef4ffcd9836904ef11230afce03ab5eaac5958b538382195b5aea9bf057c0486079869bb72ef9c958f33f1ed","0339081c4a0ce22c01aa78a5d025e7a109100d1a35ef0f8f06a0d4c5f9ffefc042","0339ea71aba2805238e636c2f1b3e5a8308b1dbdbb335787c51f2f6bf3f6218643","02ba4117a24d7e38ae14c429fce0d521aa1fb6bb97558a13f1ef2bc0a476a1741f","028cda4a0f03cbcbc695d9cac0858081fd5458acfd29564127d329553245afca42","04e7dc460c87267cf0958d6904d9cd99a4af0d64d61858636aec7a02e5f9a578d27c1329d5ddc45a937130ed4a59e4147cb4907724321baa6a976f9972a17f79ba","04f8cbd67830ab37138c92898a64a4edf836a60aa5b36956547788bd205c635d6a3056fa6a079961384ae336e737d4c45835821c8915dbc5e18a7def88df83946b"]},"seed_version":13,"stored_height":492756,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_8_3_seeded(self): - wallet_str = '{"addr_history":{"13sNgoAhqDUTB3YSzWYcKKvP2EczG5JGmt":[],"14C6nXs2GRaK3o5U5e8dJSpVRCoqTsyAkJ":[],"14fH7oRM4bqJtJkgJEynTShcUXQwdxH6mw":[],"16FECc7nP2wor1ijXKihGofUoCkoJnq6XR":[],"16cMJC5ZAtPnvLQBzfHm9YR9GoDxUseMEk":[],"17CbQhK3gutqgWt2iLX69ZeSCvw8yFxPLz":[],"17jEaAyekE8BHPvPmkJqFUh1v1GSi6ywoV":[],"19F5SjaWYVCKMPWR8q1Freo4RGChSmFztL":[],"19snysSPZEbgjmeMtuT7qDMTLH2fa7zrWW":[],"1AFgvLGNHP3nZDNrZ4R2BZKnbwDVAEUP4q":[],"1AwWgUbjQfRhKVLKm1o7qfpXnqeN3cu7Ms":[],"1B4FU2WEd2NQzd2MkWBLHw87uJhBxoVghh":[],"1BEBouVJFihDmEQMTAv4bNV2Q7dZh5iJzv":[],"1BdB7ahc8TSR9RJDmWgGSgsWji2BgzcVvC":[],"1DGhQ1up6dMieEwFdsQQFHRriyyR59rYVq":[],"1HBAAqFVndXBcWdWQNYVYSDK9kdUu8ZRU3":[],"1HMrRJkTayNRBZdXZKVb7oLZKj24Pq65T6":[],"1HiB2QCfNem8b4cJaZ2Rt9T4BbUCPXvTpT":[],"1HkbtbyocwHWjKBmzKmq8szv3cFgSGy7dL":[],"1K5CWjgZEYcKTsJWeQrH6NcMPzFUAikD8z":[],"1KMDUXdqpthH1XZU4q5kdSoMZmCW9yDMcN":[],"1KmHNiNmeS7tWRLYTFDMrTbKR6TERYicst":[],"1NQwmHYdxU1pFTTWyptn8vPW1hsSWJBRTn":[],"1NuPofeK8yNEjtVAu9Rc2pKS9kw8YWUatL":[],"1Q3eTNJWTnfxPkUJXQkeCqPh1cBQjjEXFn":[],"1QEuVTdenchPn9naMhakYx8QwGUXE6JYp":[]},"addresses":{"change":["1K5CWjgZEYcKTsJWeQrH6NcMPzFUAikD8z","19snysSPZEbgjmeMtuT7qDMTLH2fa7zrWW","1DGhQ1up6dMieEwFdsQQFHRriyyR59rYVq","17CbQhK3gutqgWt2iLX69ZeSCvw8yFxPLz","1Q3eTNJWTnfxPkUJXQkeCqPh1cBQjjEXFn","17jEaAyekE8BHPvPmkJqFUh1v1GSi6ywoV"],"receiving":["1KMDUXdqpthH1XZU4q5kdSoMZmCW9yDMcN","1HkbtbyocwHWjKBmzKmq8szv3cFgSGy7dL","1HiB2QCfNem8b4cJaZ2Rt9T4BbUCPXvTpT","14fH7oRM4bqJtJkgJEynTShcUXQwdxH6mw","1NuPofeK8yNEjtVAu9Rc2pKS9kw8YWUatL","16FECc7nP2wor1ijXKihGofUoCkoJnq6XR","19F5SjaWYVCKMPWR8q1Freo4RGChSmFztL","1NQwmHYdxU1pFTTWyptn8vPW1hsSWJBRTn","1HBAAqFVndXBcWdWQNYVYSDK9kdUu8ZRU3","1B4FU2WEd2NQzd2MkWBLHw87uJhBxoVghh","1HMrRJkTayNRBZdXZKVb7oLZKj24Pq65T6","1KmHNiNmeS7tWRLYTFDMrTbKR6TERYicst","1BdB7ahc8TSR9RJDmWgGSgsWji2BgzcVvC","14C6nXs2GRaK3o5U5e8dJSpVRCoqTsyAkJ","1AFgvLGNHP3nZDNrZ4R2BZKnbwDVAEUP4q","13sNgoAhqDUTB3YSzWYcKKvP2EczG5JGmt","1AwWgUbjQfRhKVLKm1o7qfpXnqeN3cu7Ms","1QEuVTdenchPn9naMhakYx8QwGUXE6JYp","1BEBouVJFihDmEQMTAv4bNV2Q7dZh5iJzv","16cMJC5ZAtPnvLQBzfHm9YR9GoDxUseMEk"]},"keystore":{"seed":"novel clay width echo swing blanket absorb salute asset under ginger final","type":"bip32","xprv":"xprv9s21ZrQH143K2jfFF6ektPj6zCCsDGGjQxhD2FQ21j6yrA1piWWEjch2kf1smzB2rzm8rPkdJuHf3vsKqMX9ogtE2A7JF49qVUHrgtjRymM","xpub":"xpub661MyMwAqRbcFDjiM8BmFXfqYE3McizanBcopdoda4dxixLyG3pVHR1WbwgjLo9RL882KRfpfpxh7a7zXPogDdR4xj9TpJWJGsbwaodLSKe"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' + wallet_str = '{"addr_history":{"LN6Kx1UXusiWRrEcAeXubLz9ESzGRQwKcu":[],"LNR43kArM5pNJbmdFn7vaTtFdRB7a94V8x":[],"LNtEP1jB9G5N97SqUNy5jTmNgjnDofR2DW":[],"LQUBTpRcThBs6pQthThzYpjF1R85RnLRad":[],"LQqJZQPPFYdrB96MAoH4RZUuV1bEYGQzgB":[],"LRRYfucsma8twKaBtUWPRaiCR9JR5mtDJo":[],"LRxBqPHUptNEYCcYwtJ8XVkn8DdirU1M4J":[],"LTU2hwtLd9SNcCCaJxzZ8frpdUZyVGohou":[],"LU6kF5kDdtqjzaLX53SR7ERDYVPwd9iKfr":[],"LUUeBYaCN3Hqp251jCQKTaPYp9amJpSHML":[],"LVATwguZVKfkaJ2Uw9nR7gtJ141e6pxHCG":[],"LVHCjEp4hgcUFRiWveAdZxBt7X4U8r93F2":[],"LVT957o8LNwH236WdJuMsPYncKzqmrWyJM":[],"LVr8No1SD7gUQDzNwefZihwGwvPTnWxmg2":[],"LXVefEDeBHbmu3dQp1PhXJVcwCLh99DUVe":[],"LbQ7S3ZKsHmEsKKfaWXnpTH5Mxzm3EUigP":[],"LbaogX4HfdcUSNKgjTUtPpQKXwPLVrf6q2":[],"Lbw8HcWVTK1BqsJTkh1jAAWpPoqUSM7h1K":[],"LbyZ9pHdhbXZz7swATm8Qu4gFpcxZCBsFa":[],"LdJ9mwzPKCrNifzfpYqaNPg7cCckHRhfPU":[],"LdaAjjwfuYwLGLFdEy53uTs7myZnG3pQr4":[],"LdzEdvgbj6MwmE2hdPCf8Uf5dJpWVcSqVt":[],"Lgdu2VrU38FsWG9g9xt5QwTGDvEie2hWou":[],"Lh8M4sx9DdcHzhBL5HQuJqPCMyJQdXBFXY":[],"LiGbiacLYSv1eZAThYjwUrTTDpYgvBVvXm":[],"LKdCAhmTjSrkeaqwkVgt2a1td9dkeCBwDX":[]},"addresses":{"change":["LdJ9mwzPKCrNifzfpYqaNPg7cCckHRhfPU","LU6kF5kDdtqjzaLX53SR7ERDYVPwd9iKfr","LXVefEDeBHbmu3dQp1PhXJVcwCLh99DUVe","LRRYfucsma8twKaBtUWPRaiCR9JR5mtDJo","LiGbiacLYSv1eZAThYjwUrTTDpYgvBVvXm","LRxBqPHUptNEYCcYwtJ8XVkn8DdirU1M4J"],"receiving":["LdaAjjwfuYwLGLFdEy53uTs7myZnG3pQr4","LbyZ9pHdhbXZz7swATm8Qu4gFpcxZCBsFa","Lbw8HcWVTK1BqsJTkh1jAAWpPoqUSM7h1K","LNtEP1jB9G5N97SqUNy5jTmNgjnDofR2DW","Lh8M4sx9DdcHzhBL5HQuJqPCMyJQdXBFXY","LQUBTpRcThBs6pQthThzYpjF1R85RnLRad","LTU2hwtLd9SNcCCaJxzZ8frpdUZyVGohou","Lgdu2VrU38FsWG9g9xt5QwTGDvEie2hWou","LbQ7S3ZKsHmEsKKfaWXnpTH5Mxzm3EUigP","LVHCjEp4hgcUFRiWveAdZxBt7X4U8r93F2","LbaogX4HfdcUSNKgjTUtPpQKXwPLVrf6q2","LdzEdvgbj6MwmE2hdPCf8Uf5dJpWVcSqVt","LVr8No1SD7gUQDzNwefZihwGwvPTnWxmg2","LNR43kArM5pNJbmdFn7vaTtFdRB7a94V8x","LUUeBYaCN3Hqp251jCQKTaPYp9amJpSHML","LN6Kx1UXusiWRrEcAeXubLz9ESzGRQwKcu","LVATwguZVKfkaJ2Uw9nR7gtJ141e6pxHCG","LKdCAhmTjSrkeaqwkVgt2a1td9dkeCBwDX","LVT957o8LNwH236WdJuMsPYncKzqmrWyJM","LQqJZQPPFYdrB96MAoH4RZUuV1bEYGQzgB"]},"keystore":{"seed":"novel clay width echo swing blanket absorb salute asset under ginger final","type":"bip32","xprv":"xprv9s21ZrQH143K2jfFF6ektPj6zCCsDGGjQxhD2FQ21j6yrA1piWWEjch2kf1smzB2rzm8rPkdJuHf3vsKqMX9ogtE2A7JF49qVUHrgtjRymM","xpub":"xpub661MyMwAqRbcFDjiM8BmFXfqYE3McizanBcopdoda4dxixLyG3pVHR1WbwgjLo9RL882KRfpfpxh7a7zXPogDdR4xj9TpJWJGsbwaodLSKe"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_8_3_importedkeys(self): - wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' + wallet_str = '{"addr_history":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":[],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":[],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":[]},"addresses":{"change":[],"receiving":["LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY","LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb","LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_8_3_watchaddresses(self): - wallet_str = '{"addr_history":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[]},"addresses":["1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs","1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa","1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf"],"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[535,380,840,405]}' + wallet_str = '{"addr_history":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[]},"addresses":["LbGiejb64pNXrjPZfiauVkchFQksBnFjrz","Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy","LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2"],"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[535,380,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_8_3_trezor_singleacc(self): - wallet_str = '''{"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"addresses":{"change":["1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ","14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM","1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG","15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6","1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL","1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs"],"receiving":["1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu","18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw","17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH","12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC","15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ","1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid","1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz","1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj","146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz","1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC","1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo","1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb","1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe","1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv","1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp","15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S","1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX","1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp","1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk","1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD"]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[744,390,840,405]}''' + wallet_str = '''{"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"addresses":{"change":["LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV","LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK","LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o","LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN","LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom","Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG"],"receiving":["Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4","LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ","LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC","LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf","LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX","Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf","Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG","Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr","LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT","LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R","LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4","LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi","LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ","LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE","LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN","LQDkeaPgZyTG88UietSqaXKgGthudu92c8","LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P","LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo","LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ","LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw"]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[744,390,840,405]}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_8_3_multisig(self): - wallet_str = '{"addr_history":{"32Qk6Q7XYD2v3et9g5fA97ky8XRAJNDZCS":[],"339axnadPaQg3ngChNBKap2dndUWrSwjk6":[],"34FG8qzA6UYLxrnkpVkM9mrGYix3ZyePJZ":[],"35CR3h2dFF3EkRX5yK47NGuF2FcLtJvpUM":[],"35zrocLBQbHfEqysgv2v5z3RH7BRGQzSMJ":[],"36uBJPkgiQwav23ybewbgkQ2zEzJDY2EX1":[],"37nSiBvGXm1PNYseymaJn5ERcU4mSMueYc":[],"39r4XCmfU4J3N98YQ8Fwvm8VN1Fukfj7QW":[],"3BDqFoYMxyy7nWCpRChYV6YCGh9qnWDmav":[],"3CGCLSHU8ZjeXv6oukJ3eAQN4fqEQ7wuyX":[],"3DCNnfh7oWLsnS3p5QdWfW3hvcFF8qAPFq":[],"3DPheE9uany9ET2qBnWF1wh3zDtptGP6Ts":[],"3EeNJHgSYVJPxYR2NaYv2M2ZnXkPRWSHQh":[],"3FWZ7pJPxZhGr8p6HNr9LLsHA8sABcP7cF":[],"3FZbzEF9HdRqzif2cKUFnwW9AFTJcibjVK":[],"3GEhQHTrWykC6Jfu923qtpxJECsEGVdhUc":[],"3HJ95uxwW6rMoEhYgUfcgpd3ExU3fjkfNb":[],"3HbdMVgKRqadNiHRNGizUCyTQYpJ1aXFav":[],"3J6xRF9d16QNsvoXkYkeTwTU8L5N3Y8f7c":[],"3JBbS3GvhvoLgtLcuMvHCtqjE7dnbpTMkz":[],"3KNWZasWDBuVzzp5Y5cbEgjeYn3NKHZKso":[],"3KQ5tTEbkQSkKiccKFDPrhLnBjSMey6CQM":[],"3KrFHcAzNJYjukGDDZm2HeV5Mok4NGQaD6":[],"3LNZbX9wenL3bLxJTQnPidSvVt3EtDrnUg":[],"3LzjAqqfiN8w4TSiW8Up7bKLD5CicBUC3a":[],"3Nro51wauHugv72NMtY9pmLnwX3FXWU1eE":[]},"addresses":{"change":["34FG8qzA6UYLxrnkpVkM9mrGYix3ZyePJZ","3LzjAqqfiN8w4TSiW8Up7bKLD5CicBUC3a","3GEhQHTrWykC6Jfu923qtpxJECsEGVdhUc","3Nro51wauHugv72NMtY9pmLnwX3FXWU1eE","3JBbS3GvhvoLgtLcuMvHCtqjE7dnbpTMkz","3CGCLSHU8ZjeXv6oukJ3eAQN4fqEQ7wuyX"],"receiving":["35zrocLBQbHfEqysgv2v5z3RH7BRGQzSMJ","3FWZ7pJPxZhGr8p6HNr9LLsHA8sABcP7cF","3DPheE9uany9ET2qBnWF1wh3zDtptGP6Ts","3HbdMVgKRqadNiHRNGizUCyTQYpJ1aXFav","3KQ5tTEbkQSkKiccKFDPrhLnBjSMey6CQM","35CR3h2dFF3EkRX5yK47NGuF2FcLtJvpUM","3HJ95uxwW6rMoEhYgUfcgpd3ExU3fjkfNb","3FZbzEF9HdRqzif2cKUFnwW9AFTJcibjVK","39r4XCmfU4J3N98YQ8Fwvm8VN1Fukfj7QW","3LNZbX9wenL3bLxJTQnPidSvVt3EtDrnUg","32Qk6Q7XYD2v3et9g5fA97ky8XRAJNDZCS","339axnadPaQg3ngChNBKap2dndUWrSwjk6","3EeNJHgSYVJPxYR2NaYv2M2ZnXkPRWSHQh","3BDqFoYMxyy7nWCpRChYV6YCGh9qnWDmav","3DCNnfh7oWLsnS3p5QdWfW3hvcFF8qAPFq","3KNWZasWDBuVzzp5Y5cbEgjeYn3NKHZKso","37nSiBvGXm1PNYseymaJn5ERcU4mSMueYc","3KrFHcAzNJYjukGDDZm2HeV5Mok4NGQaD6","36uBJPkgiQwav23ybewbgkQ2zEzJDY2EX1","3J6xRF9d16QNsvoXkYkeTwTU8L5N3Y8f7c"]},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[671,238,840,405],"x1/":{"seed":"property play install hill hunt follow trash comic pulse consider canyon limit","type":"bip32","xprv":"xprv9s21ZrQH143K46tCjDh5i4H9eSJpnMrYyLUbVZheTbNjiamdxPiffMEYLgxuYsMFokFrNEZ6S6z5wSXXszXaCVQWf6jzZvn14uYZhsnM9Sb","xpub":"xpub661MyMwAqRbcGaxfqFE65CDtCU9KBpaQLZQCHx7G1vuibP6nVw2vD9Z2Bz2DsH43bDZGXjmcvx2TD9wq3CmmFcoT96RCiDd1wMSUB2UH7Gu"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcEncvVc1zrPFZSKe7iAP1LTRhzxuXpmztu1kTtnfj8XNFzzmGH1X1gcGxczBZ3MmYKkxXgZKJCsNXXdasNaQJKJE4KcUjn1L"}}' + wallet_str = '{"addr_history":{"M8ctQHXVVKtLrAA3mxeVxm1NTE1cLB59XX":[],"M9MjGfzbLhG6rHx6oFAfQTH37L4xroiVcz":[],"MATQSjQ83bPmmN4evNjgyR6fsRYVXUEi91":[],"MBQZMaSbCMtfYvnz5C3TBv9eLxCnuAwdtH":[],"MCD17Vk9Mi963MFmno2FudHpbomsE8n6tg":[],"MD7KcHAefXo1iXKshXvwWPeSJwakELozTJ":[],"MDzb25LEUsrpB49Z5eZebiUpwAfDTdhHtS":[],"MG4Cq6BdRB9UAeQSW1FHkQNtghrMnk1uBk":[],"MHRyZgxKv6pYb1UiX5gtJjnbbPkHpKKpva":[],"MJULeKhS5gb5LRNi1dHPToemPNRgMxbtnj":[],"MKQX6Z75kdCJawKiBHcrV9J7FJqh7uwJPD":[],"MKbqx7ZsXupa2xJjHfVaqawTJvVGsBwAtX":[],"MLrWcB6QVc9pm3gvUTYFqzGy7ELqNssXpx":[],"MMihRhiMugYhee5zPFqV9z7gUqTc7xNtbj":[],"MMmkJ7f7EkHGoDvviCTbcakYUx3kaW27wz":[],"MNSqiAspU6bctowoEu3BiUChYuTgFZcjn1":[],"MPWHPoNuTDhnbjySnMexWTsSZf4VZvHbPj":[],"MPomfP6HNxS4BDZKU9iLHrDrjFQjyCUA8q":[],"MQK6j8ZaxDFogS5RrRjzHahsT2fozuLaWx":[],"MQPjjvgtf3emVPcX1Eud2Y68YpEEbFDHw5":[],"MRaesUHUAJkvoW5ydxbw4Kz3sUdpGiN3pS":[],"MRcECLeZhXJB8DtWR8CjgLbBWS2odKRiga":[],"MS4PbVaxKRQAiFY7KSkN7HjUgWLWHxMjFd":[],"MSahuQZubuBUPrECZHmjYGhKpadgx4KiVK":[],"MTCsUjFdfUzMrxicc1U9wEZjXmoAbFyUZa":[],"MV4wNuMYrQm7icJGTmXVeQbCGDdhZeabe9":[]},"addresses":{"change":["MATQSjQ83bPmmN4evNjgyR6fsRYVXUEi91","MTCsUjFdfUzMrxicc1U9wEZjXmoAbFyUZa","MNSqiAspU6bctowoEu3BiUChYuTgFZcjn1","MV4wNuMYrQm7icJGTmXVeQbCGDdhZeabe9","MQPjjvgtf3emVPcX1Eud2Y68YpEEbFDHw5","MJULeKhS5gb5LRNi1dHPToemPNRgMxbtnj"],"receiving":["MCD17Vk9Mi963MFmno2FudHpbomsE8n6tg","MMihRhiMugYhee5zPFqV9z7gUqTc7xNtbj","MKbqx7ZsXupa2xJjHfVaqawTJvVGsBwAtX","MPomfP6HNxS4BDZKU9iLHrDrjFQjyCUA8q","MRcECLeZhXJB8DtWR8CjgLbBWS2odKRiga","MBQZMaSbCMtfYvnz5C3TBv9eLxCnuAwdtH","MPWHPoNuTDhnbjySnMexWTsSZf4VZvHbPj","MMmkJ7f7EkHGoDvviCTbcakYUx3kaW27wz","MG4Cq6BdRB9UAeQSW1FHkQNtghrMnk1uBk","MSahuQZubuBUPrECZHmjYGhKpadgx4KiVK","M8ctQHXVVKtLrAA3mxeVxm1NTE1cLB59XX","M9MjGfzbLhG6rHx6oFAfQTH37L4xroiVcz","MLrWcB6QVc9pm3gvUTYFqzGy7ELqNssXpx","MHRyZgxKv6pYb1UiX5gtJjnbbPkHpKKpva","MKQX6Z75kdCJawKiBHcrV9J7FJqh7uwJPD","MRaesUHUAJkvoW5ydxbw4Kz3sUdpGiN3pS","MDzb25LEUsrpB49Z5eZebiUpwAfDTdhHtS","MS4PbVaxKRQAiFY7KSkN7HjUgWLWHxMjFd","MD7KcHAefXo1iXKshXvwWPeSJwakELozTJ","MQK6j8ZaxDFogS5RrRjzHahsT2fozuLaWx"]},"pruned_txo":{},"seed_version":13,"stored_height":0,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[671,238,840,405],"x1/":{"seed":"property play install hill hunt follow trash comic pulse consider canyon limit","type":"bip32","xprv":"xprv9s21ZrQH143K46tCjDh5i4H9eSJpnMrYyLUbVZheTbNjiamdxPiffMEYLgxuYsMFokFrNEZ6S6z5wSXXszXaCVQWf6jzZvn14uYZhsnM9Sb","xpub":"xpub661MyMwAqRbcGaxfqFE65CDtCU9KBpaQLZQCHx7G1vuibP6nVw2vD9Z2Bz2DsH43bDZGXjmcvx2TD9wq3CmmFcoT96RCiDd1wMSUB2UH7Gu"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcEncvVc1zrPFZSKe7iAP1LTRhzxuXpmztu1kTtnfj8XNFzzmGH1X1gcGxczBZ3MmYKkxXgZKJCsNXXdasNaQJKJE4KcUjn1L"}}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_9_3_seeded(self): - wallet_str = '{"addr_history":{"12ECgkzK6gHouKAZ7QiooYBuk1CgJLJxes":[],"12iR43FPb5M7sw4Mcrr5y1nHKepg9EtZP1":[],"13HT1pfWctsSXVFzF76uYuVdQvcAQ2MAgB":[],"13kG9WH9JqS7hyCcVL1ssLdNv4aXocQY9c":[],"14Tf3qiiHJXStSU4KmienAhHfHq7FHpBpz":[],"14gmBxYV97mzYwWdJSJ3MTLbTHVegaKrcA":[],"15FGuHvRssu1r8fCw98vrbpfc3M4xs5FAV":[],"17oJzweA2gn6SDjsKgA9vUD5ocT1sSnr2Z":[],"18hNcSjZzRcRP6J2bfFRxp9UfpMoC4hGTv":[],"18n9PFxBjmKCGhd4PCDEEqYsi2CsnEfn2B":[],"19a98ZfEezDNbCwidVigV5PAJwrR2kw4Jz":[],"19z3j2ELqbg2pR87byCCt3BCyKR7rc3q8G":[],"1A3XSmvLQvePmvm7yctsGkBMX9ZKKXLrVq":[],"1CmhFe2BN1h9jheFpJf4v39XNPj8F9U6d":[],"1DuphhHUayKzbkdvjVjf5dtjn2ACkz4zEs":[],"1E4ygSNJpWL2uPXZHBptmU2LqwZTqb1Ado":[],"1GTDSjkVc9vaaBBBGNVqTANHJBcoT5VW9z":[],"1GWqgpThAuSq3tDg6uCoLQxPXQNnU8jZ52":[],"1GhmpwqSF5cqNgdr9oJMZx8dKxPRo4pYPP":[],"1J5TTUQKhwehEACw6Jjte1E22FVrbeDmpv":[],"1JWySzjzJhsETUUcqVZHuvQLA7pfFfmesb":[],"1KQHxcy3QUHAWMHKUtJjqD9cMKXcY2RTwZ":[],"1KoxZfc2KsgovjGDxwqanbFEA76uxgYH4G":[],"1KqVEPXdpbYvEbwsZcEKkrA4A2jsgj9hYN":[],"1N16yDSYe76c5A3CoVoWAKxHeAUc8Jhf9J":[],"1Pm8JBhzUJDqeQQKrmnop1Frr4phe1jbTt":[]},"addresses":{"change":["1GhmpwqSF5cqNgdr9oJMZx8dKxPRo4pYPP","1GTDSjkVc9vaaBBBGNVqTANHJBcoT5VW9z","15FGuHvRssu1r8fCw98vrbpfc3M4xs5FAV","1A3XSmvLQvePmvm7yctsGkBMX9ZKKXLrVq","19z3j2ELqbg2pR87byCCt3BCyKR7rc3q8G","1JWySzjzJhsETUUcqVZHuvQLA7pfFfmesb"],"receiving":["14gmBxYV97mzYwWdJSJ3MTLbTHVegaKrcA","13HT1pfWctsSXVFzF76uYuVdQvcAQ2MAgB","19a98ZfEezDNbCwidVigV5PAJwrR2kw4Jz","1J5TTUQKhwehEACw6Jjte1E22FVrbeDmpv","1Pm8JBhzUJDqeQQKrmnop1Frr4phe1jbTt","13kG9WH9JqS7hyCcVL1ssLdNv4aXocQY9c","1KQHxcy3QUHAWMHKUtJjqD9cMKXcY2RTwZ","12ECgkzK6gHouKAZ7QiooYBuk1CgJLJxes","12iR43FPb5M7sw4Mcrr5y1nHKepg9EtZP1","14Tf3qiiHJXStSU4KmienAhHfHq7FHpBpz","1KqVEPXdpbYvEbwsZcEKkrA4A2jsgj9hYN","17oJzweA2gn6SDjsKgA9vUD5ocT1sSnr2Z","1E4ygSNJpWL2uPXZHBptmU2LqwZTqb1Ado","18hNcSjZzRcRP6J2bfFRxp9UfpMoC4hGTv","1KoxZfc2KsgovjGDxwqanbFEA76uxgYH4G","18n9PFxBjmKCGhd4PCDEEqYsi2CsnEfn2B","1CmhFe2BN1h9jheFpJf4v39XNPj8F9U6d","1DuphhHUayKzbkdvjVjf5dtjn2ACkz4zEs","1GWqgpThAuSq3tDg6uCoLQxPXQNnU8jZ52","1N16yDSYe76c5A3CoVoWAKxHeAUc8Jhf9J"]},"keystore":{"seed":"cereal wise two govern top pet frog nut rule sketch bundle logic","type":"bip32","xprv":"xprv9s21ZrQH143K29XjRjUs6MnDB9wXjXbJP2kG1fnRk8zjdDYWqVkQYUqaDtgZp5zPSrH5PZQJs8sU25HrUgT1WdgsPU8GbifKurtMYg37d4v","xpub":"xpub661MyMwAqRbcEdcCXm1sTViwjBn28zK9kFfrp4C3JUXiW1sfP34f6HA45B9yr7EH5XGzWuTfMTdqpt9XPrVQVUdgiYb5NW9m8ij1FSZgGBF"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[619,310,840,405]}' + wallet_str = '{"addr_history":{"LLT9wyJ9BLXsA7riHYi75ZFfxDZxS32oAG":[],"LLwNKFZDfjbB8jkWnzqPF2r3XsBxHu3mHF":[],"LMWQH2yLhZ7VnHx9RF6CpvZPd8ySV5Lanh":[],"LMyDQiayPVgAxmtmfU1B9Mh98GwozAPdCj":[],"LNgcK42YMxmW9FADVuhx4Bm3sWCPTPydxX":[],"LNuiTArKDn23okCnUaHLdUQMfVrvjvjMnU":[],"LPUEAWEFxY956wMN7H8E8ctRpFiM528kSn":[],"LS2GG9wz7M29h2S2Vp9TCVGr1ppHuMvQeL":[],"LSvKsf3Q55rUdtzBmoEjEqDEt2j5NEo9CF":[],"LT16eUG1pRZFXWKDZLCXWrcdvEa9vWyQz8":[],"LTo6Pmy4jeTRr1dsodhym6SvXADh7b69Av":[],"LUCzzEYAvFv65DpGn7BWA4EyBXnQ5evfQJ":[],"LUGUhzEAVatT2jTH9ktAYmF7jMvbPaECbC":[],"LKRixTwrG2FkQYPoRxHxLw6ujam1EHbQAf":[],"LY8mxubJfda3rZL5udixMexVzEXUsqGaNP":[],"LYHvweg8uAa6ACDiTKpC3V6749vk1g26k1":[],"LagAhx4KgpAdpysLSWV8jBS3WPz5YsDTXU":[],"Lajnx2mXFZgtJguqH3C6cS29jck4ago9vq":[],"Lavj6A9GKjrtdVL1KwHeqyCPYAkhyZoFVE":[],"LcJQigi9nbtkUxu6GSjBv2HnETs8jtLNPR":[],"LcjviD3pPN7HiHAn1dYbBwU6NLBwJJrSXZ":[],"LddFDqGsV8XDm9yUf2J37EDNZXtth3N4UF":[],"Le2upsurQXvsBXxP95pt4cJzNKUC6NQTuK":[],"Le4SVbqTuFnyVQe2jkDd2sDpNF79ngHorT":[],"LgE4ERkNimLfKxjMydnoSM23rNqtG5pPYc":[],"Lhz5ZQ1pYxTtuD6V2un762Kd4HByp4QwXB":[]},"addresses":{"change":["Lavj6A9GKjrtdVL1KwHeqyCPYAkhyZoFVE","LagAhx4KgpAdpysLSWV8jBS3WPz5YsDTXU","LPUEAWEFxY956wMN7H8E8ctRpFiM528kSn","LUGUhzEAVatT2jTH9ktAYmF7jMvbPaECbC","LUCzzEYAvFv65DpGn7BWA4EyBXnQ5evfQJ","LcjviD3pPN7HiHAn1dYbBwU6NLBwJJrSXZ"],"receiving":["LNuiTArKDn23okCnUaHLdUQMfVrvjvjMnU","LMWQH2yLhZ7VnHx9RF6CpvZPd8ySV5Lanh","LTo6Pmy4jeTRr1dsodhym6SvXADh7b69Av","LcJQigi9nbtkUxu6GSjBv2HnETs8jtLNPR","Lhz5ZQ1pYxTtuD6V2un762Kd4HByp4QwXB","LMyDQiayPVgAxmtmfU1B9Mh98GwozAPdCj","LddFDqGsV8XDm9yUf2J37EDNZXtth3N4UF","LLT9wyJ9BLXsA7riHYi75ZFfxDZxS32oAG","LLwNKFZDfjbB8jkWnzqPF2r3XsBxHu3mHF","LNgcK42YMxmW9FADVuhx4Bm3sWCPTPydxX","Le4SVbqTuFnyVQe2jkDd2sDpNF79ngHorT","LS2GG9wz7M29h2S2Vp9TCVGr1ppHuMvQeL","LYHvweg8uAa6ACDiTKpC3V6749vk1g26k1","LSvKsf3Q55rUdtzBmoEjEqDEt2j5NEo9CF","Le2upsurQXvsBXxP95pt4cJzNKUC6NQTuK","LT16eUG1pRZFXWKDZLCXWrcdvEa9vWyQz8","LKRixTwrG2FkQYPoRxHxLw6ujam1EHbQAf","LY8mxubJfda3rZL5udixMexVzEXUsqGaNP","Lajnx2mXFZgtJguqH3C6cS29jck4ago9vq","LgE4ERkNimLfKxjMydnoSM23rNqtG5pPYc"]},"keystore":{"seed":"cereal wise two govern top pet frog nut rule sketch bundle logic","type":"bip32","xprv":"xprv9s21ZrQH143K29XjRjUs6MnDB9wXjXbJP2kG1fnRk8zjdDYWqVkQYUqaDtgZp5zPSrH5PZQJs8sU25HrUgT1WdgsPU8GbifKurtMYg37d4v","xpub":"xpub661MyMwAqRbcEdcCXm1sTViwjBn28zK9kFfrp4C3JUXiW1sfP34f6HA45B9yr7EH5XGzWuTfMTdqpt9XPrVQVUdgiYb5NW9m8ij1FSZgGBF"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[619,310,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_9_3_importedkeys(self): - wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' + wallet_str = '{"addr_history":{"LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY":[],"LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM":[],"LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb":[]},"addresses":{"change":[],"receiving":["LMK1a5LKLkLFCEKukwwTrGxPboNvZjDbcY","LZBc9EVXNXW1aGdrxodATNp9kYeCxufeWb","LPRvUteVjy7MwDYro7o6XJ8SzhaYBJQhoM"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"T8hVerMmMsVnq7mkXpEw4krEhXJ5BZNVv7mb4C7LoV8Ni8iywME1","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"T96yXyhXKvujT4sMAPihoJJ2sXNTwDircc7WnT2qqXTdBs433uZ5","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"6vHESf1YF8tPdqpGyEiNvibJPRZzKsB4ijYsywkUaz3SfUAnidY"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_9_3_watchaddresses(self): - wallet_str = '{"addr_history":{"1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf":[],"1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs":[],"1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa":[]},"addresses":["1H3mPXHFzA8UbvhQVabcDjYw3CPb3djvxs","1HocPduHmQUJerpdaLG8DnmxvnDCVQwWsa","1DgrwN2JCDZ6uPMSvSz8dPeUtaxLxWM2kf"],"pruned_txo":{},"seed_version":13,"stored_height":490039,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[499,386,840,405]}' + wallet_str = '{"addr_history":{"LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2":[],"LbGiejb64pNXrjPZfiauVkchFQksBnFjrz":[],"Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy":[]},"addresses":["LbGiejb64pNXrjPZfiauVkchFQksBnFjrz","Lc2ZerD7r4iMufWnkUFRVoqj8zaUdra9gy","LXupCaL8GsoAAC3c6ayRuQiF6oKd6jzvF2"],"pruned_txo":{},"seed_version":13,"stored_height":490039,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"verified_tx3":{},"wallet_type":"imported","winpos-qt":[499,386,840,405]}' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_9_3_trezor_singleacc(self): - wallet_str = '''{"addr_history":{"12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC":[],"146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz":[],"14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM":[],"15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ":[],"15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6":[],"15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S":[],"17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH":[],"18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw":[],"1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb":[],"1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX":[],"1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ":[],"1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp":[],"1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk":[],"1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD":[],"1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp":[],"1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz":[],"1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs":[],"1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid":[],"1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu":[],"1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo":[],"1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj":[],"1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv":[],"1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC":[],"1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe":[],"1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL":[],"1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG":[]},"addresses":{"change":["1ES8hmtgXFLRex71CZHu85cLFRYDczeTZ","14Co2CRVu67XLCGrD4RVVpadtoXcodUUWM","1rDkHFozR7kC7MxRiakx3mBeU1Fu6BRbG","15sFkiVrGad5QiKgtYjfgi8SSeEfRzxed6","1NZs4y3cJhukVdKSYDhaiMHhP4ZU2qVpAL","1KotB3FVFcYuHAVdRNAe2ZN1MREpVWnBgs"],"receiving":["1LpV3F25jiNWV8N2RPP1cnKGgpjZh2r8xu","18TKpsznSha4VHLzpVatnrEBdtWkoQSyGw","17YQXYHoDqcpd7GvWN9BYK8FnDryhYbKyH","12sQvVXgdoy2QDorLgr2t6J8JVzygBGueC","15KDqFhdXP6Zn4XtJVVVgahJ7chw9jGhvQ","1Le4rXQD4kMGsoet4EH8VGzt5VZjdHBpid","1KnQX5D5Tv2u5CyWpuXaeM8CvuuVAmfwRz","1MrA1WS4iWcTjLrnSqNNpXzSq5W92Bttbj","146j6RMbWpKYEaGTdWVza3if3bnCD9Maiz","1NMkEhuUYsxTCkfq9zxxCTozKNNqjHeKeC","1Mdq8bVFSBfaeH5vjaXGjiPiy6qPVtdfUo","1BngGArwhpzWjCREXYRS1uhUGszCTe7vqb","1NTRF8Y7Mu57dQ9TFwUA98EdmzbAamtLYe","1NFhYYBh1zDGdnqD1Avo9gaVV8LvnAH6iv","1J2NdSfFiQLhkHs2DVyBmB47Mk65rfrGPp","15zoPN5rVKDCsKnZUkTYJWFv4gLdYTat8S","1E9wSjSWkFJp3HUaUzUF9eWpCkUZnsNCuX","1FdV7zK6RdRAKqg3ccGHGK51nJLUwpuBFp","1GjFaGxzqK12N2F7Ao49k7ZvMApCmK7Enk","1HkHDREiY3m9UCxaSAZEn1troa3eHWaiQD"]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"seed_version":13,"stored_height":490014,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[753,486,840,405]}''' + wallet_str = '''{"addr_history":{"LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf":[],"LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT":[],"LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK":[],"LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX":[],"LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN":[],"LQDkeaPgZyTG88UietSqaXKgGthudu92c8":[],"LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC":[],"LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ":[],"LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi":[],"LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P":[],"LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV":[],"LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo":[],"LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ":[],"LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw":[],"LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN":[],"Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG":[],"Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG":[],"Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf":[],"Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4":[],"LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4":[],"Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr":[],"LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE":[],"LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R":[],"LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ":[],"LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom":[],"LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o":[]},"addresses":{"change":["LKTPPv5imBVPgTeGBLYbB99NYTnpPpF5wV","LNRkHQjKykMaazy1PCQnmqeQ71ttwUuuQK","LL5B1VZe55MoSv47bra4E4pwrgNY1zHv1o","LQ6D1vogMEs8fX1r4gixxjCCerbwTX3srN","LgnpLBMSPN9okS1biMgszNMTbGvkCxAxom","Le2qSFZKLGnxXyBnbW9wJaRmZdc6bfBmDG"],"receiving":["Lf3SJTKupNcZjw4BbXNJtoP2u36qoUPFJ4","LSgH66JcXMp7k639zdaC4sHwr6t2yTKAwQ","LRmMnkbdJVrssuy5gW8UpLC1zSEFp7omPC","LM6NBhqWiUD5f2W1WpqLA7MtWiNFjW5Gpf","LPYB6U1Tc3Ld2sE3UdUnxbm4Kq5DDkPCEX","Les27ji39QbL8cM3ENGRmJ4eHhw1nkrHLf","Le1MnHWuYaGxL1fg13WsvNBy98GmHpurMG","Lg57GijtoArWz9YwcyMg6Z4D3HsR6N1tGr","LNKgMdfRbUZbVNxcoeVHr4nRFp9ULZX4bT","LgahVvDJdYCWTZMzL8xFUUskXak7rKY76R","LfrnPoo5Wqudu5n5uiWa1jTVBKCfbNbeG4","LW1dXPAmnVEZz17PhgQjHvmEV6MUcd6Zhi","LggNWLqwSZKAtCqcS5TTR9JPzCxSgoznXZ","LgUeokVX6eTKtbXNBJv6RheFhLiCzwSPaE","LcFKtey5o4am16ZBPdxV3C7sZxTMyRqyoN","LQDkeaPgZyTG88UietSqaXKgGthudu92c8","LYNthwkLpuYsJ6Ajf8TYRfaaQxqqtYWC1P","LZrSPCcvWHfDaeNCnkFaYL8mzWhm89qZxo","LaxCqVGpuyF5cpwGLw3T28dgZPBUoRcMSZ","LbyEUdYYci1Cj1ejcJYY42xd1nQvM6eiXw"]},"keystore":{"derivation":"m/44'/0'/0'","hw_type":"trezor","label":"trezor1","type":"hardware","xpub":"xpub6BycoSLDNcWjBQMuYgSaEoinupMjma8Cu2uj4XiRCZkecLHXXmzcxbyR1gdfrZpiZDVSs92MEGGNhF78BEbbYi2b5U2oPnaUPRhjriWz85y"},"pruned_txo":{},"seed_version":13,"stored_height":490014,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[753,486,840,405]}''' self._upgrade_storage(wallet_str) def test_upgrade_from_client_2_9_3_multisig(self): - wallet_str = '{"addr_history":{"31uiqKhw4PQSmZWnCkqpeh6moB8B1jXEt3":[],"32PBjkXmwRoEQt8HBZcAEUbNwaHw5dR5fe":[],"33FQMD675LMRLZDLYLK7QV6TMYA1uYW1sw":[],"33MQEs6TCgxmAJhZvUEXYr6gCkEoEYzUfm":[],"33vuhs2Wor9Xkax66ucDkscPcU6nQHw8LA":[],"35tbMt1qBGmy5RNcsdGZJgs7XVbf5gEgPs":[],"36zhHEtGA33NjHJdxCMjY6DLeU2qxhiLUE":[],"37rZuTsieKVpRXshwrY8qvFBn6me42mYr5":[],"38A2KDXYRmRKZRRCGgazrj19i22kDr8d4V":[],"38GZH5GhxLKi5so9Aka6orY2EDZkvaXdxm":[],"3AEtxrCwiYv5Y5CRmHn1c5nZnV3Hpfh5BM":[],"3AaHWprY1MytygvQVDLp6i63e9o5CwMSN5":[],"3DAD19hHXNxAfZjCtUbWjZVxw1fxQqCbY7":[],"3GK4CBbgwumoeR9wxJjr1QnfnYhGUEzHhN":[],"3H18xmkyX3XAb5MwucqKpEhTnh3qz8V4Mn":[],"3JhkakvHAyFvukJ3cyaVgiyaqjYNo2gmsS":[],"3JtA4x1AKW4BR5YAEeLR5D157Nd92NHArC":[],"3KQosfGFGsUniyqsidE2Y4Bz1y4iZUkGW6":[],"3KXe1z2Lfk22zL6ggQJLpHZfc9dKxYV95p":[],"3KZiENj4VHdUycv9UDts4ojVRsaMk8LC5c":[],"3KeTKHJbkZN1QVkvKnHRqYDYP7UXsUu6va":[],"3L5aZKtDKSd65wPLMRooNtWHkKd5Mz6E3i":[],"3LAPqjqW4C2Se9HNziUhNaJQS46X1r9p3M":[],"3P3JJPoyNFussuyxkDbnYevYim5XnPGmwZ":[],"3PgNdMYSaPRymskby885DgKoTeA1uZr6Gi":[],"3Pm7DaUzaDMxy2mW5WzHp1sE9hVWEpdf7J":[]},"addresses":{"change":["31uiqKhw4PQSmZWnCkqpeh6moB8B1jXEt3","3JhkakvHAyFvukJ3cyaVgiyaqjYNo2gmsS","3GK4CBbgwumoeR9wxJjr1QnfnYhGUEzHhN","3LAPqjqW4C2Se9HNziUhNaJQS46X1r9p3M","33MQEs6TCgxmAJhZvUEXYr6gCkEoEYzUfm","3AEtxrCwiYv5Y5CRmHn1c5nZnV3Hpfh5BM"],"receiving":["3P3JJPoyNFussuyxkDbnYevYim5XnPGmwZ","33FQMD675LMRLZDLYLK7QV6TMYA1uYW1sw","3DAD19hHXNxAfZjCtUbWjZVxw1fxQqCbY7","3AaHWprY1MytygvQVDLp6i63e9o5CwMSN5","3H18xmkyX3XAb5MwucqKpEhTnh3qz8V4Mn","36zhHEtGA33NjHJdxCMjY6DLeU2qxhiLUE","37rZuTsieKVpRXshwrY8qvFBn6me42mYr5","38A2KDXYRmRKZRRCGgazrj19i22kDr8d4V","38GZH5GhxLKi5so9Aka6orY2EDZkvaXdxm","33vuhs2Wor9Xkax66ucDkscPcU6nQHw8LA","3L5aZKtDKSd65wPLMRooNtWHkKd5Mz6E3i","3KXe1z2Lfk22zL6ggQJLpHZfc9dKxYV95p","3KQosfGFGsUniyqsidE2Y4Bz1y4iZUkGW6","3KZiENj4VHdUycv9UDts4ojVRsaMk8LC5c","32PBjkXmwRoEQt8HBZcAEUbNwaHw5dR5fe","3KeTKHJbkZN1QVkvKnHRqYDYP7UXsUu6va","3JtA4x1AKW4BR5YAEeLR5D157Nd92NHArC","3PgNdMYSaPRymskby885DgKoTeA1uZr6Gi","3Pm7DaUzaDMxy2mW5WzHp1sE9hVWEpdf7J","35tbMt1qBGmy5RNcsdGZJgs7XVbf5gEgPs"]},"pruned_txo":{},"seed_version":13,"stored_height":485855,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[617,227,840,405],"x1/":{"seed":"speed cruise market wasp ability alarm hold essay grass coconut tissue recipe","type":"bip32","xprv":"xprv9s21ZrQH143K48ig2wcAuZoEKaYdNRaShKFR3hLrgwsNW13QYRhXH6gAG1khxim6dw2RtAzF8RWbQxr1vvWUJFfEu2SJZhYbv6pfreMpuLB","xpub":"xpub661MyMwAqRbcGco98y9BGhjxscP7mtJJ4YB1r5kUFHQMNoNZ5y1mptze7J37JypkbrmBdnqTvSNzxL7cE1FrHg16qoj9S12MUpiYxVbTKQV"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcGrCDZaVs9VC7Z6579tsGvpqyDYZEHKg2MXoDkxhrWoukqvwDPXKdxVkYA6Hv9XHLETptfZfNpcJZmsUThdXXkTNGoBjQv1o"}}' + wallet_str = '{"addr_history":{"M87s9D7u1WFsa4ngJdqAULMB7siczAwtwt":[],"M8bL3dwjtYefDPQBHSbW47qnGGtP5WWniV":[],"M9TYf6W52TCr94VEeDJTE8LrgEkTvsookV":[],"M9ZYYkWR9opBxoyU2MDsNVM5XSqFAGCXQF":[],"MA941kSUkxzxZ6DzCnbZaWrnwAhERS4KY3":[],"MC6jfmRo8PdPsveWyWFu8L7WrCC75u7dvM":[],"MDCqb8JE79toXnaY45M5MjTjyAdHzLrGgQ":[],"ME4iDMHgbSMFE39c3jXUfZVb6oN5zsbSsf":[],"MENAd6wWNtGkMvh6NZaLgNFZ2idCGJMSH1":[],"MEUhaxgfuTB8tP53GdZSdVnRYvACvy8HoN":[],"MGT3GjcuffmWLaUKsAmMRj2y7BdjrqcB4f":[],"MGnRpiGVxUqKnCCJb6L9vMLSxrPXDTqz4C":[],"MKNMK37FUVobU516zMarZCkNFiGQNAr5p9":[],"MNXCW51eu2dESvRr4BjBq4357FHiTECShe":[],"MPDHGfAwUANbPadr1Vpfdsws7PeHvbie9r":[],"MQutteLF867MiFZwirZqWNDzAS8ppWXSSC":[],"MR6JNqR8GcucDap4LXKktrFUS5DayikmLX":[],"MRcxBYgDDzLDXV7mpWDNMhSPLffAYWSep2":[],"MRjnKsSJcrsTnqNanHHgdvp4vrDmzPsUtV":[],"MRmrYG92SQUun8C3a6tCtSytkaAohBRyz7":[],"MRrbdAiZhgDSD12pRfGmfBTwhp4yt4dkyy":[],"MSHisDJBGZUWtSfETJo9CXkh52DXLd8DDP":[],"MSNY9dFU1JssSeZH6bU3CDYokkgy1bMyre":[],"MVFScHDwKNmJgRFrr6b8NJAx3Tfyj1N5Ya":[],"MVtWwExQXWHQaP2W517R3KaCnLkTzUuKfs":[],"MVyFXTtxXLDPmY3QBPyddf7dUQ5xC5AiCh":[]},"addresses":{"change":["M87s9D7u1WFsa4ngJdqAULMB7siczAwtwt","MQutteLF867MiFZwirZqWNDzAS8ppWXSSC","MNXCW51eu2dESvRr4BjBq4357FHiTECShe","MSNY9dFU1JssSeZH6bU3CDYokkgy1bMyre","M9ZYYkWR9opBxoyU2MDsNVM5XSqFAGCXQF","MGT3GjcuffmWLaUKsAmMRj2y7BdjrqcB4f"],"receiving":["MVFScHDwKNmJgRFrr6b8NJAx3Tfyj1N5Ya","M9TYf6W52TCr94VEeDJTE8LrgEkTvsookV","MKNMK37FUVobU516zMarZCkNFiGQNAr5p9","MGnRpiGVxUqKnCCJb6L9vMLSxrPXDTqz4C","MPDHGfAwUANbPadr1Vpfdsws7PeHvbie9r","MDCqb8JE79toXnaY45M5MjTjyAdHzLrGgQ","ME4iDMHgbSMFE39c3jXUfZVb6oN5zsbSsf","MENAd6wWNtGkMvh6NZaLgNFZ2idCGJMSH1","MEUhaxgfuTB8tP53GdZSdVnRYvACvy8HoN","MA941kSUkxzxZ6DzCnbZaWrnwAhERS4KY3","MSHisDJBGZUWtSfETJo9CXkh52DXLd8DDP","MRjnKsSJcrsTnqNanHHgdvp4vrDmzPsUtV","MRcxBYgDDzLDXV7mpWDNMhSPLffAYWSep2","MRmrYG92SQUun8C3a6tCtSytkaAohBRyz7","M8bL3dwjtYefDPQBHSbW47qnGGtP5WWniV","MRrbdAiZhgDSD12pRfGmfBTwhp4yt4dkyy","MR6JNqR8GcucDap4LXKktrFUS5DayikmLX","MVtWwExQXWHQaP2W517R3KaCnLkTzUuKfs","MVyFXTtxXLDPmY3QBPyddf7dUQ5xC5AiCh","MC6jfmRo8PdPsveWyWFu8L7WrCC75u7dvM"]},"pruned_txo":{},"seed_version":13,"stored_height":485855,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"2of2","winpos-qt":[617,227,840,405],"x1/":{"seed":"speed cruise market wasp ability alarm hold essay grass coconut tissue recipe","type":"bip32","xprv":"xprv9s21ZrQH143K48ig2wcAuZoEKaYdNRaShKFR3hLrgwsNW13QYRhXH6gAG1khxim6dw2RtAzF8RWbQxr1vvWUJFfEu2SJZhYbv6pfreMpuLB","xpub":"xpub661MyMwAqRbcGco98y9BGhjxscP7mtJJ4YB1r5kUFHQMNoNZ5y1mptze7J37JypkbrmBdnqTvSNzxL7cE1FrHg16qoj9S12MUpiYxVbTKQV"},"x2/":{"type":"bip32","xprv":null,"xpub":"xpub661MyMwAqRbcGrCDZaVs9VC7Z6579tsGvpqyDYZEHKg2MXoDkxhrWoukqvwDPXKdxVkYA6Hv9XHLETptfZfNpcJZmsUThdXXkTNGoBjQv1o"}}' self._upgrade_storage(wallet_str) ########## diff --git a/lib/tests/test_transaction.py b/lib/tests/test_transaction.py index cc800454c8c5..99d1818e9ff9 100644 --- a/lib/tests/test_transaction.py +++ b/lib/tests/test_transaction.py @@ -58,7 +58,7 @@ def test_tx_unsigned(self): expected = { 'inputs': [{ 'type': 'p2pkh', - 'address': '1446oU3z268EeFgfcwJv6X2VBXHfoYxfuD', + 'address': 'LNH44gMp6kNHu4Npo5JDNY6FPjewvMKDnz', 'num_sig': 1, 'prevout_hash': '3140eb24b43386f35ba69e3875eb6c93130ac66201d01c58f598defc949a5c2a', 'prevout_n': 0, @@ -69,7 +69,7 @@ def test_tx_unsigned(self): 'x_pubkeys': ['ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000']}], 'lockTime': 0, 'outputs': [{ - 'address': '14CHYaaByjJZpx4oHBpfDMdqhTyXnZ3kVs', + 'address': 'LNREont24PYd5kkxTKoxVNhbugLowNb7H8', 'prevout_n': 0, 'scriptPubKey': '76a914230ac37834073a42146f11ef8414ae929feaafc388ac', 'type': TYPE_ADDRESS, @@ -81,12 +81,12 @@ def test_tx_unsigned(self): self.assertEqual(tx.deserialize(), None) self.assertEqual(tx.as_dict(), {'hex': unsigned_blob, 'complete': False, 'final': True}) - self.assertEqual(tx.get_outputs(), [('14CHYaaByjJZpx4oHBpfDMdqhTyXnZ3kVs', 1000000)]) - self.assertEqual(tx.get_output_addresses(), ['14CHYaaByjJZpx4oHBpfDMdqhTyXnZ3kVs']) + self.assertEqual(tx.get_outputs(), [('LNREont24PYd5kkxTKoxVNhbugLowNb7H8', 1000000)]) + self.assertEqual(tx.get_output_addresses(), ['LNREont24PYd5kkxTKoxVNhbugLowNb7H8']) - self.assertTrue(tx.has_address('14CHYaaByjJZpx4oHBpfDMdqhTyXnZ3kVs')) - self.assertTrue(tx.has_address('1446oU3z268EeFgfcwJv6X2VBXHfoYxfuD')) - self.assertFalse(tx.has_address('1CQj15y1N7LDHp7wTt28eoD1QhHgFgxECH')) + self.assertTrue(tx.has_address('LNREont24PYd5kkxTKoxVNhbugLowNb7H8')) + self.assertTrue(tx.has_address('LNH44gMp6kNHu4Npo5JDNY6FPjewvMKDnz')) + self.assertFalse(tx.has_address('LWdgGJGqSmaGYcp6e21RvpGmcuexJorNEH')) self.assertEqual(tx.serialize(), unsigned_blob) @@ -102,7 +102,7 @@ def test_tx_signed(self): expected = { 'inputs': [{ 'type': 'p2pkh', - 'address': '1446oU3z268EeFgfcwJv6X2VBXHfoYxfuD', + 'address': 'LNH44gMp6kNHu4Npo5JDNY6FPjewvMKDnz', 'num_sig': 1, 'prevout_hash': '3140eb24b43386f35ba69e3875eb6c93130ac66201d01c58f598defc949a5c2a', 'prevout_n': 0, @@ -113,7 +113,7 @@ def test_tx_signed(self): 'x_pubkeys': ['02e61d176da16edd1d258a200ad9759ef63adf8e14cd97f53227bae35cdb84d2f6']}], 'lockTime': 0, 'outputs': [{ - 'address': '14CHYaaByjJZpx4oHBpfDMdqhTyXnZ3kVs', + 'address': 'LNREont24PYd5kkxTKoxVNhbugLowNb7H8', 'prevout_n': 0, 'scriptPubKey': '76a914230ac37834073a42146f11ef8414ae929feaafc388ac', 'type': TYPE_ADDRESS, @@ -137,10 +137,10 @@ def test_tx_signed(self): def test_estimated_output_size(self): estimated_output_size = transaction.Transaction.estimated_output_size - self.assertEqual(estimated_output_size('14gcRovpkCoGkCNBivQBvw7eso7eiNAbxG'), 34) - self.assertEqual(estimated_output_size('35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT'), 32) - self.assertEqual(estimated_output_size('bc1q3g5tmkmlvxryhh843v4dz026avatc0zzr6h3af'), 31) - self.assertEqual(estimated_output_size('bc1qnvks7gfdu72de8qv6q6rhkkzu70fqz4wpjzuxjf6aydsx7wxfwcqnlxuv3'), 43) + self.assertEqual(estimated_output_size('LNuZh2Eeps3L114Lu4PVCxBR61UvrUKgze'), 34) + self.assertEqual(estimated_output_size('MBmyiC29MUQSfPC2gKtdrazbSWHvGqJCnU'), 32) + self.assertEqual(estimated_output_size('xzc1q3g5tmkmlvxryhh843v4dz026avatc0zz8xd49e'), 31) + self.assertEqual(estimated_output_size('xzc1qnvks7gfdu72de8qv6q6rhkkzu70fqz4wpjzuxjf6aydsx7wxfwcqsmgvk5'), 43) # TODO other tests for segwit tx def test_tx_signed_segwit(self): @@ -161,7 +161,7 @@ def test_errors(self): def test_parse_xpub(self): res = xpubkey_to_address('fe4e13b0f311a55b8a5db9a32e959da9f011b131019d4cebe6141b9e2c93edcbfc0954c358b062a9f94111548e50bde5847a3096b8b7872dcffadb0e9579b9017b01000200') - self.assertEqual(res, ('04ee98d63800824486a1cf5b4376f2f574d86e0a3009a6448105703453f3368e8e1d8d090aaecdd626a45cc49876709a3bbb6dc96a4311b3cac03e225df5f63dfc', '19h943e4diLc68GXW7G75QNe2KWuMu7BaJ')) + self.assertEqual(res, ('04ee98d63800824486a1cf5b4376f2f574d86e0a3009a6448105703453f3368e8e1d8d090aaecdd626a45cc49876709a3bbb6dc96a4311b3cac03e225df5f63dfc', 'LTv6KFwtiNafLvxggFFQMRSQEXtBUru9eG')) def test_version_field(self): tx = transaction.Transaction(v2_blob) @@ -235,385 +235,6 @@ def test_txid_input_p2wsh_p2sh_not_multisig(self): tx = transaction.Transaction('0100000000010160f84fdcda039c3ca1b20038adea2d49a53db92f7c467e8def13734232bb610804000000232200202814720f16329ab81cb8867c4d447bd13255931f23e6655944c9ada1797fcf88ffffffff0ba3dcfc04000000001976a91488124a57c548c9e7b1dd687455af803bd5765dea88acc9f44900000000001976a914da55045a0ccd40a56ce861946d13eb861eb5f2d788ac49825e000000000017a914ca34d4b190e36479aa6e0023cfe0a8537c6aa8dd87680c0d00000000001976a914651102524c424b2e7c44787c4f21e4c54dffafc088acf02fa9000000000017a914ee6c596e6f7066466d778d4f9ba633a564a6e95d874d250900000000001976a9146ca7976b48c04fd23867748382ee8401b1d27c2988acf5119600000000001976a914cf47d5dcdba02fd547c600697097252d38c3214a88ace08a12000000000017a914017bef79d92d5ec08c051786bad317e5dd3befcf87e3d76201000000001976a9148ec1b88b66d142bcbdb42797a0fd402c23e0eec288ac718f6900000000001976a914e66344472a224ce6f843f2989accf435ae6a808988ac65e51300000000001976a914cad6717c13a2079066f876933834210ebbe68c3f88ac0347304402201a4907c4706104320313e182ecbb1b265b2d023a79586671386de86bb47461590220472c3db9fc99a728ebb9b555a72e3481d20b181bd059a9c1acadfb853d90c96c01210338a46f2a54112fef8803c8478bc17e5f8fc6a5ec276903a946c1fafb2e3a8b181976a914eda8660085bf607b82bd18560ca8f3a9ec49178588ac00000000') self.assertEqual('e9933221a150f78f9f224899f8568ff6422ffcc28ca3d53d87936368ff7c4b1d', tx.txid()) - # input: p2sh, not multisig - def test_txid_regression_issue_3899(self): - tx = transaction.Transaction('0100000004328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c010000000b0009630330472d5fae685bffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c020000000b0009630359646d5fae6858ffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c030000000b000963034bd4715fae6854ffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c040000000b000963036de8705fae6860ffffffff0130750000000000001976a914b5abca61d20f9062fb1fdbb880d9d93bac36675188ac00000000') - self.assertEqual('f570d5d1e965ee61bcc7005f8fefb1d3abbed9d7ddbe035e2a68fa07e5fc4a0d', tx.txid()) - - -# these transactions are from Bitcoin Core unit tests ---> -# https://github.com/bitcoin/bitcoin/blob/11376b5583a283772c82f6d32d0007cdbf5b8ef0/src/test/data/tx_valid.json - - def test_txid_bitcoin_core_0001(self): - tx = transaction.Transaction('0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000') - self.assertEqual('23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63', tx.txid()) - - def test_txid_bitcoin_core_0002(self): - tx = transaction.Transaction('0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000') - self.assertEqual('fcabc409d8e685da28536e1e5ccc91264d755cd4c57ed4cae3dbaa4d3b93e8ed', tx.txid()) - - def test_txid_bitcoin_core_0003(self): - tx = transaction.Transaction('0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000') - self.assertEqual('c9aa95f2c48175fdb70b34c23f1c3fc44f869b073a6f79b1343fbce30c3cb575', tx.txid()) - - def test_txid_bitcoin_core_0004(self): - tx = transaction.Transaction('0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000') - self.assertEqual('da94fda32b55deb40c3ed92e135d69df7efc4ee6665e0beb07ef500f407c9fd2', tx.txid()) - - def test_txid_bitcoin_core_0005(self): - tx = transaction.Transaction('0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000') - self.assertEqual('f76f897b206e4f78d60fe40f2ccb542184cfadc34354d3bb9bdc30cc2f432b86', tx.txid()) - - def test_txid_bitcoin_core_0006(self): - tx = transaction.Transaction('01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000') - self.assertEqual('c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73', tx.txid()) - - def test_txid_bitcoin_core_0007(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000') - self.assertEqual('e41ffe19dff3cbedb413a2ca3fbbcd05cb7fd7397ffa65052f8928aa9c700092', tx.txid()) - - def test_txid_bitcoin_core_0008(self): - tx = transaction.Transaction('01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000') - self.assertEqual('f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb', tx.txid()) - - def test_txid_bitcoin_core_0009(self): - tx = transaction.Transaction('01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000') - self.assertEqual('b56471690c3ff4f7946174e51df68b47455a0d29344c351377d712e6d00eabe5', tx.txid()) - - def test_txid_bitcoin_core_0010(self): - tx = transaction.Transaction('010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000') - self.assertEqual('99517e5b47533453cc7daa332180f578be68b80370ecfe84dbfff7f19d791da4', tx.txid()) - - def test_txid_bitcoin_core_0011(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000') - self.assertEqual('ab097537b528871b9b64cb79a769ae13c3c3cd477cc9dddeebe657eabd7fdcea', tx.txid()) - - def test_txid_bitcoin_core_0012(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000') - self.assertEqual('4d163e00f1966e9a1eab8f9374c3e37f4deb4857c247270e25f7d79a999d2dc9', tx.txid()) - - def test_txid_bitcoin_core_0013(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000') - self.assertEqual('9fe2ef9dde70e15d78894a4800b7df3bbfb1addb9a6f7d7c204492fdb6ee6cc4', tx.txid()) - - def test_txid_bitcoin_core_0014(self): - tx = transaction.Transaction('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000') - self.assertEqual('99d3825137602e577aeaf6a2e3c9620fd0e605323dc5265da4a570593be791d4', tx.txid()) - - def test_txid_bitcoin_core_0015(self): - tx = transaction.Transaction('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000') - self.assertEqual('c0d67409923040cc766bbea12e4c9154393abef706db065ac2e07d91a9ba4f84', tx.txid()) - - def test_txid_bitcoin_core_0016(self): - tx = transaction.Transaction('010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000') - self.assertEqual('c610d85d3d5fdf5046be7f123db8a0890cee846ee58de8a44667cfd1ab6b8666', tx.txid()) - - def test_txid_bitcoin_core_0017(self): - tx = transaction.Transaction('01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000') - self.assertEqual('a647a7b3328d2c698bfa1ee2dd4e5e05a6cea972e764ccb9bd29ea43817ca64f', tx.txid()) - - def test_txid_bitcoin_core_0018(self): - tx = transaction.Transaction('010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000') - self.assertEqual('afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae', tx.txid()) - - def test_txid_bitcoin_core_0019(self): - tx = transaction.Transaction('01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000') - self.assertEqual('f4b05f978689c89000f729cae187dcfbe64c9819af67a4f05c0b4d59e717d64d', tx.txid()) - - def test_txid_bitcoin_core_0020(self): - tx = transaction.Transaction('0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000') - self.assertEqual('cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984', tx.txid()) - - def test_txid_bitcoin_core_0021(self): - tx = transaction.Transaction('01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000') - self.assertEqual('1edc7f214659d52c731e2016d258701911bd62a0422f72f6c87a1bc8dd3f8667', tx.txid()) - - def test_txid_bitcoin_core_0022(self): - tx = transaction.Transaction('0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000') - self.assertEqual('018adb7133fde63add9149a2161802a1bcf4bdf12c39334e880c073480eda2ff', tx.txid()) - - def test_txid_bitcoin_core_0023(self): - tx = transaction.Transaction('0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000') - self.assertEqual('1464caf48c708a6cc19a296944ded9bb7f719c9858986d2501cf35068b9ce5a2', tx.txid()) - - def test_txid_bitcoin_core_0024(self): - tx = transaction.Transaction('010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000') - self.assertEqual('1fb73fbfc947d52f5d80ba23b67c06a232ad83fdd49d1c0a657602f03fbe8f7a', tx.txid()) - - def test_txid_bitcoin_core_0025(self): - tx = transaction.Transaction('0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000') - self.assertEqual('24cecfce0fa880b09c9b4a66c5134499d1b09c01cc5728cd182638bea070e6ab', tx.txid()) - - def test_txid_bitcoin_core_0026(self): - tx = transaction.Transaction('0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000') - self.assertEqual('9eaa819e386d6a54256c9283da50c230f3d8cd5376d75c4dcc945afdeb157dd7', tx.txid()) - - def test_txid_bitcoin_core_0027(self): - tx = transaction.Transaction('01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000') - self.assertEqual('46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa', tx.txid()) - - def test_txid_bitcoin_core_0028(self): - tx = transaction.Transaction('01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000') - self.assertEqual('8d66836045db9f2d7b3a75212c5e6325f70603ee27c8333a3bce5bf670d9582e', tx.txid()) - - def test_txid_bitcoin_core_0029(self): - tx = transaction.Transaction('01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000') - self.assertEqual('aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8', tx.txid()) - - def test_txid_bitcoin_core_0030(self): - tx = transaction.Transaction('010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000') - self.assertEqual('6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190', tx.txid()) - - def test_txid_bitcoin_core_0031(self): - tx = transaction.Transaction('010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000') - self.assertEqual('892464645599cc3c2d165adcc612e5f982a200dfaa3e11e9ce1d228027f46880', tx.txid()) - - def test_txid_bitcoin_core_0032(self): - tx = transaction.Transaction('010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000') - self.assertEqual('578db8c6c404fec22c4a8afeaf32df0e7b767c4dda3478e0471575846419e8fc', tx.txid()) - - def test_txid_bitcoin_core_0033(self): - tx = transaction.Transaction('0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000') - self.assertEqual('974f5148a0946f9985e75a240bb24c573adbbdc25d61e7b016cdbb0a5355049f', tx.txid()) - - def test_txid_bitcoin_core_0034(self): - tx = transaction.Transaction('01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000') - self.assertEqual('b0097ec81df231893a212657bf5fe5a13b2bff8b28c0042aca6fc4159f79661b', tx.txid()) - - def test_txid_bitcoin_core_0035(self): - tx = transaction.Transaction('01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000') - self.assertEqual('feeba255656c80c14db595736c1c7955c8c0a497622ec96e3f2238fbdd43a7c9', tx.txid()) - - def test_txid_bitcoin_core_0036(self): - tx = transaction.Transaction('01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000') - self.assertEqual('a0c984fc820e57ddba97f8098fa640c8a7eb3fe2f583923da886b7660f505e1e', tx.txid()) - - def test_txid_bitcoin_core_0037(self): - tx = transaction.Transaction('0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000') - self.assertEqual('5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f', tx.txid()) - - def test_txid_bitcoin_core_0038(self): - tx = transaction.Transaction('0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000') - self.assertEqual('ded7ff51d89a4e1ec48162aee5a96447214d93dfb3837946af2301a28f65dbea', tx.txid()) - - def test_txid_bitcoin_core_0039(self): - tx = transaction.Transaction('010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000') - self.assertEqual('3444be2e216abe77b46015e481d8cc21abd4c20446aabf49cd78141c9b9db87e', tx.txid()) - - def test_txid_bitcoin_core_0040(self): - tx = transaction.Transaction('0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d') - self.assertEqual('abd62b4627d8d9b2d95fcfd8c87e37d2790637ce47d28018e3aece63c1d62649', tx.txid()) - - def test_txid_bitcoin_core_0041(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d') - self.assertEqual('58b6de8413603b7f556270bf48caedcf17772e7105f5419f6a80be0df0b470da', tx.txid()) - - def test_txid_bitcoin_core_0042(self): - tx = transaction.Transaction('0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff') - self.assertEqual('5f99c0abf511294d76cbe144d86b77238a03e086974bc7a8ea0bdb2c681a0324', tx.txid()) - - def test_txid_bitcoin_core_0043(self): - tx = transaction.Transaction('010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000') - self.assertEqual('25d35877eaba19497710666473c50d5527d38503e3521107a3fc532b74cd7453', tx.txid()) - - def test_txid_bitcoin_core_0044(self): - tx = transaction.Transaction('0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff') - self.assertEqual('1b9aef851895b93c62c29fbd6ca4d45803f4007eff266e2f96ff11e9b6ef197b', tx.txid()) - - def test_txid_bitcoin_core_0045(self): - tx = transaction.Transaction('010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000') - self.assertEqual('3444be2e216abe77b46015e481d8cc21abd4c20446aabf49cd78141c9b9db87e', tx.txid()) - - def test_txid_bitcoin_core_0046(self): - tx = transaction.Transaction('01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000') - self.assertEqual('f53761038a728b1f17272539380d96e93f999218f8dcb04a8469b523445cd0fd', tx.txid()) - - def test_txid_bitcoin_core_0047(self): - tx = transaction.Transaction('0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000') - self.assertEqual('d193f0f32fceaf07bb25c897c8f99ca6f69a52f6274ca64efc2a2e180cb97fc1', tx.txid()) - - def test_txid_bitcoin_core_0048(self): - tx = transaction.Transaction('010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000') - self.assertEqual('50a1e0e6a134a564efa078e3bd088e7e8777c2c0aec10a752fd8706470103b89', tx.txid()) - - def test_txid_bitcoin_core_0049(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000') - self.assertEqual('e2207d1aaf6b74e5d98c2fa326d2dc803b56b30a3f90ce779fa5edb762f38755', tx.txid()) - - def test_txid_bitcoin_core_0050(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000') - self.assertEqual('f335864f7c12ec7946d2c123deb91eb978574b647af125a414262380c7fbd55c', tx.txid()) - - def test_txid_bitcoin_core_0051(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000') - self.assertEqual('d1edbcde44691e98a7b7f556bd04966091302e29ad9af3c2baac38233667e0d2', tx.txid()) - - def test_txid_bitcoin_core_0052(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000') - self.assertEqual('3a13e1b6371c545147173cc4055f0ed73686a9f73f092352fb4b39ca27d360e6', tx.txid()) - - def test_txid_bitcoin_core_0053(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000') - self.assertEqual('bffda23e40766d292b0510a1b556453c558980c70c94ab158d8286b3413e220d', tx.txid()) - - def test_txid_bitcoin_core_0054(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000') - self.assertEqual('01a86c65460325dc6699714d26df512a62a854a669f6ed2e6f369a238e048cfd', tx.txid()) - - def test_txid_bitcoin_core_0055(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000') - self.assertEqual('f6d2359c5de2d904e10517d23e7c8210cca71076071bbf46de9fbd5f6233dbf1', tx.txid()) - - def test_txid_bitcoin_core_0056(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000') - self.assertEqual('19c2b7377229dae7aa3e50142a32fd37cef7171a01682f536e9ffa80c186f6c9', tx.txid()) - - def test_txid_bitcoin_core_0057(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000') - self.assertEqual('c9dda3a24cc8a5acb153d1085ecd2fecf6f87083122f8cdecc515b1148d4c40d', tx.txid()) - - def test_txid_bitcoin_core_0058(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000') - self.assertEqual('d1edbcde44691e98a7b7f556bd04966091302e29ad9af3c2baac38233667e0d2', tx.txid()) - - def test_txid_bitcoin_core_0059(self): - tx = transaction.Transaction('020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000') - self.assertEqual('01a86c65460325dc6699714d26df512a62a854a669f6ed2e6f369a238e048cfd', tx.txid()) - - def test_txid_bitcoin_core_0060(self): - tx = transaction.Transaction('02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000') - self.assertEqual('4b5e0aae1251a9dc66b4d5f483f1879bf518ea5e1765abc5a9f2084b43ed1ea7', tx.txid()) - - def test_txid_bitcoin_core_0061(self): - tx = transaction.Transaction('0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000') - self.assertEqual('5f16eb3ca4581e2dfb46a28140a4ee15f85e4e1c032947da8b93549b53c105f5', tx.txid()) - - def test_txid_bitcoin_core_0062(self): - tx = transaction.Transaction('0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100cfb07164b36ba64c1b1e8c7720a56ad64d96f6ef332d3d37f9cb3c96477dc44502200a464cd7a9cf94cd70f66ce4f4f0625ef650052c7afcfe29d7d7e01830ff91ed012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000') - self.assertEqual('b2ce556154e5ab22bec0a2f990b2b843f4f4085486c0d2cd82873685c0012004', tx.txid()) - - def test_txid_bitcoin_core_0063(self): - tx = transaction.Transaction('0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000') - self.assertEqual('b2ce556154e5ab22bec0a2f990b2b843f4f4085486c0d2cd82873685c0012004', tx.txid()) - - def test_txid_bitcoin_core_0064(self): - tx = transaction.Transaction('01000000000101000100000000000000000000000000000000000000000000000000000000000000000000171600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100cfb07164b36ba64c1b1e8c7720a56ad64d96f6ef332d3d37f9cb3c96477dc44502200a464cd7a9cf94cd70f66ce4f4f0625ef650052c7afcfe29d7d7e01830ff91ed012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000') - self.assertEqual('fee125c6cd142083fabd0187b1dd1f94c66c89ec6e6ef6da1374881c0c19aece', tx.txid()) - - def test_txid_bitcoin_core_0065(self): - tx = transaction.Transaction('0100000000010100010000000000000000000000000000000000000000000000000000000000000000000023220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000') - self.assertEqual('5f32557914351fee5f89ddee6c8983d476491d29e601d854e3927299e50450da', tx.txid()) - - def test_txid_bitcoin_core_0066(self): - tx = transaction.Transaction('0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000') - self.assertEqual('07dfa2da3d67c8a2b9f7bd31862161f7b497829d5da90a88ba0f1a905e7a43f7', tx.txid()) - - def test_txid_bitcoin_core_0067(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0068(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff0484030000000000000151d0070000000000000151540b0000000000000151c800000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('f92bb6e4f3ff89172f23ef647f74c13951b665848009abb5862cdf7a0412415a', tx.txid()) - - def test_txid_bitcoin_core_0069(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0070(self): - tx = transaction.Transaction('0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('e657e25fc9f2b33842681613402759222a58cf7dd504d6cdc0b69a0b8c2e7dcb', tx.txid()) - - def test_txid_bitcoin_core_0071(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0072(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff04b60300000000000001519e070000000000000151860b0000000000000100960000000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('4ede5e22992d43d42ccdf6553fb46e448aa1065ba36423f979605c1e5ab496b8', tx.txid()) - - def test_txid_bitcoin_core_0073(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0074(self): - tx = transaction.Transaction('01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('cfe9f4b19f52b8366860aec0d2b5815e329299b2e9890d477edd7f1182be7ac8', tx.txid()) - - def test_txid_bitcoin_core_0075(self): - tx = transaction.Transaction('0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('aee8f4865ca40fa77ff2040c0d7de683bea048b103d42ca406dc07dd29d539cb', tx.txid()) - - def test_txid_bitcoin_core_0076(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0077(self): - tx = transaction.Transaction('0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623ffffffffff1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('8a1bddf924d24570074b09d7967c145e54dc4cee7972a92fd975a2ad9e64b424', tx.txid()) - - def test_txid_bitcoin_core_0078(self): - tx = transaction.Transaction('0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015102fd08020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002755100000000') - self.assertEqual('d93ab9e12d7c29d2adc13d5cdf619d53eec1f36eb6612f55af52be7ba0448e97', tx.txid()) - - def test_txid_bitcoin_core_0079(self): - tx = transaction.Transaction('0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000') - self.assertEqual('b83579db5246aa34255642768167132a0c3d2932b186cd8fb9f5490460a0bf91', tx.txid()) - - def test_txid_bitcoin_core_0080(self): - tx = transaction.Transaction('010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000') - self.assertEqual('2b1e44fff489d09091e5e20f9a01bbc0e8d80f0662e629fd10709cdb4922a874', tx.txid()) - - def test_txid_bitcoin_core_0081(self): - tx = transaction.Transaction('0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff01d00700000000000001510003483045022100e078de4e96a0e05dcdc0a414124dd8475782b5f3f0ed3f607919e9a5eeeb22bf02201de309b3a3109adb3de8074b3610d4cf454c49b61247a2779a0bcbf31c889333032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc711976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac00000000') - self.assertEqual('60ebb1dd0b598e20dd0dd462ef6723dd49f8f803b6a2492926012360119cfdd7', tx.txid()) - - def test_txid_bitcoin_core_0082(self): - tx = transaction.Transaction('0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000') - self.assertEqual('ed0c7f4163e275f3f77064f471eac861d01fdf55d03aa6858ebd3781f70bf003', tx.txid()) - - def test_txid_bitcoin_core_0083(self): - tx = transaction.Transaction('0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000') - self.assertEqual('f531ddf5ce141e1c8a7fdfc85cc634e5ff686f446a5cf7483e9dbe076b844862', tx.txid()) - - def test_txid_bitcoin_core_0084(self): - tx = transaction.Transaction('01000000020001000000000000000000000000000000000000000000000000000000000000000000004847304402202a0b4b1294d70540235ae033d78e64b4897ec859c7b6f1b2b1d8a02e1d46006702201445e756d2254b0f1dfda9ab8e1e1bc26df9668077403204f32d16a49a36eb6983ffffffff00010000000000000000000000000000000000000000000000000000000000000100000049483045022100acb96cfdbda6dc94b489fd06f2d720983b5f350e31ba906cdbd800773e80b21c02200d74ea5bdf114212b4bbe9ed82c36d2e369e302dff57cb60d01c428f0bd3daab83ffffffff02e8030000000000000151e903000000000000015100000000') - self.assertEqual('98229b70948f1c17851a541f1fe532bf02c408267fecf6d7e174c359ae870654', tx.txid()) - - def test_txid_bitcoin_core_0085(self): - tx = transaction.Transaction('01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000') - self.assertEqual('570e3730deeea7bd8bc92c836ccdeb4dd4556f2c33f2a1f7b889a4cb4e48d3ab', tx.txid()) - - def test_txid_bitcoin_core_0086(self): - tx = transaction.Transaction('01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000') - self.assertEqual('e0b8142f587aaa322ca32abce469e90eda187f3851043cc4f2a0fff8c13fc84e', tx.txid()) - - def test_txid_bitcoin_core_0087(self): - tx = transaction.Transaction('0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000') - self.assertEqual('b9ecf72df06b8f98f8b63748d1aded5ffc1a1186f8a302e63cf94f6250e29f4d', tx.txid()) - - def test_txid_bitcoin_core_0088(self): - tx = transaction.Transaction('0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000') - self.assertEqual('27eae69aff1dd4388c0fa05cbbfe9a3983d1b0b5811ebcd4199b86f299370aac', tx.txid()) - - def test_txid_bitcoin_core_0089(self): - tx = transaction.Transaction('010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000') - self.assertEqual('22d020638e3b7e1f2f9a63124ac76f5e333c74387862e3675f64b25e960d3641', tx.txid()) - - def test_txid_bitcoin_core_0090(self): - tx = transaction.Transaction('0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000') - self.assertEqual('2862bc0c69d2af55da7284d1b16a7cddc03971b77e5a97939cca7631add83bf5', tx.txid()) - - def test_txid_bitcoin_core_0091(self): - tx = transaction.Transaction('01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000') - self.assertEqual('1aebf0c98f01381765a8c33d688f8903e4d01120589ac92b78f1185dc1f4119c', tx.txid()) - - def test_txid_bitcoin_core_0092(self): - tx = transaction.Transaction('010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000') - self.assertEqual('45d17fb7db86162b2b6ca29fa4e163acf0ef0b54110e49b819bda1f948d423a3', tx.txid()) - -# txns from Bitcoin Core ends <--- - class NetworkMock(object): diff --git a/lib/tests/test_util.py b/lib/tests/test_util.py index ea4476ab029c..747374cc13aa 100644 --- a/lib/tests/test_util.py +++ b/lib/tests/test_util.py @@ -23,48 +23,48 @@ def _do_test_parse_URI(self, uri, expected): self.assertEqual(expected, result) def test_parse_URI_address(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv'}) def test_parse_URI_only_address(self): - self._do_test_parse_URI('15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma'}) + self._do_test_parse_URI('LectrumELqJWMECz7W2iarBpT4VvAPqwAv', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv'}) def test_parse_URI_address_label(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?label=electrum%20test', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'label': 'electrum test'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?label=electrum%20test', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'label': 'electrum test'}) def test_parse_URI_address_message(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?message=electrum%20test', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'message': 'electrum test', 'memo': 'electrum test'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?message=electrum%20test', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'message': 'electrum test', 'memo': 'electrum test'}) def test_parse_URI_address_amount(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'amount': 30000}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?amount=0.0003', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'amount': 30000}) def test_parse_URI_address_request_url(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?r=http://domain.tld/page?h%3D2a8628fc2fbe', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'r': 'http://domain.tld/page?h=2a8628fc2fbe'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?r=http://domain.tld/page?h%3D2a8628fc2fbe', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'r': 'http://domain.tld/page?h=2a8628fc2fbe'}) def test_parse_URI_ignore_args(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?test=test', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'test': 'test'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?test=test', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'test': 'test'}) def test_parse_URI_multiple_args(self): - self._do_test_parse_URI('bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.00004&label=electrum-test&message=electrum%20test&test=none&r=http://domain.tld/page', - {'address': '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma', 'amount': 4000, 'label': 'electrum-test', 'message': u'electrum test', 'memo': u'electrum test', 'r': 'http://domain.tld/page', 'test': 'none'}) + self._do_test_parse_URI('zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?amount=0.00004&label=electrum-test&message=electrum%20test&test=none&r=http://domain.tld/page', + {'address': 'LectrumELqJWMECz7W2iarBpT4VvAPqwAv', 'amount': 4000, 'label': 'electrum-test', 'message': u'electrum test', 'memo': u'electrum test', 'r': 'http://domain.tld/page', 'test': 'none'}) def test_parse_URI_no_address_request_url(self): - self._do_test_parse_URI('bitcoin:?r=http://domain.tld/page?h%3D2a8628fc2fbe', + self._do_test_parse_URI('zcoin:?r=http://domain.tld/page?h%3D2a8628fc2fbe', {'r': 'http://domain.tld/page?h=2a8628fc2fbe'}) def test_parse_URI_invalid_address(self): - self.assertRaises(BaseException, parse_URI, 'bitcoin:invalidaddress') + self.assertRaises(BaseException, parse_URI, 'zcoin:invalidaddress') def test_parse_URI_invalid(self): - self.assertRaises(BaseException, parse_URI, 'notbitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma') + self.assertRaises(BaseException, parse_URI, 'notzcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv') def test_parse_URI_parameter_polution(self): - self.assertRaises(Exception, parse_URI, 'bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003&label=test&amount=30.0') + self.assertRaises(Exception, parse_URI, 'zcoin:LectrumELqJWMECz7W2iarBpT4VvAPqwAv?amount=0.0003&label=test&amount=30.0') diff --git a/lib/tests/test_wallet_vertical.py b/lib/tests/test_wallet_vertical.py index 4a95cb119937..12735fb4a728 100644 --- a/lib/tests/test_wallet_vertical.py +++ b/lib/tests/test_wallet_vertical.py @@ -6,8 +6,6 @@ import lib.storage as storage import lib.wallet as wallet -from plugins.trustedcoin import trustedcoin - # TODO passphrase/seed_extension class TestWalletKeystoreAddressIntegrity(unittest.TestCase): @@ -66,8 +64,8 @@ def test_electrum_seed_standard(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2pkh') - self.assertEqual(w.get_receiving_addresses()[0], '1NNkttn1YvVGdqBW4PR6zvc3Zx3H5owKRf') - self.assertEqual(w.get_change_addresses()[0], '1KSezYMhAJMWqFbVFB2JshYg69UpmEXR4D') + self.assertEqual(w.get_receiving_addresses()[0], 'LgbiA75qdajKtdsfEXQQGwfonAQZEEEbjS') + self.assertEqual(w.get_change_addresses()[0], 'LdfcFkfXExba64HeRK1c9icSJMr6tMKyfv') @mock.patch.object(storage.WalletStorage, '_write') def test_electrum_seed_segwit(self, mock_write): @@ -85,8 +83,8 @@ def test_electrum_seed_segwit(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2wpkh') - self.assertEqual(w.get_receiving_addresses()[0], 'bc1q3g5tmkmlvxryhh843v4dz026avatc0zzr6h3af') - self.assertEqual(w.get_change_addresses()[0], 'bc1qdy94n2q5qcp0kg7v9yzwe6wvfkhnvyzje7nx2p') + self.assertEqual(w.get_receiving_addresses()[0], 'xzc1q3g5tmkmlvxryhh843v4dz026avatc0zz8xd49e') + self.assertEqual(w.get_change_addresses()[0], 'xzc1qdy94n2q5qcp0kg7v9yzwe6wvfkhnvyzjazfzj3') @mock.patch.object(storage.WalletStorage, '_write') def test_electrum_seed_old(self, mock_write): @@ -103,41 +101,8 @@ def test_electrum_seed_old(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2pkh') - self.assertEqual(w.get_receiving_addresses()[0], '1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo') - self.assertEqual(w.get_change_addresses()[0], '1KRW8pH6HFHZh889VDq6fEKvmrsmApwNfe') - - @mock.patch.object(storage.WalletStorage, '_write') - def test_electrum_seed_2fa(self, mock_write): - seed_words = 'kiss live scene rude gate step hip quarter bunker oxygen motor glove' - self.assertEqual(bitcoin.seed_type(seed_words), '2fa') - - xprv1, xpub1, xprv2, xpub2 = trustedcoin.TrustedCoinPlugin.xkeys_from_seed(seed_words, '') - - ks1 = keystore.from_xprv(xprv1) - self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore)) - self.assertEqual(ks1.xprv, 'xprv9uraXy9F3HP7i8QDqwNTBiD8Jf4bPD4Epif8cS8qbUbgeidUesyZpKmzfcSeHutsGfFnjgih7kzwTB5UQVRNB5LoXaNc8pFusKYx3KVVvYR') - self.assertEqual(ks1.xpub, 'xpub68qvwUg8sewQvcUgwxuTYr9rrgu5nfn6BwajQpYT9p8fXWxdCRHpN86UWruWJAD1ede8Sv8ERrTa22Gyc4SBfm7zFpcyoVWVBKCVwnw6s1J') - self.assertEqual(ks1.xpub, xpub1) - - ks2 = keystore.from_xprv(xprv2) - self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore)) - self.assertEqual(ks2.xprv, 'xprv9uraXy9F3HP7kKSiRAvLV7Nrjj7YzspDys7dvGLLu4tLZT49CEBxPWp88dHhVxvZ69SHrPQMUCWjj4Ka2z9kNvs1HAeEf3extGGeSWqEVqf') - self.assertEqual(ks2.xpub, 'xpub68qvwUg8sewQxoXBXCTLrFKbHkx3QLY5M63EiejxTQRKSFPHjmWCwK8byvZMM2wZNYA3SmxXoma3M1zxhGESHZwtB7SwrxRgKXAG8dCD2eS') - self.assertEqual(ks2.xpub, xpub2) - - long_user_id, short_id = trustedcoin.get_user_id( - {'x1/': {'xpub': xpub1}, - 'x2/': {'xpub': xpub2}}) - xpub3 = trustedcoin.make_xpub(trustedcoin.signing_xpub, long_user_id) - ks3 = keystore.from_xpub(xpub3) - self._check_xpub_keystore_sanity(ks3) - self.assertTrue(isinstance(ks3, keystore.BIP32_KeyStore)) - - w = self._create_multisig_wallet(ks1, ks2, ks3) - self.assertEqual(w.txin_type, 'p2sh') - - self.assertEqual(w.get_receiving_addresses()[0], '35L8XmCDoEBKeaWRjvmZvoZvhp8BXMMMPV') - self.assertEqual(w.get_change_addresses()[0], '3PeZEcumRqHSPNN43hd4yskGEBdzXgY8Cy') + self.assertEqual(w.get_receiving_addresses()[0], 'LZXBVPSYn3bfFfibvUm9K8h4BddGhUE4Fe') + self.assertEqual(w.get_change_addresses()[0], 'LdeTQ2avMuXcwvpJfMpPwFPgz5F3Fnbsdu') @mock.patch.object(storage.WalletStorage, '_write') def test_bip39_seed_bip44_standard(self, mock_write): @@ -154,8 +119,8 @@ def test_bip39_seed_bip44_standard(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2pkh') - self.assertEqual(w.get_receiving_addresses()[0], '16j7Dqk3Z9DdTdBtHcCVLaNQy9MTgywUUo') - self.assertEqual(w.get_change_addresses()[0], '1GG5bVeWgAp5XW7JLCphse14QaC4qiHyWn') + self.assertEqual(w.get_receiving_addresses()[0], 'LQx4V43sdoTgiRt3TkBncbSBBMijtP3jg3') + self.assertEqual(w.get_change_addresses()[0], 'LaV2rhxLkq48nJoTWLp19f4pcnZLtJeLoB') @mock.patch.object(storage.WalletStorage, '_write') def test_bip39_seed_bip49_p2sh_segwit(self, mock_write): @@ -172,8 +137,8 @@ def test_bip39_seed_bip49_p2sh_segwit(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2wpkh-p2sh') - self.assertEqual(w.get_receiving_addresses()[0], '35ohQTdNykjkF1Mn9nAVEFjupyAtsPAK1W') - self.assertEqual(w.get_change_addresses()[0], '3KaBTcviBLEJajTEMstsA2GWjYoPzPK7Y7') + self.assertEqual(w.get_receiving_addresses()[0], 'MC1qiM3LvsbB3WdgFf9q3tzK9fmLrX1SQs') + self.assertEqual(w.get_change_addresses()[0], 'MRnKmWLg8T5jPEj8TktCyfWv4FPqyFBS3V') @mock.patch.object(storage.WalletStorage, '_write') def test_bip39_seed_bip84_native_segwit(self, mock_write): @@ -191,8 +156,8 @@ def test_bip39_seed_bip84_native_segwit(self, mock_write): w = self._create_standard_wallet(ks) self.assertEqual(w.txin_type, 'p2wpkh') - self.assertEqual(w.get_receiving_addresses()[0], 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu') - self.assertEqual(w.get_change_addresses()[0], 'bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el') + self.assertEqual(w.get_receiving_addresses()[0], 'xzc1qcr8te4kr609gcawutmrza0j4xv80jy8z4nqduv') + self.assertEqual(w.get_change_addresses()[0], 'xzc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0') @mock.patch.object(storage.WalletStorage, '_write') def test_electrum_multisig_seed_standard(self, mock_write): @@ -213,8 +178,8 @@ def test_electrum_multisig_seed_standard(self, mock_write): w = self._create_multisig_wallet(ks1, ks2) self.assertEqual(w.txin_type, 'p2sh') - self.assertEqual(w.get_receiving_addresses()[0], '32ji3QkAgXNz6oFoRfakyD3ys1XXiERQYN') - self.assertEqual(w.get_change_addresses()[0], '36XWwEHrrVCLnhjK5MrVVGmUHghr9oWTN1') + self.assertEqual(w.get_receiving_addresses()[0], 'M8wrMJA8deEQuJXhXYa6nrJPBi7yiLnCN5') + self.assertEqual(w.get_change_addresses()[0], 'MCjfF7hpoc3mbD1DBEqqJv1scPJJDhtoMG') @mock.patch.object(storage.WalletStorage, '_write') def test_electrum_multisig_seed_segwit(self, mock_write): @@ -235,8 +200,8 @@ def test_electrum_multisig_seed_segwit(self, mock_write): w = self._create_multisig_wallet(ks1, ks2) self.assertEqual(w.txin_type, 'p2wsh') - self.assertEqual(w.get_receiving_addresses()[0], 'bc1qvzezdcv6vs5h45ugkavp896e0nde5c5lg5h0fwe2xyfhnpkxq6gq7pnwlc') - self.assertEqual(w.get_change_addresses()[0], 'bc1qxqf840dqswcmu7a8v82fj6ej0msx08flvuy6kngr7axstjcaq6us9hrehd') + self.assertEqual(w.get_receiving_addresses()[0], 'xzc1qvzezdcv6vs5h45ugkavp896e0nde5c5lg5h0fwe2xyfhnpkxq6gqa9a79a') + self.assertEqual(w.get_change_addresses()[0], 'xzc1qxqf840dqswcmu7a8v82fj6ej0msx08flvuy6kngr7axstjcaq6usxndfdg') @mock.patch.object(storage.WalletStorage, '_write') def test_bip39_multisig_seed_bip45_standard(self, mock_write): @@ -257,8 +222,8 @@ def test_bip39_multisig_seed_bip45_standard(self, mock_write): w = self._create_multisig_wallet(ks1, ks2) self.assertEqual(w.txin_type, 'p2sh') - self.assertEqual(w.get_receiving_addresses()[0], '3JPTQ2nitVxXBJ1yhMeDwH6q417UifE3bN') - self.assertEqual(w.get_change_addresses()[0], '3FGyDuxgUDn2pSZe5xAJH1yUwSdhzDMyEE') + self.assertEqual(w.get_receiving_addresses()[0], 'MQbbhvCgqcowyoHsoEdZkvMENhhvktToCi') + self.assertEqual(w.get_change_addresses()[0], 'MMV7XoNeRLdTcwqYBq9e6fDtG9E9uHciwz') @mock.patch.object(storage.WalletStorage, '_write') def test_bip39_multisig_seed_p2sh_segwit(self, mock_write): @@ -278,5 +243,5 @@ def test_bip39_multisig_seed_p2sh_segwit(self, mock_write): w = self._create_multisig_wallet(ks1, ks2) self.assertEqual(w.txin_type, 'p2wsh-p2sh') - self.assertEqual(w.get_receiving_addresses()[0], '35LeC45QgCVeRor1tJD6LiDgPbybBXisns') - self.assertEqual(w.get_change_addresses()[0], '39RhtDchc6igmx5tyoimhojFL1ZbQBrXa6') + self.assertEqual(w.get_receiving_addresses()[0], 'MBYnVwVNdKM5EK7uzBCSAMU5iJa3ATHxCK') + self.assertEqual(w.get_change_addresses()[0], 'MFdrC72fZDa7aTMo5gi7XSyeeiA3P9VtUM') diff --git a/lib/transaction.py b/lib/transaction.py index 4ee57d4e1d2a..5688dd911367 100644 --- a/lib/transaction.py +++ b/lib/transaction.py @@ -32,8 +32,6 @@ from . import bitcoin from .bitcoin import * import struct -import traceback -import sys # # Workalike python implementation of Bitcoin's CDataStream class. @@ -305,8 +303,7 @@ def parse_scriptSig(d, _bytes): decoded = [ x for x in script_GetOp(_bytes) ] except Exception as e: # coinbase transactions raise an exception - print_error("parse_scriptSig: cannot find address in input script (coinbase?)", - bh2u(_bytes)) + print_error("cannot find address in input script", bh2u(_bytes)) return match = [ opcodes.OP_PUSHDATA4 ] @@ -337,9 +334,9 @@ def parse_scriptSig(d, _bytes): d['pubkeys'] = ["(pubkey)"] return - # p2pkh TxIn transactions push a signature - # (71-73 bytes) and then their public key - # (33 or 65 bytes) onto the stack: + # non-generated TxIn transactions push a signature + # (seventy-something bytes) and then their public key + # (65 bytes) onto the stack: match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ] if match_decoded(decoded, match): sig = bh2u(decoded[0][1]) @@ -348,8 +345,7 @@ def parse_scriptSig(d, _bytes): signatures = parse_sig([sig]) pubkey, address = xpubkey_to_address(x_pubkey) except: - print_error("parse_scriptSig: cannot find address in input script (p2pkh?)", - bh2u(_bytes)) + print_error("cannot find address in input script", bh2u(_bytes)) return d['type'] = 'p2pkh' d['signatures'] = signatures @@ -361,41 +357,30 @@ def parse_scriptSig(d, _bytes): # p2sh transaction, m of n match = [ opcodes.OP_0 ] + [ opcodes.OP_PUSHDATA4 ] * (len(decoded) - 1) - if match_decoded(decoded, match): - x_sig = [bh2u(x[1]) for x in decoded[1:-1]] - try: - m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1]) - except NotRecognizedRedeemScript: - print_error("parse_scriptSig: cannot find address in input script (p2sh?)", - bh2u(_bytes)) - # we could still guess: - # d['address'] = hash160_to_p2sh(hash_160(decoded[-1][1])) - return - # write result in d - d['type'] = 'p2sh' - d['num_sig'] = m - d['signatures'] = parse_sig(x_sig) - d['x_pubkeys'] = x_pubkeys - d['pubkeys'] = pubkeys - d['redeemScript'] = redeemScript - d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript))) + if not match_decoded(decoded, match): + print_error("cannot find address in input script", bh2u(_bytes)) return - - print_error("parse_scriptSig: cannot find address in input script (unknown)", - bh2u(_bytes)) + x_sig = [bh2u(x[1]) for x in decoded[1:-1]] + m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1]) + # write result in d + d['type'] = 'p2sh' + d['num_sig'] = m + d['signatures'] = parse_sig(x_sig) + d['x_pubkeys'] = x_pubkeys + d['pubkeys'] = pubkeys + d['redeemScript'] = redeemScript + d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript))) def parse_redeemScript(s): dec2 = [ x for x in script_GetOp(s) ] - try: - m = dec2[0][0] - opcodes.OP_1 + 1 - n = dec2[-2][0] - opcodes.OP_1 + 1 - except IndexError: - raise NotRecognizedRedeemScript() + m = dec2[0][0] - opcodes.OP_1 + 1 + n = dec2[-2][0] - opcodes.OP_1 + 1 op_m = opcodes.OP_1 + m - 1 op_n = opcodes.OP_1 + n - 1 match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ] if not match_decoded(dec2, match_multisig): + print_error("cannot find address in input script", bh2u(s)) raise NotRecognizedRedeemScript() x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]] pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys] @@ -451,11 +436,7 @@ def parse_input(vds): d['num_sig'] = 0 if scriptSig: d['scriptSig'] = bh2u(scriptSig) - try: - parse_scriptSig(d, scriptSig) - except BaseException: - traceback.print_exc(file=sys.stderr) - print_error('failed to parse scriptSig', bh2u(scriptSig)) + parse_scriptSig(d, scriptSig) else: d['scriptSig'] = '' @@ -484,40 +465,25 @@ def parse_witness(vds, txin): # between p2wpkh and p2wsh; we do this based on number of witness items, # hence (FIXME) p2wsh with n==2 (maybe n==1 ?) will probably fail. # If v==0 and n==2, we need parent scriptPubKey to distinguish between p2wpkh and p2wsh. - try: - if txin['type'] == 'coinbase': - pass - elif txin['type'] == 'p2wsh-p2sh' or n > 2: - try: - m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1])) - except NotRecognizedRedeemScript: - raise UnknownTxinType() - txin['signatures'] = parse_sig(w[1:-1]) - txin['num_sig'] = m - txin['x_pubkeys'] = x_pubkeys - txin['pubkeys'] = pubkeys - txin['witnessScript'] = witnessScript - if not txin.get('scriptSig'): # native segwit script - txin['type'] = 'p2wsh' - txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript']) - elif txin['type'] == 'p2wpkh-p2sh' or n == 2: - txin['num_sig'] = 1 - txin['x_pubkeys'] = [w[1]] - txin['pubkeys'] = [safe_parse_pubkey(w[1])] - txin['signatures'] = parse_sig([w[0]]) - if not txin.get('scriptSig'): # native segwit script - txin['type'] = 'p2wpkh' - txin['address'] = bitcoin.public_key_to_p2wpkh(bfh(txin['pubkeys'][0])) - else: + if txin['type'] == 'coinbase': + pass + elif txin['type'] == 'p2wsh-p2sh' or n > 2: + try: + m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1])) + except NotRecognizedRedeemScript: raise UnknownTxinType() - except UnknownTxinType: - txin['type'] = 'unknown' - # FIXME: GUI might show 'unknown' address (e.g. for a non-multisig p2wsh) - except BaseException: - txin['type'] = 'unknown' - traceback.print_exc(file=sys.stderr) - print_error('failed to parse witness', txin.get('witness')) - + txin['signatures'] = parse_sig(w[1:-1]) + txin['num_sig'] = m + txin['x_pubkeys'] = x_pubkeys + txin['pubkeys'] = pubkeys + txin['witnessScript'] = witnessScript + elif txin['type'] == 'p2wpkh-p2sh' or n == 2: + txin['num_sig'] = 1 + txin['x_pubkeys'] = [w[1]] + txin['pubkeys'] = [safe_parse_pubkey(w[1])] + txin['signatures'] = parse_sig([w[0]]) + else: + raise UnknownTxinType() def parse_output(vds, i): d = {} @@ -547,7 +513,20 @@ def deserialize(raw): if is_segwit: for i in range(n_vin): txin = d['inputs'][i] - parse_witness(vds, txin) + try: + parse_witness(vds, txin) + except UnknownTxinType: + txin['type'] = 'unknown' + # FIXME: GUI might show 'unknown' address (e.g. for a non-multisig p2wsh) + continue + # segwit-native script + if not txin.get('scriptSig'): + if txin['num_sig'] == 1: + txin['type'] = 'p2wpkh' + txin['address'] = bitcoin.public_key_to_p2wpkh(bfh(txin['pubkeys'][0])) + else: + txin['type'] = 'p2wsh' + txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript']) d['lockTime'] = vds.read_uint32() return d @@ -818,14 +797,6 @@ def get_preimage_script(self, txin): def serialize_outpoint(self, txin): return bh2u(bfh(txin['prevout_hash'])[::-1]) + int_to_hex(txin['prevout_n'], 4) - @classmethod - def get_outpoint_from_txin(cls, txin): - if txin['type'] == 'coinbase': - return None - prevout_hash = txin['prevout_hash'] - prevout_n = txin['prevout_n'] - return prevout_hash + ':%d' % prevout_n - @classmethod def serialize_input(self, txin, script): # Prev hash and index diff --git a/lib/util.py b/lib/util.py index 60723810ac0c..dc305eca91fb 100644 --- a/lib/util.py +++ b/lib/util.py @@ -40,7 +40,7 @@ def inv_dict(d): return {v: k for k, v in d.items()} -base_units = {'BTC':8, 'mBTC':5, 'uBTC':2} +base_units = {'XZC':8, 'mXZC':5, 'uXZC':2} fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')] def normalize_version(v): @@ -58,19 +58,6 @@ class InvalidPassword(Exception): def __str__(self): return _("Incorrect password") - -class FileImportFailed(Exception): - def __str__(self): - return _("Failed to import file.") - - -class FileImportFailedEncrypted(FileImportFailed): - def __str__(self): - return (_('Failed to import file.') + ' ' + - _('Perhaps it is encrypted...') + '\n' + - _('Importing encrypted files is not supported.')) - - # Throw this exception to unwind the stack like when an error occurs. # However unlike other exceptions the user won't be informed. class UserCancelled(Exception): @@ -250,7 +237,7 @@ def android_data_dir(): return PythonActivity.mActivity.getFilesDir().getPath() + '/data' def android_headers_dir(): - d = android_ext_dir() + '/org.electrum.electrum' + d = android_ext_dir() + '/org.electrum_xzc.electrum_xzc' if not os.path.exists(d): os.mkdir(d) return d @@ -259,7 +246,7 @@ def android_check_data_dir(): """ if needed, move old directory to sandbox """ ext_dir = android_ext_dir() data_dir = android_data_dir() - old_electrum_dir = ext_dir + '/electrum' + old_electrum_dir = ext_dir + '/electrum-xzc' if not os.path.exists(data_dir) and os.path.exists(old_electrum_dir): import shutil new_headers_path = android_headers_dir() + '/blockchain_headers' @@ -340,11 +327,11 @@ def user_dir(): if 'ANDROID_DATA' in os.environ: return android_check_data_dir() elif os.name == 'posix': - return os.path.join(os.environ["HOME"], ".electrum") + return os.path.join(os.environ["HOME"], ".electrum-xzc") elif "APPDATA" in os.environ: - return os.path.join(os.environ["APPDATA"], "Electrum") + return os.path.join(os.environ["APPDATA"], "Electrum-XZC") elif "LOCALAPPDATA" in os.environ: - return os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + return os.path.join(os.environ["LOCALAPPDATA"], "Electrum-XZC") else: #raise Exception("No home directory found in environment variables.") return @@ -444,41 +431,23 @@ def time_difference(distance_in_time, include_seconds): return "over %d years" % (round(distance_in_minutes / 525600)) mainnet_block_explorers = { - 'Biteasy.com': ('https://www.biteasy.com/blockchain/', - {'tx': 'transactions/', 'addr': 'addresses/'}), - 'Bitflyer.jp': ('https://chainflyer.bitflyer.jp/', - {'tx': 'Transaction/', 'addr': 'Address/'}), - 'Blockchain.info': ('https://blockchain.info/', - {'tx': 'tx/', 'addr': 'address/'}), - 'blockchainbdgpzk.onion': ('https://blockchainbdgpzk.onion/', - {'tx': 'tx/', 'addr': 'address/'}), - 'Blockr.io': ('https://btc.blockr.io/', - {'tx': 'tx/info/', 'addr': 'address/info/'}), - 'Blocktrail.com': ('https://www.blocktrail.com/BTC/', - {'tx': 'tx/', 'addr': 'address/'}), - 'BTC.com': ('https://chain.btc.com/', - {'tx': 'tx/', 'addr': 'address/'}), - 'Chain.so': ('https://www.chain.so/', - {'tx': 'tx/BTC/', 'addr': 'address/BTC/'}), - 'Insight.is': ('https://insight.bitpay.com/', - {'tx': 'tx/', 'addr': 'address/'}), - 'TradeBlock.com': ('https://tradeblock.com/blockchain/', - {'tx': 'tx/', 'addr': 'address/'}), - 'BlockCypher.com': ('https://live.blockcypher.com/btc/', - {'tx': 'tx/', 'addr': 'address/'}), - 'Blockchair.com': ('https://blockchair.com/bitcoin/', - {'tx': 'transaction/', 'addr': 'address/'}), - 'blockonomics.co': ('https://www.blockonomics.co/', - {'tx': 'api/tx?txid=', 'addr': '#/search?q='}), - 'system default': ('blockchain:/', - {'tx': 'tx/', 'addr': 'address/'}), + 'explorer.zcoin.net': ('http://explorer.zcoin.net', + {'tx': 'tx', 'addr': 'address'}), + 'Blockr.io': ('https://xzc.blockr.io', + {'tx': 'tx/info', 'addr': 'address/info'}), + 'BlockCypher.com': ('https://live.blockcypher.com/xzc', + {'tx': 'tx', 'addr': 'address'}), + 'SoChain': ('https://chain.so', + {'tx': 'tx/XZC', 'addr': 'address/XZC'}), + 'system default': ('blockchain:', + {'tx': 'tx', 'addr': 'address'}), } testnet_block_explorers = { - 'Blocktrail.com': ('https://www.blocktrail.com/tBTC/', - {'tx': 'tx/', 'addr': 'address/'}), - 'system default': ('blockchain://000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943/', - {'tx': 'tx/', 'addr': 'address/'}), + 'SoChain': ('https://chain.so', + {'tx': 'tx/XZCTEST', 'addr': 'address/XZCTEST'}), + 'system default': ('blockchain:', + {'tx': 'tx', 'addr': 'address'}), } def block_explorer_info(): @@ -486,7 +455,7 @@ def block_explorer_info(): return testnet_block_explorers if bitcoin.NetworkConstants.TESTNET else mainnet_block_explorers def block_explorer(config): - return config.get('block_explorer', 'Blocktrail.com') + return config.get('block_explorer', 'SoChain') def block_explorer_tuple(config): return block_explorer_info().get(block_explorer(config)) @@ -499,7 +468,7 @@ def block_explorer_URL(config, kind, item): if not kind_str: return url_parts = [be_tuple[0], kind_str, item] - return ''.join(url_parts) + return "/".join(url_parts) # URL decode #_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE) @@ -511,12 +480,12 @@ def parse_URI(uri, on_pr=None): if ':' not in uri: if not bitcoin.is_address(uri): - raise BaseException("Not a bitcoin address") + raise BaseException("Not a zcoin address") return {'address': uri} u = urllib.parse.urlparse(uri) - if u.scheme != 'bitcoin': - raise BaseException("Not a bitcoin URI") + if u.scheme != 'zcoin': + raise BaseException("Not a zcoin URI") address = u.path # python for android fails to parse query @@ -533,7 +502,7 @@ def parse_URI(uri, on_pr=None): out = {k: v[0] for k, v in pq.items()} if address: if not bitcoin.is_address(address): - raise BaseException("Invalid bitcoin address:" + address) + raise BaseException("Invalid zcoin address:" + address) out['address'] = address if 'amount' in out: am = out['amount'] @@ -583,7 +552,7 @@ def create_URI(addr, amount, message): query.append('amount=%s'%format_satoshis_plain(amount)) if message: query.append('message=%s'%urllib.parse.quote(message)) - p = urllib.parse.ParseResult(scheme='bitcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='') + p = urllib.parse.ParseResult(scheme='zcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='') return urllib.parse.urlunparse(p) @@ -747,8 +716,4 @@ def run_with_except_hook(*args2, **kwargs2): self.run = run_with_except_hook - threading.Thread.__init__ = init - - -def versiontuple(v): - return tuple(map(int, (v.split(".")))) + threading.Thread.__init__ = init \ No newline at end of file diff --git a/lib/version.py b/lib/version.py index 1d653e591a3c..2f71ac17b536 100644 --- a/lib/version.py +++ b/lib/version.py @@ -1,5 +1,5 @@ -ELECTRUM_VERSION = '3.1' # version of the client package -PROTOCOL_VERSION = '1.2' # protocol version requested +ELECTRUM_VERSION = '3.0.5' # version of the client package +PROTOCOL_VERSION = '1.1' # protocol version requested # The hash of the mnemonic seed must begin with this SEED_PREFIX = '01' # Standard wallet diff --git a/lib/wallet.py b/lib/wallet.py index 921a1bb844e8..3972b255bf31 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -38,7 +38,6 @@ from functools import partial from collections import defaultdict from numbers import Number -from decimal import Decimal import sys @@ -49,7 +48,7 @@ from .bitcoin import * from .version import * from .keystore import load_keystore, Hardware_KeyStore -from .storage import multisig_type, STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW +from .storage import multisig_type from . import transaction from .transaction import Transaction @@ -67,6 +66,7 @@ TX_STATUS = [ _('Replaceable'), _('Unconfirmed parent'), + _('Low fee'), _('Unconfirmed'), _('Not Verified'), _('Local only'), @@ -78,8 +78,8 @@ def relayfee(network): - RELAY_FEE = 1000 - MAX_RELAY_FEE = 50000 + RELAY_FEE = 100000 + MAX_RELAY_FEE = 10 * RELAY_FEE f = network.relay_fee if network and network.relay_fee else RELAY_FEE return min(f, MAX_RELAY_FEE) @@ -185,12 +185,11 @@ def __init__(self, storage): self.labels = storage.get('labels', {}) self.frozen_addresses = set(storage.get('frozen_addresses',[])) self.history = storage.get('addr_history',{}) # address -> list(txid, height) - self.fiat_value = storage.get('fiat_value', {}) self.load_keystore() self.load_addresses() self.load_transactions() - self.build_spent_outpoints() + self.build_reverse_history() # load requests self.receive_requests = self.storage.get('payment_requests', {}) @@ -206,10 +205,8 @@ def __init__(self, storage): # interface.is_up_to_date() returns true when all requests have been answered and processed # wallet.up_to_date is true when the wallet is synchronized (stronger requirement) self.up_to_date = False - - # locks: if you need to take multiple ones, acquire them in the order they are defined here! - self.lock = threading.RLock() - self.transaction_lock = threading.RLock() + self.lock = threading.Lock() + self.transaction_lock = threading.Lock() self.check_history() @@ -242,8 +239,7 @@ def load_transactions(self): for tx_hash, raw in tx_list.items(): tx = Transaction(raw) self.transactions[tx_hash] = tx - if self.txi.get(tx_hash) is None and self.txo.get(tx_hash) is None \ - and (tx_hash not in self.pruned_txo.values()): + if self.txi.get(tx_hash) is None and self.txo.get(tx_hash) is None and (tx_hash not in self.pruned_txo.values()): self.print_error("removing unreferenced tx", tx_hash) self.transactions.pop(tx_hash) @@ -263,25 +259,24 @@ def save_transactions(self, write=False): self.storage.write() def clear_history(self): + with self.transaction_lock: + self.txi = {} + self.txo = {} + self.tx_fees = {} + self.pruned_txo = {} + self.save_transactions() with self.lock: - with self.transaction_lock: - self.txi = {} - self.txo = {} - self.tx_fees = {} - self.pruned_txo = {} - self.spent_outpoints = {} - self.history = {} - self.verified_tx = {} - self.transactions = {} - self.save_transactions() + self.history = {} + self.tx_addr_hist = {} @profiler - def build_spent_outpoints(self): - self.spent_outpoints = {} - for txid, items in self.txi.items(): - for addr, l in items.items(): - for ser, v in l: - self.spent_outpoints[ser] = txid + def build_reverse_history(self): + self.tx_addr_hist = {} + for addr, hist in self.history.items(): + for tx_hash, h in hist: + s = self.tx_addr_hist.get(tx_hash, set()) + s.add(addr) + self.tx_addr_hist[tx_hash] = s @profiler def check_history(self): @@ -322,9 +317,6 @@ def load_addresses(self): def synchronize(self): pass - def is_deterministic(self): - return self.keystore.is_deterministic() - def set_up_to_date(self, up_to_date): with self.lock: self.up_to_date = up_to_date @@ -346,36 +338,12 @@ def set_label(self, name, text = None): if old_text: self.labels.pop(name) changed = True + if changed: run_hook('set_label', self, name, text) self.storage.put('labels', self.labels) - return changed - def set_fiat_value(self, txid, ccy, text): - if txid not in self.transactions: - return - if not text: - d = self.fiat_value.get(ccy, {}) - if d and txid in d: - d.pop(txid) - else: - return - else: - try: - Decimal(text) - except: - return - if ccy not in self.fiat_value: - self.fiat_value[ccy] = {} - self.fiat_value[ccy][txid] = text - self.storage.put('fiat_value', self.fiat_value) - - def get_fiat_value(self, txid, ccy): - fiat_value = self.fiat_value.get(ccy, {}).get(txid) - try: - return Decimal(fiat_value) - except: - return + return changed def is_mine(self, address): return address in self.get_addresses() @@ -448,7 +416,7 @@ def get_local_height(self): return self.network.get_local_height() if self.network else self.storage.get('stored_height', 0) def get_tx_height(self, tx_hash): - """ Given a transaction, returns (height, conf, timestamp) """ + """ return the height and timestamp of a transaction. """ with self.lock: if tx_hash in self.verified_tx: height, timestamp, pos = self.verified_tx[tx_hash] @@ -563,17 +531,17 @@ def get_tx_info(self, tx): height, conf, timestamp = self.get_tx_height(tx_hash) if height > 0: if conf: - status = _("{} confirmations").format(conf) + status = _("%d confirmations") % conf else: status = _('Not verified') elif height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED): status = _('Unconfirmed') if fee is None: fee = self.tx_fees.get(tx_hash) - if fee and self.network.config.has_fee_etas(): + if fee and self.network.config.has_fee_estimates(): size = tx.estimated_size() fee_per_kb = fee * 1000 / size - exp_n = self.network.config.fee_to_eta(fee_per_kb) + exp_n = self.network.config.reverse_dynfee(fee_per_kb) can_bump = is_mine and not tx.is_final() else: status = _('Local') @@ -707,12 +675,7 @@ def get_address_history(self, addr): h.append((tx_hash, tx_height)) return h - def get_txin_address(self, txi): - addr = txi.get('address') - if addr != "(pubkey)": - return addr - prevout_hash = txi.get('prevout_hash') - prevout_n = txi.get('prevout_n') + def find_pay_to_pubkey_address(self, prevout_hash, prevout_n): dd = self.txo.get(prevout_hash, {}) for addr, l in dd.items(): for n, v, is_cb in l: @@ -720,89 +683,23 @@ def get_txin_address(self, txi): self.print_error("found pay-to-pubkey address:", addr) return addr - def get_txout_address(self, txo): - _type, x, v = txo - if _type == TYPE_ADDRESS: - addr = x - elif _type == TYPE_PUBKEY: - addr = bitcoin.public_key_to_p2pkh(bfh(x)) - else: - addr = None - return addr - - def get_conflicting_transactions(self, tx): - """Returns a set of transaction hashes from the wallet history that are - directly conflicting with tx, i.e. they have common outpoints being - spent with tx. - """ - conflicting_txns = set() - with self.transaction_lock: - for txi in tx.inputs(): - ser = Transaction.get_outpoint_from_txin(txi) - if ser is None: - continue - spending_tx_hash = self.spent_outpoints.get(ser, None) - if spending_tx_hash is None: - continue - # this outpoint (ser) has already been spent, by spending_tx - assert spending_tx_hash in self.transactions - conflicting_txns |= {spending_tx_hash} - return conflicting_txns - def add_transaction(self, tx_hash, tx): + is_coinbase = tx.inputs()[0]['type'] == 'coinbase' + related = False with self.transaction_lock: - if tx in self.transactions: - return True - is_coinbase = tx.inputs()[0]['type'] == 'coinbase' - tx_height = self.get_tx_height(tx_hash)[0] - is_mine = any([self.is_mine(txin['address']) for txin in tx.inputs()]) - # do not save if tx is local and not mine - if tx_height == TX_HEIGHT_LOCAL and not is_mine: - # FIXME the test here should be for "not all is_mine"; cannot detect conflict in some cases - return False - # raise exception if unrelated to wallet - is_for_me = any([self.is_mine(self.get_txout_address(txo)) for txo in tx.outputs()]) - if not is_mine and not is_for_me: - raise UnrelatedTransactionException() - # Find all conflicting transactions. - # In case of a conflict, - # 1. confirmed > mempool > local - # 2. this new txn has priority over existing ones - # When this method exits, there must NOT be any conflict, so - # either keep this txn and remove all conflicting (along with dependencies) - # or drop this txn - conflicting_txns = self.get_conflicting_transactions(tx) - if conflicting_txns: - existing_mempool_txn = any( - self.get_tx_height(tx_hash2)[0] in (TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT) - for tx_hash2 in conflicting_txns) - existing_confirmed_txn = any( - self.get_tx_height(tx_hash2)[0] > 0 - for tx_hash2 in conflicting_txns) - if existing_confirmed_txn and tx_height <= 0: - # this is a non-confirmed tx that conflicts with confirmed txns; drop. - return False - if existing_mempool_txn and tx_height == TX_HEIGHT_LOCAL: - # this is a local tx that conflicts with non-local txns; drop. - return False - # keep this txn and remove all conflicting - to_remove = set() - to_remove |= conflicting_txns - for conflicting_tx_hash in conflicting_txns: - to_remove |= self.get_depending_transactions(conflicting_tx_hash) - for tx_hash2 in to_remove: - self.remove_transaction(tx_hash2) # add inputs self.txi[tx_hash] = d = {} for txi in tx.inputs(): - addr = self.get_txin_address(txi) + addr = txi.get('address') if txi['type'] != 'coinbase': prevout_hash = txi['prevout_hash'] prevout_n = txi['prevout_n'] ser = prevout_hash + ':%d'%prevout_n - self.spent_outpoints[ser] = tx_hash + if addr == "(pubkey)": + addr = self.find_pay_to_pubkey_address(prevout_hash, prevout_n) # find value from prev output if addr and self.is_mine(addr): + related = True dd = self.txo.get(prevout_hash, {}) for n, v, is_cb in dd.get(addr, []): if n == prevout_n: @@ -812,13 +709,20 @@ def add_transaction(self, tx_hash, tx): break else: self.pruned_txo[ser] = tx_hash + # add outputs self.txo[tx_hash] = d = {} for n, txo in enumerate(tx.outputs()): - v = txo[2] ser = tx_hash + ':%d'%n - addr = self.get_txout_address(txo) + _type, x, v = txo + if _type == TYPE_ADDRESS: + addr = x + elif _type == TYPE_PUBKEY: + addr = bitcoin.public_key_to_p2pkh(bfh(x)) + else: + addr = None if addr and self.is_mine(addr): + related = True if d.get(addr) is None: d[addr] = [] d[addr].append((n, v, is_coinbase)) @@ -830,22 +734,20 @@ def add_transaction(self, tx_hash, tx): if dd.get(addr) is None: dd[addr] = [] dd[addr].append((ser, v)) + + if not related: + raise UnrelatedTransactionException() + # save self.transactions[tx_hash] = tx - return True def remove_transaction(self, tx_hash): - def undo_spend(outpoint_to_txid_map): - for addr, l in self.txi[tx_hash].items(): - for ser, v in l: - outpoint_to_txid_map.pop(ser, None) - with self.transaction_lock: self.print_error("removing tx from history", tx_hash) - self.transactions.pop(tx_hash, None) - undo_spend(self.pruned_txo) - undo_spend(self.spent_outpoints) - + #tx = self.transactions.pop(tx_hash) + for ser, hh in list(self.pruned_txo.items()): + if hh == tx_hash: + self.pruned_txo.pop(ser) # add tx to pruned_txo, and undo the txi addition for next_tx, dd in self.txi.items(): for addr, l in list(dd.items()): @@ -867,27 +769,26 @@ def undo_spend(outpoint_to_txid_map): self.print_error("tx was not in history", tx_hash) def receive_tx_callback(self, tx_hash, tx, tx_height): - self.add_unverified_tx(tx_hash, tx_height) self.add_transaction(tx_hash, tx) + self.add_unverified_tx(tx_hash, tx_height) def receive_history_callback(self, addr, hist, tx_fees): with self.lock: - old_hist = self.get_address_history(addr) + old_hist = self.history.get(addr, []) for tx_hash, height in old_hist: if (tx_hash, height) not in hist: # make tx local self.unverified_tx.pop(tx_hash, None) self.verified_tx.pop(tx_hash, None) - self.verifier.merkle_roots.pop(tx_hash, None) - # but remove completely if not is_mine - if self.txi[tx_hash] == {}: - # FIXME the test here should be for "not all is_mine"; cannot detect conflict in some cases - self.remove_transaction(tx_hash) self.history[addr] = hist for tx_hash, tx_height in hist: # add it in case it was previously unconfirmed self.add_unverified_tx(tx_hash, tx_height) + # add reference in tx_addr_hist + s = self.tx_addr_hist.get(tx_hash, set()) + s.add(addr) + self.tx_addr_hist[tx_hash] = s # if addr is new, we have to recompute txi and txo tx = self.transactions.get(tx_hash) if tx is not None and self.txi.get(tx_hash, {}).get(addr) is None and self.txo.get(tx_hash, {}).get(addr) is None: @@ -940,94 +841,6 @@ def get_history(self, domain=None): return h2 - def balance_at_timestamp(self, domain, target_timestamp): - h = self.get_history(domain) - for tx_hash, height, conf, timestamp, value, balance in h: - if timestamp > target_timestamp: - return balance - value - # return last balance - return balance - - def export_history(self, domain=None, from_timestamp=None, to_timestamp=None, fx=None, show_addresses=False): - from .util import format_time, format_satoshis, timestamp_to_datetime - h = self.get_history(domain) - out = [] - init_balance = None - capital_gains = 0 - fiat_income = 0 - for tx_hash, height, conf, timestamp, value, balance in h: - if from_timestamp and timestamp < from_timestamp: - continue - if to_timestamp and timestamp >= to_timestamp: - continue - item = { - 'txid':tx_hash, - 'height':height, - 'confirmations':conf, - 'timestamp':timestamp, - 'value': format_satoshis(value, True) if value is not None else '--', - 'balance': format_satoshis(balance) - } - if init_balance is None: - init_balance = balance - value - end_balance = balance - if item['height']>0: - date_str = format_time(timestamp) if timestamp is not None else _("unverified") - else: - date_str = _("unconfirmed") - item['date'] = date_str - item['label'] = self.get_label(tx_hash) - if show_addresses: - tx = self.transactions.get(tx_hash) - tx.deserialize() - input_addresses = [] - output_addresses = [] - for x in tx.inputs(): - if x['type'] == 'coinbase': continue - addr = self.get_txin_address(x) - if addr is None: - continue - input_addresses.append(addr) - for addr, v in tx.get_outputs(): - output_addresses.append(addr) - item['input_addresses'] = input_addresses - item['output_addresses'] = output_addresses - if fx is not None: - date = timestamp_to_datetime(time.time() if conf <= 0 else timestamp) - fiat_value = self.get_fiat_value(tx_hash, fx.ccy) - if fiat_value is None: - fiat_value = fx.historical_value(value, date) - item['fiat_value'] = fx.format_fiat(fiat_value) - if value < 0: - ap, lp = self.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy) - cg = None if lp is None or ap is None else lp - ap - item['acquisition_price'] = fx.format_fiat(ap) - item['capital_gain'] = fx.format_fiat(cg) - if cg is not None: - capital_gains += cg - else: - if fiat_value is not None: - fiat_income += fiat_value - out.append(item) - - if from_timestamp and to_timestamp: - summary = { - 'start_date': format_time(from_timestamp), - 'end_date': format_time(to_timestamp), - 'start_balance': format_satoshis(init_balance), - 'end_balance': format_satoshis(end_balance), - 'capital_gains': fx.format_fiat(capital_gains), - 'fiat_income': fx.format_fiat(fiat_income) - } - if fx: - start_date = timestamp_to_datetime(from_timestamp) - end_date = timestamp_to_datetime(to_timestamp) - summary['start_fiat_balance'] = fx.format_fiat(fx.historical_value(init_balance, start_date)) - summary['end_fiat_balance'] = fx.format_fiat(fx.historical_value(end_balance, end_date)) - out.append(summary) - - return out - def get_label(self, tx_hash): label = self.labels.get(tx_hash, '') if label is '': @@ -1047,33 +860,34 @@ def get_default_label(self, tx_hash): def get_tx_status(self, tx_hash, height, conf, timestamp): from .util import format_time - exp_n = False if conf == 0: tx = self.transactions.get(tx_hash) if not tx: - return 2, 'unknown' + return 3, 'unknown' is_final = tx and tx.is_final() fee = self.tx_fees.get(tx_hash) - if fee and self.network and self.network.config.has_fee_mempool(): - size = tx.estimated_size() - fee_per_kb = fee * 1000 / size - exp_n = self.network.config.fee_to_depth(fee_per_kb//1000) + if fee and self.network and self.network.config.has_fee_estimates(): + size = len(tx.raw)/2 + low_fee = int(self.network.config.dynfee(0)*size/1000) + is_lowfee = fee < low_fee * 0.5 + else: + is_lowfee = False if height == TX_HEIGHT_LOCAL: - status = 4 + status = 5 elif height == TX_HEIGHT_UNCONF_PARENT: status = 1 elif height == TX_HEIGHT_UNCONFIRMED and not is_final: status = 0 - elif height == TX_HEIGHT_UNCONFIRMED: + elif height == TX_HEIGHT_UNCONFIRMED and is_lowfee: status = 2 - else: + elif height == TX_HEIGHT_UNCONFIRMED: status = 3 + else: + status = 4 else: - status = 4 + min(conf, 6) + status = 5 + min(conf, 6) time_str = format_time(timestamp) if timestamp else _("unknown") - status_str = TX_STATUS[status] if status < 5 else time_str - if exp_n: - status_str += ' [%d sat/b, %.2f MB]'%(fee_per_kb//1000, exp_n/1000000) + status_str = TX_STATUS[status] if status < 6 else time_str return status, status_str def relayfee(self): @@ -1090,7 +904,7 @@ def make_unsigned_transaction(self, inputs, outputs, config, fixed_fee=None, _type, data, value = o if _type == TYPE_ADDRESS: if not is_address(data): - raise BaseException("Invalid bitcoin address:" + data) + raise BaseException("Invalid zcoin address:" + data) if value == '!': if i_max is not None: raise BaseException("More than one output set to spend max") @@ -1103,9 +917,8 @@ def make_unsigned_transaction(self, inputs, outputs, config, fixed_fee=None, if fixed_fee is None and config.fee_per_kb() is None: raise NoDynamicFeeEstimates() - if not is_sweep: - for item in inputs: - self.add_input_info(item) + for item in inputs: + self.add_input_info(item) # change address if change_addr: @@ -1430,7 +1243,7 @@ def get_payment_request(self, addr, config): if not r: return out = copy.copy(r) - out['URI'] = 'bitcoin:' + addr + '?amount=' + format_satoshis(out.get('amount')) + out['URI'] = 'zcoin:' + addr + '?amount=' + format_satoshis(out.get('amount')) status, conf = self.get_request_status(addr) out['status'] = status if conf is not None: @@ -1570,65 +1383,10 @@ def add_address(self, address): self.synchronizer.add(address) def has_password(self): - return self.has_keystore_encryption() or self.has_storage_encryption() - - def can_have_keystore_encryption(self): - return self.keystore and self.keystore.may_have_password() - - def get_available_storage_encryption_version(self): - """Returns the type of storage encryption offered to the user. - - A wallet file (storage) is either encrypted with this version - or is stored in plaintext. - """ - if isinstance(self.keystore, Hardware_KeyStore): - return STO_EV_XPUB_PW - else: - return STO_EV_USER_PW - - def has_keystore_encryption(self): - """Returns whether encryption is enabled for the keystore. - - If True, e.g. signing a transaction will require a password. - """ - if self.can_have_keystore_encryption(): - return self.storage.get('use_encryption', False) - return False - - def has_storage_encryption(self): - """Returns whether encryption is enabled for the wallet file on disk.""" - return self.storage.is_encrypted() - - @classmethod - def may_have_password(cls): - return True + return self.storage.get('use_encryption', False) def check_password(self, password): - if self.has_keystore_encryption(): - self.keystore.check_password(password) - self.storage.check_password(password) - - def update_password(self, old_pw, new_pw, encrypt_storage=False): - if old_pw is None and self.has_password(): - raise InvalidPassword() - self.check_password(old_pw) - - if encrypt_storage: - enc_version = self.get_available_storage_encryption_version() - else: - enc_version = STO_EV_PLAINTEXT - self.storage.set_password(new_pw, enc_version) - - # note: Encrypting storage with a hw device is currently only - # allowed for non-multisig wallets. Further, - # Hardware_KeyStore.may_have_password() == False. - # If these were not the case, - # extra care would need to be taken when encrypting keystores. - self._update_password_for_keystore(old_pw, new_pw) - encrypt_keystore = self.can_have_keystore_encryption() - self.storage.set_keystore_encryption(bool(new_pw) and encrypt_keystore) - - self.storage.write() + self.keystore.check_password(password) def sign_message(self, address, message, password): index = self.get_address_index(address) @@ -1649,63 +1407,6 @@ def get_depending_transactions(self, tx_hash): children |= self.get_depending_transactions(other_hash) return children - def txin_value(self, txin): - txid = txin['prevout_hash'] - prev_n = txin['prevout_n'] - for address, d in self.txo[txid].items(): - for n, v, cb in d: - if n == prev_n: - return v - raise BaseException('unknown txin value') - - def price_at_timestamp(self, txid, price_func): - height, conf, timestamp = self.get_tx_height(txid) - return price_func(timestamp) - - def capital_gain(self, txid, price_func, ccy): - """ - Difference between the fiat price of coins leaving the wallet because of transaction txid, - and the price of these coins when they entered the wallet. - price_func: function that returns the fiat price given a timestamp - """ - tx = self.transactions[txid] - ir, im, v, fee = self.get_wallet_delta(tx) - out_value = -v - fiat_value = self.get_fiat_value(txid, ccy) - if fiat_value is None: - p = self.price_at_timestamp(txid, price_func) - liquidation_price = None if p is None else out_value/Decimal(COIN) * p - else: - liquidation_price = - fiat_value - try: - acquisition_price = out_value/Decimal(COIN) * self.average_price(tx, price_func, ccy) - except: - acquisition_price = None - return acquisition_price, liquidation_price - - - def average_price(self, tx, price_func, ccy): - """ average price of the inputs of a transaction """ - input_value = sum(self.txin_value(txin) for txin in tx.inputs()) / Decimal(COIN) - total_price = sum(self.coin_price(txin, price_func, ccy, self.txin_value(txin)) for txin in tx.inputs()) - return total_price / input_value - - def coin_price(self, coin, price_func, ccy, txin_value): - """ fiat price of acquisition of coin """ - txid = coin['prevout_hash'] - tx = self.transactions[txid] - if all([self.is_mine(txin['address']) for txin in tx.inputs()]): - return self.average_price(tx, price_func, ccy) * txin_value/Decimal(COIN) - elif all([ not self.is_mine(txin['address']) for txin in tx.inputs()]): - fiat_value = self.get_fiat_value(txid, ccy) - if fiat_value is not None: - return fiat_value - else: - return self.price_at_timestamp(txid, price_func) * txin_value/Decimal(COIN) - else: - # could be some coinjoin transaction.. - return None - class Simple_Wallet(Abstract_Wallet): # wallet with a single keystore @@ -1719,10 +1420,16 @@ def get_keystores(self): def is_watching_only(self): return self.keystore.is_watching_only() - def _update_password_for_keystore(self, old_pw, new_pw): - if self.keystore and self.keystore.may_have_password(): - self.keystore.update_password(old_pw, new_pw) - self.save_keystore() + def can_change_password(self): + return self.keystore.can_change_password() + + def update_password(self, old_pw, new_pw, encrypt=False): + if old_pw is None and self.has_password(): + raise InvalidPassword() + self.keystore.update_password(old_pw, new_pw) + self.save_keystore() + self.storage.set_password(new_pw, encrypt) + self.storage.write() def save_keystore(self): self.storage.put('keystore', self.keystore.dump()) @@ -1761,6 +1468,9 @@ def load_addresses(self): def save_addresses(self): self.storage.put('addresses', self.addresses) + def can_change_password(self): + return not self.is_watching_only() + def can_import_address(self): return self.is_watching_only() @@ -1779,7 +1489,7 @@ def is_change(self, address): def get_master_public_keys(self): return [] - def is_beyond_limit(self, address): + def is_beyond_limit(self, address, is_change): return False def is_mine(self, address): @@ -1920,6 +1630,9 @@ def __init__(self, storage): def has_seed(self): return self.keystore.has_seed() + def is_deterministic(self): + return self.keystore.is_deterministic() + def get_receiving_addresses(self): return self.receiving_addresses @@ -1981,16 +1694,15 @@ def load_addresses(self): def create_new_address(self, for_change=False): assert type(for_change) is bool - with self.lock: - addr_list = self.change_addresses if for_change else self.receiving_addresses - n = len(addr_list) - x = self.derive_pubkeys(for_change, n) - address = self.pubkeys_to_address(x) - addr_list.append(address) - self._addr_to_addr_index[address] = (for_change, n) - self.save_addresses() - self.add_address(address) - return address + addr_list = self.change_addresses if for_change else self.receiving_addresses + n = len(addr_list) + x = self.derive_pubkeys(for_change, n) + address = self.pubkeys_to_address(x) + addr_list.append(address) + self._addr_to_addr_index[address] = (for_change, n) + self.save_addresses() + self.add_address(address) + return address def synchronize_sequence(self, for_change): limit = self.gap_limit_for_change if for_change else self.gap_limit @@ -2006,12 +1718,20 @@ def synchronize_sequence(self, for_change): def synchronize(self): with self.lock: - self.synchronize_sequence(False) - self.synchronize_sequence(True) - - def is_beyond_limit(self, address): - is_change, i = self.get_address_index(address) + if self.is_deterministic(): + self.synchronize_sequence(False) + self.synchronize_sequence(True) + else: + if len(self.receiving_addresses) != len(self.keystore.keypairs): + pubkeys = self.keystore.keypairs.keys() + self.receiving_addresses = [self.pubkeys_to_address(i) for i in pubkeys] + self.save_addresses() + for addr in self.receiving_addresses: + self.add_address(addr) + + def is_beyond_limit(self, address, is_change): addr_list = self.get_change_addresses() if is_change else self.get_receiving_addresses() + i = self.get_address_index(address)[1] limit = self.gap_limit_for_change if is_change else self.gap_limit if i < limit: return False @@ -2129,28 +1849,22 @@ def get_keystore(self): def get_keystores(self): return [self.keystores[i] for i in sorted(self.keystores.keys())] - def can_have_keystore_encryption(self): - return any([k.may_have_password() for k in self.get_keystores()]) - - def _update_password_for_keystore(self, old_pw, new_pw): + def update_password(self, old_pw, new_pw, encrypt=False): + if old_pw is None and self.has_password(): + raise InvalidPassword() for name, keystore in self.keystores.items(): - if keystore.may_have_password(): + if keystore.can_change_password(): keystore.update_password(old_pw, new_pw) self.storage.put(name, keystore.dump()) - - def check_password(self, password): - for name, keystore in self.keystores.items(): - if keystore.may_have_password(): - keystore.check_password(password) - self.storage.check_password(password) - - def get_available_storage_encryption_version(self): - # multisig wallets are not offered hw device encryption - return STO_EV_USER_PW + self.storage.set_password(new_pw, encrypt) + self.storage.write() def has_seed(self): return self.keystore.has_seed() + def can_change_password(self): + return self.keystore.can_change_password() + def is_watching_only(self): return not any([not k.is_watching_only() for k in self.get_keystores()]) diff --git a/plugins/audio_modem/__init__.py b/plugins/audio_modem/__init__.py index 46c2d2091e00..75610e3762a5 100644 --- a/plugins/audio_modem/__init__.py +++ b/plugins/audio_modem/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = _('Audio MODEM') description = _('Provides support for air-gapped transaction signing.') diff --git a/plugins/audio_modem/qt.py b/plugins/audio_modem/qt.py index 254988b9a870..83ccabe5d84a 100644 --- a/plugins/audio_modem/qt.py +++ b/plugins/audio_modem/qt.py @@ -5,10 +5,10 @@ import sys import platform -from electrum.plugins import BasePlugin, hook -from electrum_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog -from electrum.util import print_msg, print_error -from electrum.i18n import _ +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog +from electrum_xzc.util import print_msg, print_error +from electrum_xzc.i18n import _ from PyQt5.QtGui import * from PyQt5.QtCore import * diff --git a/plugins/cosigner_pool/__init__.py b/plugins/cosigner_pool/__init__.py index 085b5095bfb6..64cb1055b8af 100644 --- a/plugins/cosigner_pool/__init__.py +++ b/plugins/cosigner_pool/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = _('Cosigner Pool') description = ' '.join([ _("This plugin facilitates the use of multi-signatures wallets."), diff --git a/plugins/cosigner_pool/qt.py b/plugins/cosigner_pool/qt.py index 52d6a8f3451b..4cd62454336d 100644 --- a/plugins/cosigner_pool/qt.py +++ b/plugins/cosigner_pool/qt.py @@ -30,14 +30,14 @@ from PyQt5.QtCore import * from PyQt5.QtWidgets import QPushButton -from electrum import bitcoin, util -from electrum import transaction -from electrum.plugins import BasePlugin, hook -from electrum.i18n import _ -from electrum.wallet import Multisig_Wallet -from electrum.util import bh2u, bfh +from electrum_xzc import bitcoin, util +from electrum_xzc import transaction +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc.i18n import _ +from electrum_xzc.wallet import Multisig_Wallet +from electrum_xzc.util import bh2u, bfh -from electrum_gui.qt.transaction_dialog import show_transaction +from electrum_xzc_gui.qt.transaction_dialog import show_transaction import sys import traceback @@ -162,7 +162,7 @@ def transaction_dialog_update(self, d): d.cosigner_send_button.hide() def cosigner_can_sign(self, tx, cosigner_xpub): - from electrum.keystore import is_xpubkey, parse_xpubkey + from electrum_xzc.keystore import is_xpubkey, parse_xpubkey xpub_set = set([]) for txin in tx.inputs(): for x_pubkey in txin['x_pubkeys']: @@ -194,7 +194,7 @@ def on_receive(self, keyhash, message): return wallet = window.wallet - if wallet.has_keystore_encryption(): + if wallet.has_password(): password = window.password_dialog('An encrypted transaction was retrieved from cosigning pool.\nPlease enter your password to decrypt it.') if not password: return diff --git a/plugins/digitalbitbox/__init__.py b/plugins/digitalbitbox/__init__.py index 5653d6161282..338abae25e9d 100644 --- a/plugins/digitalbitbox/__init__.py +++ b/plugins/digitalbitbox/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = 'Digital Bitbox' description = _('Provides support for Digital Bitbox hardware wallet') diff --git a/plugins/digitalbitbox/cmdline.py b/plugins/digitalbitbox/cmdline.py index 7902c98a93d7..48cd3b32b50a 100644 --- a/plugins/digitalbitbox/cmdline.py +++ b/plugins/digitalbitbox/cmdline.py @@ -1,4 +1,4 @@ -from electrum.plugins import hook +from electrum_xzc.plugins import hook from .digitalbitbox import DigitalBitboxPlugin from ..hw_wallet import CmdLineHandler diff --git a/plugins/digitalbitbox/digitalbitbox.py b/plugins/digitalbitbox/digitalbitbox.py index c57e395dd4e2..2260ac750a54 100644 --- a/plugins/digitalbitbox/digitalbitbox.py +++ b/plugins/digitalbitbox/digitalbitbox.py @@ -4,15 +4,15 @@ # try: - import electrum - from electrum.bitcoin import TYPE_ADDRESS, push_script, var_int, msg_magic, Hash, verify_message, pubkey_from_signature, point_to_ser, public_key_to_p2pkh, EncodeAES, DecodeAES, MyVerifyingKey - from electrum.bitcoin import serialize_xpub, deserialize_xpub - from electrum.transaction import Transaction - from electrum.i18n import _ - from electrum.keystore import Hardware_KeyStore + import electrum_xzc as electrum + from electrum_xzc.bitcoin import TYPE_ADDRESS, push_script, var_int, msg_magic, Hash, verify_message, pubkey_from_signature, point_to_ser, public_key_to_p2pkh, EncodeAES, DecodeAES, MyVerifyingKey + from electrum_xzc.bitcoin import serialize_xpub, deserialize_xpub + from electrum_xzc.transaction import Transaction + from electrum_xzc.i18n import _ + from electrum_xzc.keystore import Hardware_KeyStore from ..hw_wallet import HW_PluginBase - from electrum.util import print_error, to_string, UserCancelled - from electrum.base_wizard import ScriptTypeNotSupported, HWD_SETUP_NEW_WALLET + from electrum_xzc.util import print_error, to_string, UserCancelled + from electrum_xzc.base_wizard import ScriptTypeNotSupported import time import hid @@ -271,7 +271,7 @@ def mobile_pairing_dialog(self): def dbb_generate_wallet(self): key = self.stretch_key(self.password) - filename = ("Electrum-" + time.strftime("%Y-%m-%d-%H-%M-%S") + ".pdf").encode('utf8') + filename = ("Electrum-XZC-" + time.strftime("%Y-%m-%d-%H-%M-%S") + ".pdf").encode('utf8') msg = b'{"seed":{"source": "create", "key": "%s", "filename": "%s", "entropy": "%s"}}' % (key, filename, b'Digital Bitbox Electrum Plugin') reply = self.hid_send_encrypt(msg) if 'error' in reply: @@ -421,7 +421,7 @@ def give_error(self, message, clear_client = False): def decrypt_message(self, pubkey, message, password): - raise RuntimeError(_('Encryption and decryption are currently not supported for {}').format(self.device)) + raise RuntimeError(_('Encryption and decryption are currently not supported for %s') % self.device) def sign_message(self, sequence, message, password): @@ -670,13 +670,12 @@ def create_client(self, device, handler): return None - def setup_device(self, device_info, wizard, purpose): + def setup_device(self, device_info, wizard): devmgr = self.device_manager() device_id = device_info.device.id_ client = devmgr.client_by_id(device_id) client.handler = self.create_handler(wizard) - if purpose == HWD_SETUP_NEW_WALLET: - client.setupRunning = True + client.setupRunning = True client.get_xpub("m/44'/0'", 'standard') diff --git a/plugins/digitalbitbox/qt.py b/plugins/digitalbitbox/qt.py index 8930d6244852..95b6480d038f 100644 --- a/plugins/digitalbitbox/qt.py +++ b/plugins/digitalbitbox/qt.py @@ -1,9 +1,9 @@ from ..hw_wallet.qt import QtHandlerBase, QtPluginBase from .digitalbitbox import DigitalBitboxPlugin -from electrum.i18n import _ -from electrum.plugins import hook -from electrum.wallet import Standard_Wallet +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import hook +from electrum_xzc.wallet import Standard_Wallet class Plugin(DigitalBitboxPlugin, QtPluginBase): @@ -39,7 +39,7 @@ def show_address(): } self.comserver_post_notification(verify_request_payload) - menu.addAction(_("Show on {}").format(self.device), show_address) + menu.addAction(_("Show on %s") % self.device, show_address) class DigitalBitbox_Handler(QtHandlerBase): diff --git a/plugins/email_requests/__init__.py b/plugins/email_requests/__init__.py index 8c9e824725eb..ebfcbbd27ba1 100644 --- a/plugins/email_requests/__init__.py +++ b/plugins/email_requests/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = _('Email') description = _("Send and receive payment request with an email account") diff --git a/plugins/email_requests/qt.py b/plugins/email_requests/qt.py index 64061841a614..439f1afdc635 100644 --- a/plugins/email_requests/qt.py +++ b/plugins/email_requests/qt.py @@ -40,11 +40,11 @@ import PyQt5.QtGui as QtGui from PyQt5.QtWidgets import (QVBoxLayout, QLabel, QGridLayout, QLineEdit) -from electrum.plugins import BasePlugin, hook -from electrum.paymentrequest import PaymentRequest -from electrum.i18n import _ -from electrum_gui.qt.util import EnterButton, Buttons, CloseButton -from electrum_gui.qt.util import OkButton, WindowModalDialog +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc.paymentrequest import PaymentRequest +from electrum_xzc.i18n import _ +from electrum_xzc_gui.qt.util import EnterButton, Buttons, CloseButton +from electrum_xzc_gui.qt.util import OkButton, WindowModalDialog class Processor(threading.Thread): @@ -72,7 +72,7 @@ def poll(self): p = [p] continue for item in p: - if item.get_content_type() == "application/bitcoin-paymentrequest": + if item.get_content_type() == "application/zcoin-paymentrequest": pr_str = item.get_payload() pr_str = base64.b64decode(pr_str) self.on_receive(pr_str) @@ -91,10 +91,10 @@ def send(self, recipient, message, payment_request): msg['Subject'] = message msg['To'] = recipient msg['From'] = self.username - part = MIMEBase('application', "bitcoin-paymentrequest") + part = MIMEBase('application', "zcoin-paymentrequest") part.set_payload(payment_request) encode_base64(part) - part.add_header('Content-Disposition', 'attachment; filename="payreq.btc"') + part.add_header('Content-Disposition', 'attachment; filename="payreq.xzc"') msg.attach(part) s = smtplib.SMTP_SSL(self.imap_server, timeout=2) s.login(self.username, self.password) @@ -143,7 +143,7 @@ def receive_list_menu(self, menu, addr): menu.addAction(_("Send via e-mail"), lambda: self.send(window, addr)) def send(self, window, addr): - from electrum import paymentrequest + from electrum_xzc import paymentrequest r = window.wallet.receive_requests.get(addr) message = r.get('memo', '') if r.get('signature'): diff --git a/plugins/hw_wallet/cmdline.py b/plugins/hw_wallet/cmdline.py index 999f82994cfd..e3b493b54145 100644 --- a/plugins/hw_wallet/cmdline.py +++ b/plugins/hw_wallet/cmdline.py @@ -1,4 +1,4 @@ -from electrum.util import print_msg, print_error, raw_input +from electrum_xzc.util import print_msg, print_error, raw_input class CmdLineHandler: diff --git a/plugins/hw_wallet/plugin.py b/plugins/hw_wallet/plugin.py index 34573cf99f08..fc887ed018b9 100644 --- a/plugins/hw_wallet/plugin.py +++ b/plugins/hw_wallet/plugin.py @@ -24,8 +24,8 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from electrum.plugins import BasePlugin, hook -from electrum.i18n import _ +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc.i18n import _ class HW_PluginBase(BasePlugin): @@ -51,10 +51,3 @@ def close_wallet(self, wallet): for keystore in wallet.get_keystores(): if isinstance(keystore, self.keystore_class): self.device_manager().unpair_xpub(keystore.xpub) - - def setup_device(self, device_info, wizard, purpose): - """Called when creating a new wallet or when using the device to decrypt - an existing wallet. Select the device to use. If the device is - uninitialized, go through the initialization process. - """ - raise NotImplementedError() diff --git a/plugins/hw_wallet/qt.py b/plugins/hw_wallet/qt.py index d2a3bb5f3664..96a5cc740a37 100644 --- a/plugins/hw_wallet/qt.py +++ b/plugins/hw_wallet/qt.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2 # -*- mode: python -*- # # Electrum - lightweight Bitcoin client @@ -27,11 +27,11 @@ import threading from PyQt5.Qt import QVBoxLayout, QLabel -from electrum_gui.qt.password_dialog import PasswordDialog, PW_PASSPHRASE -from electrum_gui.qt.util import * +from electrum_xzc_gui.qt.password_dialog import PasswordDialog, PW_PASSPHRASE +from electrum_xzc_gui.qt.util import * -from electrum.i18n import _ -from electrum.util import PrintError +from electrum_xzc.i18n import _ +from electrum_xzc.util import PrintError # The trickiest thing about this handler was getting windows properly # parented on MacOSX. @@ -70,10 +70,9 @@ def update_status(self, paired): self.status_signal.emit(paired) def _update_status(self, paired): - if hasattr(self, 'button'): - button = self.button - icon = button.icon_paired if paired else button.icon_unpaired - button.setIcon(QIcon(icon)) + button = self.button + icon = button.icon_paired if paired else button.icon_unpaired + button.setIcon(QIcon(icon)) def query_choice(self, msg, labels): self.done.clear() @@ -144,7 +143,7 @@ def word_dialog(self, msg): def message_dialog(self, msg, on_cancel): # Called more than once during signing, to confirm output and fee self.clear_dialog() - title = _('Please check your {} device').format(self.device) + title = _('Please check your %s device') % self.device self.dialog = dialog = WindowModalDialog(self.top_level_window(), title) l = QLabel(msg) vbox = QVBoxLayout(dialog) @@ -172,9 +171,9 @@ def win_yes_no_question(self, msg): -from electrum.plugins import hook -from electrum.util import UserCancelled -from electrum_gui.qt.main_window import StatusBarButton +from electrum_xzc.plugins import hook +from electrum_xzc.util import UserCancelled +from electrum_xzc_gui.qt.main_window import StatusBarButton class QtPluginBase(object): @@ -184,12 +183,10 @@ def load_wallet(self, wallet, window): if not isinstance(keystore, self.keystore_class): continue if not self.libraries_available: - if hasattr(self, 'libraries_available_message'): - message = self.libraries_available_message + '\n' - else: - message = _("Cannot find python library for") + " '%s'.\n" % self.name - message += _("Make sure you install it with python3") - window.show_error(message) + window.show_error( + _("Cannot find python library for") + " '%s'.\n" % self.name \ + + _("Make sure you install it with python3") + ) return tooltip = self.device + '\n' + (keystore.label or 'unnamed') cb = partial(self.show_settings_dialog, window, keystore) diff --git a/plugins/keepkey/__init__.py b/plugins/keepkey/__init__.py index 0b54bc4a0db5..d14a6096679b 100644 --- a/plugins/keepkey/__init__.py +++ b/plugins/keepkey/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = 'KeepKey' description = _('Provides support for KeepKey hardware wallet') diff --git a/plugins/keepkey/clientbase.py b/plugins/keepkey/clientbase.py index 4d5cf7c85f25..c8a4f183aa3b 100644 --- a/plugins/keepkey/clientbase.py +++ b/plugins/keepkey/clientbase.py @@ -1,25 +1,25 @@ import time from struct import pack -from electrum.i18n import _ -from electrum.util import PrintError, UserCancelled -from electrum.keystore import bip39_normalize_passphrase -from electrum.bitcoin import serialize_xpub +from electrum_xzc.i18n import _ +from electrum_xzc.util import PrintError, UserCancelled +from electrum_xzc.keystore import bip39_normalize_passphrase +from electrum_xzc.bitcoin import serialize_xpub class GuiMixin(object): # Requires: self.proto, self.device messages = { - 3: _("Confirm the transaction output on your {} device"), - 4: _("Confirm internal entropy on your {} device to begin"), - 5: _("Write down the seed word shown on your {}"), - 6: _("Confirm on your {} that you want to wipe it clean"), - 7: _("Confirm on your {} device the message to sign"), + 3: _("Confirm the transaction output on your %s device"), + 4: _("Confirm internal entropy on your %s device to begin"), + 5: _("Write down the seed word shown on your %s"), + 6: _("Confirm on your %s that you want to wipe it clean"), + 7: _("Confirm on your %s device the message to sign"), 8: _("Confirm the total amount spent and the transaction fee on your " - "{} device"), - 10: _("Confirm wallet address on your {} device"), - 'default': _("Check your {} device to continue"), + "%s device"), + 10: _("Confirm wallet address on your %s device"), + 'default': _("Check your %s device to continue"), } def callback_Failure(self, msg): @@ -38,18 +38,18 @@ def callback_ButtonRequest(self, msg): message = self.msg if not message: message = self.messages.get(msg.code, self.messages['default']) - self.handler.show_message(message.format(self.device), self.cancel) + self.handler.show_message(message % self.device, self.cancel) return self.proto.ButtonAck() def callback_PinMatrixRequest(self, msg): if msg.type == 2: - msg = _("Enter a new PIN for your {}:") + msg = _("Enter a new PIN for your %s:") elif msg.type == 3: - msg = (_("Re-enter the new PIN for your {}.\n\n" + msg = (_("Re-enter the new PIN for your %s.\n\n" "NOTE: the positions of the numbers have changed!")) else: - msg = _("Enter your current {} PIN:") - pin = self.handler.get_pin(msg.format(self.device)) + msg = _("Enter your current %s PIN:") + pin = self.handler.get_pin(msg % self.device) if not pin: return self.proto.Cancel() return self.proto.PinMatrixAck(pin=pin) @@ -57,9 +57,9 @@ def callback_PinMatrixRequest(self, msg): def callback_PassphraseRequest(self, req): if self.creating_wallet: msg = _("Enter a passphrase to generate this wallet. Each time " - "you use this wallet your {} will prompt you for the " + "you use this wallet your %s will prompt you for the " "passphrase. If you forget the passphrase you cannot " - "access the bitcoins in the wallet.").format(self.device) + "access the zcoins in the wallet.") % self.device else: msg = _("Enter the passphrase to unlock this wallet:") passphrase = self.handler.get_passphrase(msg, self.creating_wallet) @@ -70,8 +70,8 @@ def callback_PassphraseRequest(self, req): def callback_WordRequest(self, msg): self.step += 1 - msg = _("Step {}/24. Enter seed word as explained on " - "your {}:").format(self.step, self.device) + msg = _("Step %d/24. Enter seed word as explained on " + "your %s:") % (self.step, self.device) word = self.handler.get_word(msg) # Unfortunately the device can't handle self.proto.Cancel() return self.proto.WordAck(word=word) @@ -155,27 +155,27 @@ def get_xpub(self, bip32_path, xtype): def toggle_passphrase(self): if self.features.passphrase_protection: - self.msg = _("Confirm on your {} device to disable passphrases") + self.msg = _("Confirm on your %s device to disable passphrases") else: - self.msg = _("Confirm on your {} device to enable passphrases") + self.msg = _("Confirm on your %s device to enable passphrases") enabled = not self.features.passphrase_protection self.apply_settings(use_passphrase=enabled) def change_label(self, label): - self.msg = _("Confirm the new label on your {} device") + self.msg = _("Confirm the new label on your %s device") self.apply_settings(label=label) def change_homescreen(self, homescreen): - self.msg = _("Confirm on your {} device to change your home screen") + self.msg = _("Confirm on your %s device to change your home screen") self.apply_settings(homescreen=homescreen) def set_pin(self, remove): if remove: - self.msg = _("Confirm on your {} device to disable PIN protection") + self.msg = _("Confirm on your %s device to disable PIN protection") elif self.features.pin_protection: - self.msg = _("Confirm on your {} device to change your PIN") + self.msg = _("Confirm on your %s device to change your PIN") else: - self.msg = _("Confirm on your {} device to set a PIN") + self.msg = _("Confirm on your %s device to set a PIN") self.change_pin(remove) def clear_session(self): diff --git a/plugins/keepkey/cmdline.py b/plugins/keepkey/cmdline.py index cd30bc0ccc03..afefd4eb288d 100644 --- a/plugins/keepkey/cmdline.py +++ b/plugins/keepkey/cmdline.py @@ -1,4 +1,4 @@ -from electrum.plugins import hook +from electrum_xzc.plugins import hook from .keepkey import KeepKeyPlugin from ..hw_wallet import CmdLineHandler diff --git a/plugins/keepkey/plugin.py b/plugins/keepkey/plugin.py index acbad49c092b..cd3cedc5221a 100644 --- a/plugins/keepkey/plugin.py +++ b/plugins/keepkey/plugin.py @@ -2,15 +2,15 @@ from binascii import hexlify, unhexlify -from electrum.util import bfh, bh2u -from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, - TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants, - is_segwit_address) -from electrum.i18n import _ -from electrum.plugins import BasePlugin -from electrum.transaction import deserialize -from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey -from electrum.base_wizard import ScriptTypeNotSupported +from electrum_xzc.util import bfh, bh2u +from electrum_xzc.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, + TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants, + is_segwit_address) +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import BasePlugin +from electrum_xzc.transaction import deserialize +from electrum_xzc.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey +from electrum_xzc.base_wizard import ScriptTypeNotSupported from ..hw_wallet import HW_PluginBase @@ -30,7 +30,7 @@ def get_client(self, force_pair=True): return self.plugin.get_client(self, force_pair) def decrypt_message(self, sequence, message, password): - raise RuntimeError(_('Encryption and decryption are not implemented by {}').format(self.device)) + raise RuntimeError(_('Encryption and decryption are not implemented by %s') % self.device) def sign_message(self, sequence, message, password): client = self.get_client() @@ -119,9 +119,9 @@ def create_client(self, device, handler): return None if not client.atleast_version(*self.minimum_firmware): - msg = (_('Outdated {} firmware for device labelled {}. Please ' - 'download the updated firmware from {}') - .format(self.device, client.label(), self.firmware_URL)) + msg = (_('Outdated %s firmware for device labelled %s. Please ' + 'download the updated firmware from %s') % + (self.device, client.label(), self.firmware_URL)) self.print_error(msg) handler.show_error(msg) return None @@ -139,18 +139,18 @@ def get_client(self, keystore, force_pair=True): return client def get_coin_name(self): - return "Testnet" if NetworkConstants.TESTNET else "Bitcoin" + return "Testnet" if NetworkConstants.TESTNET else "Zcoin" def initialize_device(self, device_id, wizard, handler): # Initialization method - msg = _("Choose how you want to initialize your {}.\n\n" + msg = _("Choose how you want to initialize your %s.\n\n" "The first two methods are secure as no secret information " "is entered into your computer.\n\n" "For the last two methods you input secrets on your keyboard " - "and upload them to your {}, and so you should " + "and upload them to your %s, and so you should " "only do those on a computer you know to be trustworthy " "and free of malware." - ).format(self.device, self.device) + ) % (self.device, self.device) choices = [ # Must be short as QT doesn't word-wrap radio button text (TIM_NEW, _("Let the device generate a completely new seed randomly")), @@ -194,7 +194,10 @@ def _initialize_device(self, settings, method, device_id, wizard, handler): label, language) wizard.loop.exit(0) - def setup_device(self, device_info, wizard, purpose): + def setup_device(self, device_info, wizard): + '''Called when creating a new wallet. Select the device to use. If + the device is uninitialized, go through the intialization + process.''' devmgr = self.device_manager() device_id = device_info.device.id_ client = devmgr.client_by_id(device_id) diff --git a/plugins/keepkey/qt_generic.py b/plugins/keepkey/qt_generic.py index a66e8f3d23f6..443c87ed7204 100644 --- a/plugins/keepkey/qt_generic.py +++ b/plugins/keepkey/qt_generic.py @@ -4,14 +4,14 @@ from PyQt5.Qt import Qt from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton from PyQt5.Qt import QVBoxLayout, QLabel -from electrum_gui.qt.util import * +from electrum_xzc_gui.qt.util import * from .plugin import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC from ..hw_wallet.qt import QtHandlerBase, QtPluginBase -from electrum.i18n import _ -from electrum.plugins import hook, DeviceMgr -from electrum.util import PrintError, UserCancelled, bh2u -from electrum.wallet import Wallet, Standard_Wallet +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import hook, DeviceMgr +from electrum_xzc.util import PrintError, UserCancelled, bh2u +from electrum_xzc.wallet import Wallet, Standard_Wallet PASSPHRASE_HELP_SHORT =_( "Passphrases allow you to access new wallets, each " @@ -23,10 +23,10 @@ "accessible behind its own passphrase.") RECOMMEND_PIN = _( "You should enable PIN protection. Your PIN is the only protection " - "for your bitcoins if your device is lost or stolen.") + "for your zcoins if your device is lost or stolen.") PASSPHRASE_NOT_PIN = _( "If you forget a passphrase you will be unable to access any " - "bitcoins in the wallet behind it. A passphrase is not a PIN. " + "zcoins in the wallet behind it. A passphrase is not a PIN. " "Only change this if you are sure you understand it.") CHARACTER_RECOVERY = ( "Use the recovery cipher shown on your device to input your seed words. " @@ -194,7 +194,7 @@ def receive_menu(self, menu, addrs, wallet): if type(keystore) == self.keystore_class and len(addrs) == 1: def show_address(): keystore.thread.add(partial(self.show_address, wallet, addrs[0])) - menu.addAction(_("Show on {}").format(self.device), show_address) + menu.addAction(_("Show on %s") % self.device, show_address) def show_settings_dialog(self, window, keystore): device_id = self.choose_device(window, keystore) @@ -227,7 +227,7 @@ def clean_text(widget): bg = QButtonGroup() for i, count in enumerate([12, 18, 24]): rb = QRadioButton(gb) - rb.setText(_("{} words").format(count)) + rb.setText(_("%d words") % count) bg.addButton(rb) bg.setId(rb, i) hbox1.addWidget(rb) @@ -242,7 +242,7 @@ def clean_text(widget): else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): - from electrum.keystore import is_xprv + from electrum_xzc.keystore import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False @@ -292,7 +292,7 @@ class SettingsDialog(WindowModalDialog): their PIN.''' def __init__(self, window, plugin, keystore, device_id): - title = _("{} Settings").format(plugin.device) + title = _("%s Settings") % plugin.device super(SettingsDialog, self).__init__(window, title) self.setMaximumWidth(540) @@ -406,7 +406,7 @@ def wipe_device(): if wallet and sum(wallet.get_balance()): title = _("Confirm Device Wipe") msg = _("Are you SURE you want to wipe the device?\n" - "Your wallet still has bitcoins in it!") + "Your wallet still has zcoins in it!") if not self.question(msg, title=title, icon=QMessageBox.Critical): return @@ -457,9 +457,9 @@ def slider_released(): settings_glayout = QGridLayout() # Settings tab - Label - label_msg = QLabel(_("Name this {}. If you have mutiple devices " + label_msg = QLabel(_("Name this %s. If you have mutiple devices " "their labels help distinguish them.") - .format(plugin.device)) + % plugin.device) label_msg.setWordWrap(True) label_label = QLabel(_("Device Label")) label_edit = QLineEdit() @@ -481,8 +481,8 @@ def slider_released(): settings_glayout.addWidget(pin_button, 2, 1) pin_msg = QLabel(_("PIN protection is strongly recommended. " "A PIN is your only protection against someone " - "stealing your bitcoins if they obtain physical " - "access to your {}.").format(plugin.device)) + "stealing your zcoins if they obtain physical " + "access to your %s.") % plugin.device) pin_msg.setWordWrap(True) pin_msg.setStyleSheet("color: red") settings_glayout.addWidget(pin_msg, 3, 1, 1, -1) @@ -497,8 +497,8 @@ def slider_released(): homescreen_clear_button.clicked.connect(clear_homescreen) homescreen_msg = QLabel(_("You can set the homescreen on your " "device to personalize it. You must " - "choose a {} x {} monochrome black and " - "white image.").format(hs_rows, hs_cols)) + "choose a %d x %d monochrome black and " + "white image.") % (hs_rows, hs_cols)) homescreen_msg.setWordWrap(True) settings_glayout.addWidget(homescreen_label, 4, 0) settings_glayout.addWidget(homescreen_change_button, 4, 1) @@ -541,7 +541,7 @@ def slider_released(): clear_pin_button.clicked.connect(clear_pin) clear_pin_warning = QLabel( _("If you disable your PIN, anyone with physical access to your " - "{} device can spend your bitcoins.").format(plugin.device)) + "%s device can spend your zcoins.") % plugin.device) clear_pin_warning.setWordWrap(True) clear_pin_warning.setStyleSheet("color: red") advanced_glayout.addWidget(clear_pin_button, 0, 2) @@ -566,7 +566,7 @@ def slider_released(): wipe_device_msg.setWordWrap(True) wipe_device_warning = QLabel( _("Only wipe a device if you have the recovery seed written down " - "and the device wallet(s) are empty, otherwise the bitcoins " + "and the device wallet(s) are empty, otherwise the zcoins " "will be lost forever.")) wipe_device_warning.setWordWrap(True) wipe_device_warning.setStyleSheet("color: red") diff --git a/plugins/labels/__init__.py b/plugins/labels/__init__.py index 759637355b09..a0e95ecd4888 100644 --- a/plugins/labels/__init__.py +++ b/plugins/labels/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = _('LabelSync') description = ' '.join([ diff --git a/plugins/labels/kivy.py b/plugins/labels/kivy.py index 508a049aeb99..42da713fc078 100644 --- a/plugins/labels/kivy.py +++ b/plugins/labels/kivy.py @@ -1,5 +1,5 @@ from .labels import LabelsPlugin -from electrum.plugins import hook +from electrum_xzc.plugins import hook class Plugin(LabelsPlugin): diff --git a/plugins/labels/labels.py b/plugins/labels/labels.py index 3e778d544f96..8439306bf646 100644 --- a/plugins/labels/labels.py +++ b/plugins/labels/labels.py @@ -7,9 +7,9 @@ import base64 -import electrum -from electrum.plugins import BasePlugin, hook -from electrum.i18n import _ +import electrum_xzc as electrum +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc.i18n import _ class LabelsPlugin(BasePlugin): diff --git a/plugins/labels/qt.py b/plugins/labels/qt.py index 5fa9ee3a0a87..51aa598b2f74 100644 --- a/plugins/labels/qt.py +++ b/plugins/labels/qt.py @@ -4,11 +4,11 @@ from PyQt5.QtCore import * from PyQt5.QtWidgets import (QHBoxLayout, QLabel, QVBoxLayout) -from electrum.plugins import hook -from electrum.i18n import _ -from electrum_gui.qt import EnterButton -from electrum_gui.qt.util import ThreadedButton, Buttons -from electrum_gui.qt.util import WindowModalDialog, OkButton +from electrum_xzc.plugins import hook +from electrum_xzc.i18n import _ +from electrum_xzc_gui.qt import EnterButton +from electrum_xzc_gui.qt.util import ThreadedButton, Buttons +from electrum_xzc_gui.qt.util import WindowModalDialog, OkButton from .labels import LabelsPlugin diff --git a/plugins/ledger/__init__.py b/plugins/ledger/__init__.py index b97f02335ca6..ab01d55958bd 100644 --- a/plugins/ledger/__init__.py +++ b/plugins/ledger/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = 'Ledger Wallet' description = 'Provides support for Ledger hardware wallet' diff --git a/plugins/ledger/auth2fa.py b/plugins/ledger/auth2fa.py index add619a82fdf..843fe6952cb4 100644 --- a/plugins/ledger/auth2fa.py +++ b/plugins/ledger/auth2fa.py @@ -4,12 +4,12 @@ import PyQt5.QtCore as QtCore from PyQt5.QtWidgets import * -from electrum.i18n import _ -from electrum_gui.qt.util import * -from electrum.util import print_msg +from electrum_xzc.i18n import _ +from electrum_xzc.qt.util import * +from electrum_xzc.util import print_msg import os, hashlib, websocket, logging, json, copy -from electrum_gui.qt.qrcodewidget import QRCodeWidget +from electrum_xzc_gui.qt.qrcodewidget import QRCodeWidget from btchip.btchip import * DEBUG = False @@ -164,7 +164,7 @@ def populate_modes(self): if not self.cfg['pair']: self.modes.addItem(_("Mobile - Not paired")) else: - self.modes.addItem(_("Mobile - {}").format(self.cfg['pair'][1])) + self.modes.addItem(_("Mobile - %s") % self.cfg['pair'][1]) self.modes.blockSignals(False) def update_dlg(self): diff --git a/plugins/ledger/cmdline.py b/plugins/ledger/cmdline.py index b0b252ac8d62..bc6f701822df 100644 --- a/plugins/ledger/cmdline.py +++ b/plugins/ledger/cmdline.py @@ -1,4 +1,4 @@ -from electrum.plugins import hook +from electrum_xzc.plugins import hook from .ledger import LedgerPlugin from ..hw_wallet import CmdLineHandler diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py index 9bab60347544..f61b066b3cad 100644 --- a/plugins/ledger/ledger.py +++ b/plugins/ledger/ledger.py @@ -3,14 +3,14 @@ import sys import traceback -from electrum import bitcoin -from electrum.bitcoin import TYPE_ADDRESS, int_to_hex, var_int -from electrum.i18n import _ -from electrum.plugins import BasePlugin -from electrum.keystore import Hardware_KeyStore -from electrum.transaction import Transaction +from electrum_xzc import bitcoin +from electrum_xzc.bitcoin import TYPE_ADDRESS, int_to_hex, var_int +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import BasePlugin +from electrum_xzc.keystore import Hardware_KeyStore +from electrum_xzc.transaction import Transaction from ..hw_wallet import HW_PluginBase -from electrum.util import print_error, is_verbose, bfh, bh2u, versiontuple +from electrum_xzc.util import print_error, is_verbose, bfh, bh2u try: import hid @@ -27,10 +27,10 @@ MSG_NEEDS_FW_UPDATE_GENERIC = _('Firmware version too old. Please update at') + \ ' https://www.ledgerwallet.com' -MSG_NEEDS_FW_UPDATE_SEGWIT = _('Firmware version (or "Bitcoin" app) too old for Segwit support. Please update at') + \ +MSG_NEEDS_FW_UPDATE_SEGWIT = _('Firmware version (or "Zcoin" app) too old for Segwit support. Please update at') + \ ' https://www.ledgerwallet.com' MULTI_OUTPUT_SUPPORT = '1.1.4' -SEGWIT_SUPPORT = '1.1.10' +SEGWIT_SUPPORT = '1.1.9' SEGWIT_SUPPORT_SPECIAL = '1.0.4' @@ -57,6 +57,9 @@ def label(self): def i4b(self, x): return pack('>I', x) + def versiontuple(self, v): + return tuple(map(int, (v.split(".")))) + def test_pin_unlocked(func): """Function decorator to test the Ledger for being unlocked, and if not, raise a human-readable exception. @@ -137,9 +140,9 @@ def perform_hw1_preflight(self): try: firmwareInfo = self.dongleObject.getFirmwareVersion() firmware = firmwareInfo['version'] - self.multiOutputSupported = versiontuple(firmware) >= versiontuple(MULTI_OUTPUT_SUPPORT) - self.nativeSegwitSupported = versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT) - self.segwitSupported = self.nativeSegwitSupported or (firmwareInfo['specialVersion'] == 0x20 and versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT_SPECIAL)) + self.multiOutputSupported = self.versiontuple(firmware) >= self.versiontuple(MULTI_OUTPUT_SUPPORT) + self.nativeSegwitSupported = self.versiontuple(firmware) >= self.versiontuple(SEGWIT_SUPPORT) + self.segwitSupported = self.nativeSegwitSupported or (firmwareInfo['specialVersion'] == 0x20 and self.versiontuple(firmware) >= self.versiontuple(SEGWIT_SUPPORT_SPECIAL)) if not checkFirmware(firmwareInfo): self.dongleObject.dongle.close() @@ -164,15 +167,12 @@ def perform_hw1_preflight(self): raise Exception('Aborted by user - please unplug the dongle and plug it again before retrying') pin = pin.encode() self.dongleObject.verifyPin(pin) + self.dongleObject.setAlternateCoinVersions(ADDRTYPE_P2PKH, ADDRTYPE_P2SH) except BTChipException as e: if (e.sw == 0x6faa): raise Exception("Dongle is temporarily locked - please unplug it and replug it again") if ((e.sw & 0xFFF0) == 0x63c0): raise Exception("Invalid PIN - please unplug the dongle and plug it again before retrying") - if e.sw == 0x6f00 and e.message == 'Invalid channel': - # based on docs 0x6f00 might be a more general error, hence we also compare message to be sure - raise Exception("Invalid channel.\n" - "Please make sure that 'Browser support' is disabled on your device.") raise e def checkDevice(self): @@ -237,7 +237,7 @@ def address_id_stripped(self, address): return address_path[2:] def decrypt_message(self, pubkey, message, password): - raise RuntimeError(_('Encryption and decryption are currently not supported for {}').format(self.device)) + raise RuntimeError(_('Encryption and decryption are currently not supported for %s') % self.device) def sign_message(self, sequence, message, password): self.signing = True @@ -523,12 +523,12 @@ def create_client(self, device, handler): client = Ledger_Client(client) return client - def setup_device(self, device_info, wizard, purpose): + def setup_device(self, device_info, wizard): devmgr = self.device_manager() device_id = device_info.device.id_ client = devmgr.client_by_id(device_id) client.handler = self.create_handler(wizard) - client.get_xpub("m/44'/0'", 'standard') # TODO replace by direct derivation once Nano S > 1.1 + client.get_xpub("m/44'/2'", 'standard') # TODO replace by direct derivation once Nano S > 1.1 def get_xpub(self, device_id, derivation, xtype, wizard): devmgr = self.device_manager() diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py index cfdd7c383a05..69c18c462d9e 100644 --- a/plugins/ledger/qt.py +++ b/plugins/ledger/qt.py @@ -2,12 +2,12 @@ from PyQt5.Qt import QInputDialog, QLineEdit, QVBoxLayout, QLabel -from electrum.i18n import _ -from electrum.plugins import hook -from electrum.wallet import Standard_Wallet +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import hook +from electrum_xzc.wallet import Standard_Wallet from .ledger import LedgerPlugin from ..hw_wallet.qt import QtHandlerBase, QtPluginBase -from electrum_gui.qt.util import * +from electrum_xzc_gui.qt.util import * #from btchip.btchipPersoWizard import StartBTChipPersoDialog diff --git a/plugins/trezor/__init__.py b/plugins/trezor/__init__.py index e3b08ed65b85..0118d8615321 100644 --- a/plugins/trezor/__init__.py +++ b/plugins/trezor/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = 'TREZOR Wallet' description = _('Provides support for TREZOR hardware wallet') diff --git a/plugins/trezor/clientbase.py b/plugins/trezor/clientbase.py index f890c59b0840..297435b6bbb4 100644 --- a/plugins/trezor/clientbase.py +++ b/plugins/trezor/clientbase.py @@ -1,25 +1,25 @@ import time from struct import pack -from electrum.i18n import _ -from electrum.util import PrintError, UserCancelled -from electrum.keystore import bip39_normalize_passphrase -from electrum.bitcoin import serialize_xpub +from electrum_xzc.i18n import _ +from electrum_xzc.util import PrintError, UserCancelled +from electrum_xzc.keystore import bip39_normalize_passphrase +from electrum_xzc.bitcoin import serialize_xpub class GuiMixin(object): # Requires: self.proto, self.device messages = { - 3: _("Confirm the transaction output on your {} device"), - 4: _("Confirm internal entropy on your {} device to begin"), - 5: _("Write down the seed word shown on your {}"), - 6: _("Confirm on your {} that you want to wipe it clean"), - 7: _("Confirm on your {} device the message to sign"), + 3: _("Confirm the transaction output on your %s device"), + 4: _("Confirm internal entropy on your %s device to begin"), + 5: _("Write down the seed word shown on your %s"), + 6: _("Confirm on your %s that you want to wipe it clean"), + 7: _("Confirm on your %s device the message to sign"), 8: _("Confirm the total amount spent and the transaction fee on your " - "{} device"), - 10: _("Confirm wallet address on your {} device"), - 'default': _("Check your {} device to continue"), + "%s device"), + 10: _("Confirm wallet address on your %s device"), + 'default': _("Check your %s device to continue"), } def callback_Failure(self, msg): @@ -38,18 +38,18 @@ def callback_ButtonRequest(self, msg): message = self.msg if not message: message = self.messages.get(msg.code, self.messages['default']) - self.handler.show_message(message.format(self.device), self.cancel) + self.handler.show_message(message % self.device, self.cancel) return self.proto.ButtonAck() def callback_PinMatrixRequest(self, msg): if msg.type == 2: - msg = _("Enter a new PIN for your {}:") + msg = _("Enter a new PIN for your %s:") elif msg.type == 3: - msg = (_("Re-enter the new PIN for your {}.\n\n" + msg = (_("Re-enter the new PIN for your %s.\n\n" "NOTE: the positions of the numbers have changed!")) else: - msg = _("Enter your current {} PIN:") - pin = self.handler.get_pin(msg.format(self.device)) + msg = _("Enter your current %s PIN:") + pin = self.handler.get_pin(msg % self.device) if not pin: return self.proto.Cancel() return self.proto.PinMatrixAck(pin=pin) @@ -57,9 +57,9 @@ def callback_PinMatrixRequest(self, msg): def callback_PassphraseRequest(self, req): if self.creating_wallet: msg = _("Enter a passphrase to generate this wallet. Each time " - "you use this wallet your {} will prompt you for the " + "you use this wallet your %s will prompt you for the " "passphrase. If you forget the passphrase you cannot " - "access the bitcoins in the wallet.").format(self.device) + "access the zcoins in the wallet.") % self.device else: msg = _("Enter the passphrase to unlock this wallet:") passphrase = self.handler.get_passphrase(msg, self.creating_wallet) @@ -70,8 +70,8 @@ def callback_PassphraseRequest(self, req): def callback_WordRequest(self, msg): self.step += 1 - msg = _("Step {}/24. Enter seed word as explained on " - "your {}:").format(self.step, self.device) + msg = _("Step %d/24. Enter seed word as explained on " + "your %s:") % (self.step, self.device) word = self.handler.get_word(msg) # Unfortunately the device can't handle self.proto.Cancel() return self.proto.WordAck(word=word) @@ -155,27 +155,27 @@ def get_xpub(self, bip32_path, xtype): def toggle_passphrase(self): if self.features.passphrase_protection: - self.msg = _("Confirm on your {} device to disable passphrases") + self.msg = _("Confirm on your %s device to disable passphrases") else: - self.msg = _("Confirm on your {} device to enable passphrases") + self.msg = _("Confirm on your %s device to enable passphrases") enabled = not self.features.passphrase_protection self.apply_settings(use_passphrase=enabled) def change_label(self, label): - self.msg = _("Confirm the new label on your {} device") + self.msg = _("Confirm the new label on your %s device") self.apply_settings(label=label) def change_homescreen(self, homescreen): - self.msg = _("Confirm on your {} device to change your home screen") + self.msg = _("Confirm on your %s device to change your home screen") self.apply_settings(homescreen=homescreen) def set_pin(self, remove): if remove: - self.msg = _("Confirm on your {} device to disable PIN protection") + self.msg = _("Confirm on your %s device to disable PIN protection") elif self.features.pin_protection: - self.msg = _("Confirm on your {} device to change your PIN") + self.msg = _("Confirm on your %s device to change your PIN") else: - self.msg = _("Confirm on your {} device to set a PIN") + self.msg = _("Confirm on your %s device to set a PIN") self.change_pin(remove) def clear_session(self): diff --git a/plugins/trezor/cmdline.py b/plugins/trezor/cmdline.py index 9149eeee444f..7161afb2810c 100644 --- a/plugins/trezor/cmdline.py +++ b/plugins/trezor/cmdline.py @@ -1,4 +1,4 @@ -from electrum.plugins import hook +from electrum_xzc.plugins import hook from .trezor import TrezorPlugin from ..hw_wallet import CmdLineHandler diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py new file mode 100644 index 000000000000..bd9e1afcd08e --- /dev/null +++ b/plugins/trezor/plugin.py @@ -0,0 +1,411 @@ +import threading + +from binascii import hexlify, unhexlify + +from electrum_xzc.util import bfh, bh2u +from electrum_xzc.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, + TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants) +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import BasePlugin +from electrum_xzc.transaction import deserialize +from electrum_xzc.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey + +from ..hw_wallet import HW_PluginBase + + +# TREZOR initialization methods +TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) + +# script "generation" +SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3) + +class TrezorCompatibleKeyStore(Hardware_KeyStore): + + def get_derivation(self): + return self.derivation + + def get_script_gen(self): + def is_p2sh_segwit(): + return self.derivation.startswith("m/49'/") + + def is_native_segwit(): + return self.derivation.startswith("m/84'/") + + if is_native_segwit(): + return SCRIPT_GEN_NATIVE_SEGWIT + elif is_p2sh_segwit(): + return SCRIPT_GEN_P2SH_SEGWIT + else: + return SCRIPT_GEN_LEGACY + + def get_client(self, force_pair=True): + return self.plugin.get_client(self, force_pair) + + def decrypt_message(self, sequence, message, password): + raise RuntimeError(_('Encryption and decryption are not implemented by %s') % self.device) + + def sign_message(self, sequence, message, password): + client = self.get_client() + address_path = self.get_derivation() + "/%d/%d"%sequence + address_n = client.expand_path(address_path) + msg_sig = client.sign_message(self.plugin.get_coin_name(), address_n, message) + return msg_sig.signature + + def sign_transaction(self, tx, password): + if tx.is_complete(): + return + # previous transactions used as inputs + prev_tx = {} + # path of the xpubs that are involved + xpub_path = {} + for txin in tx.inputs(): + pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin) + tx_hash = txin['prevout_hash'] + prev_tx[tx_hash] = txin['prev_tx'] + for x_pubkey in x_pubkeys: + if not is_xpubkey(x_pubkey): + continue + xpub, s = parse_xpubkey(x_pubkey) + if xpub == self.get_master_public_key(): + xpub_path[xpub] = self.get_derivation() + + self.plugin.sign_transaction(self, tx, prev_tx, xpub_path) + + +class TrezorCompatiblePlugin(HW_PluginBase): + # Derived classes provide: + # + # class-static variables: client_class, firmware_URL, handler_class, + # libraries_available, libraries_URL, minimum_firmware, + # wallet_class, ckd_public, types, HidTransport + + MAX_LABEL_LEN = 32 + + def __init__(self, parent, config, name): + HW_PluginBase.__init__(self, parent, config, name) + self.main_thread = threading.current_thread() + # FIXME: move to base class when Ledger is fixed + if self.libraries_available: + self.device_manager().register_devices(self.DEVICE_IDS) + + def _try_hid(self, device): + self.print_error("Trying to connect over USB...") + try: + return self.hid_transport(device) + except BaseException as e: + # see fdb810ba622dc7dbe1259cbafb5b28e19d2ab114 + # raise + self.print_error("cannot connect at", device.path, str(e)) + return None + + def _try_bridge(self, device): + self.print_error("Trying to connect over Trezor Bridge...") + try: + return self.bridge_transport({'path': hexlify(device.path)}) + except BaseException as e: + self.print_error("cannot connect to bridge", str(e)) + return None + + def create_client(self, device, handler): + # disable bridge because it seems to never returns if keepkey is plugged + #transport = self._try_bridge(device) or self._try_hid(device) + transport = self._try_hid(device) + if not transport: + self.print_error("cannot connect to device") + return + + self.print_error("connected to device at", device.path) + + client = self.client_class(transport, handler, self) + + # Try a ping for device sanity + try: + client.ping('t') + except BaseException as e: + self.print_error("ping failed", str(e)) + return None + + if not client.atleast_version(*self.minimum_firmware): + msg = (_('Outdated %s firmware for device labelled %s. Please ' + 'download the updated firmware from %s') % + (self.device, client.label(), self.firmware_URL)) + self.print_error(msg) + handler.show_error(msg) + return None + + return client + + def get_client(self, keystore, force_pair=True): + devmgr = self.device_manager() + handler = keystore.handler + with devmgr.hid_lock: + client = devmgr.client_for_keystore(self, handler, keystore, force_pair) + # returns the client for a given keystore. can use xpub + if client: + client.used() + return client + + def get_coin_name(self): + return "Testnet" if NetworkConstants.TESTNET else "Zcoin" + + def initialize_device(self, device_id, wizard, handler): + # Initialization method + msg = _("Choose how you want to initialize your %s.\n\n" + "The first two methods are secure as no secret information " + "is entered into your computer.\n\n" + "For the last two methods you input secrets on your keyboard " + "and upload them to your %s, and so you should " + "only do those on a computer you know to be trustworthy " + "and free of malware." + ) % (self.device, self.device) + choices = [ + # Must be short as QT doesn't word-wrap radio button text + (TIM_NEW, _("Let the device generate a completely new seed randomly")), + (TIM_RECOVER, _("Recover from a seed you have previously written down")), + (TIM_MNEMONIC, _("Upload a BIP39 mnemonic to generate the seed")), + (TIM_PRIVKEY, _("Upload a master private key")) + ] + def f(method): + import threading + settings = self.request_trezor_init_settings(wizard, method, self.device) + t = threading.Thread(target = self._initialize_device, args=(settings, method, device_id, wizard, handler)) + t.setDaemon(True) + t.start() + wizard.loop.exec_() + wizard.choice_dialog(title=_('Initialize Device'), message=msg, choices=choices, run_next=f) + + def _initialize_device(self, settings, method, device_id, wizard, handler): + item, label, pin_protection, passphrase_protection = settings + + if method == TIM_RECOVER: + # FIXME the PIN prompt will appear over this message + # which makes this unreadable + handler.show_error(_( + "You will be asked to enter 24 words regardless of your " + "seed's actual length. If you enter a word incorrectly or " + "misspell it, you cannot change it or go back - you will need " + "to start again from the beginning.\n\nSo please enter " + "the words carefully!")) + + language = 'english' + devmgr = self.device_manager() + client = devmgr.client_by_id(device_id) + + if method == TIM_NEW: + strength = 64 * (item + 2) # 128, 192 or 256 + u2f_counter = 0 + skip_backup = False + client.reset_device(True, strength, passphrase_protection, + pin_protection, label, language, + u2f_counter, skip_backup) + elif method == TIM_RECOVER: + word_count = 6 * (item + 2) # 12, 18 or 24 + client.step = 0 + client.recovery_device(word_count, passphrase_protection, + pin_protection, label, language) + elif method == TIM_MNEMONIC: + pin = pin_protection # It's the pin, not a boolean + client.load_device_by_mnemonic(str(item), pin, + passphrase_protection, + label, language) + else: + pin = pin_protection # It's the pin, not a boolean + client.load_device_by_xprv(item, pin, passphrase_protection, + label, language) + wizard.loop.exit(0) + + def setup_device(self, device_info, wizard): + '''Called when creating a new wallet. Select the device to use. If + the device is uninitialized, go through the intialization + process.''' + devmgr = self.device_manager() + device_id = device_info.device.id_ + client = devmgr.client_by_id(device_id) + # fixme: we should use: client.handler = wizard + client.handler = self.create_handler(wizard) + if not device_info.initialized: + self.initialize_device(device_id, wizard, client.handler) + client.get_xpub('m', 'standard') + client.used() + + def get_xpub(self, device_id, derivation, xtype, wizard): + devmgr = self.device_manager() + client = devmgr.client_by_id(device_id) + client.handler = wizard + xpub = client.get_xpub(derivation, xtype) + client.used() + return xpub + + def sign_transaction(self, keystore, tx, prev_tx, xpub_path): + self.prev_tx = prev_tx + self.xpub_path = xpub_path + client = self.get_client(keystore) + inputs = self.tx_inputs(tx, True, keystore.get_script_gen()) + outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) + signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1] + raw = bh2u(signed_tx) + tx.update_signatures(raw) + + def show_address(self, wallet, address): + client = self.get_client(wallet.keystore) + if not client.atleast_version(1, 3): + wallet.keystore.handler.show_error(_("Your device firmware is too old")) + return + change, index = wallet.get_address_index(address) + derivation = wallet.keystore.derivation + address_path = "%s/%d/%d"%(derivation, change, index) + address_n = client.expand_path(address_path) + script_gen = wallet.keystore.get_script_gen() + if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + script_type = self.types.InputScriptType.SPENDWITNESS + elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + script_type = self.types.InputScriptType.SPENDP2SHWITNESS + else: + script_type = self.types.InputScriptType.SPENDADDRESS + client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) + + def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): + inputs = [] + for txin in tx.inputs(): + txinputtype = self.types.TxInputType() + if txin['type'] == 'coinbase': + prev_hash = "\0"*32 + prev_index = 0xffffffff # signed int -1 + else: + if for_sig: + x_pubkeys = txin['x_pubkeys'] + if len(x_pubkeys) == 1: + x_pubkey = x_pubkeys[0] + xpub, s = parse_xpubkey(x_pubkey) + xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) + txinputtype._extend_address_n(xpub_n + s) + if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + txinputtype.script_type = self.types.InputScriptType.SPENDWITNESS + elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + txinputtype.script_type = self.types.InputScriptType.SPENDP2SHWITNESS + else: + txinputtype.script_type = self.types.InputScriptType.SPENDADDRESS + else: + def f(x_pubkey): + if is_xpubkey(x_pubkey): + xpub, s = parse_xpubkey(x_pubkey) + else: + xpub = xpub_from_pubkey(0, bfh(x_pubkey)) + s = [] + node = self.ckd_public.deserialize(xpub) + return self.types.HDNodePathType(node=node, address_n=s) + pubkeys = list(map(f, x_pubkeys)) + multisig = self.types.MultisigRedeemScriptType( + pubkeys=pubkeys, + signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), + m=txin.get('num_sig'), + ) + if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + script_type = self.types.InputScriptType.SPENDWITNESS + elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + script_type = self.types.InputScriptType.SPENDP2SHWITNESS + else: + script_type = self.types.InputScriptType.SPENDMULTISIG + txinputtype = self.types.TxInputType( + script_type=script_type, + multisig=multisig + ) + # find which key is mine + for x_pubkey in x_pubkeys: + if is_xpubkey(x_pubkey): + xpub, s = parse_xpubkey(x_pubkey) + if xpub in self.xpub_path: + xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) + txinputtype._extend_address_n(xpub_n + s) + break + + prev_hash = unhexlify(txin['prevout_hash']) + prev_index = txin['prevout_n'] + + if 'value' in txin: + txinputtype.amount = txin['value'] + txinputtype.prev_hash = prev_hash + txinputtype.prev_index = prev_index + + if 'scriptSig' in txin: + script_sig = bfh(txin['scriptSig']) + txinputtype.script_sig = script_sig + + txinputtype.sequence = txin.get('sequence', 0xffffffff - 1) + + inputs.append(txinputtype) + + return inputs + + def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): + outputs = [] + has_change = False + + for _type, address, amount in tx.outputs(): + info = tx.output_info.get(address) + if info is not None and not has_change: + has_change = True # no more than one change address + index, xpubs, m = info + if len(xpubs) == 1: + if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + script_type = self.types.OutputScriptType.PAYTOWITNESS + elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS + else: + script_type = self.types.OutputScriptType.PAYTOADDRESS + address_n = self.client_class.expand_path(derivation + "/%d/%d"%index) + txoutputtype = self.types.TxOutputType( + amount = amount, + script_type = script_type, + address_n = address_n, + ) + else: + if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + script_type = self.types.OutputScriptType.PAYTOWITNESS + elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS + else: + script_type = self.types.OutputScriptType.PAYTOMULTISIG + address_n = self.client_class.expand_path("/%d/%d"%index) + nodes = map(self.ckd_public.deserialize, xpubs) + pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes] + multisig = self.types.MultisigRedeemScriptType( + pubkeys = pubkeys, + signatures = [b''] * len(pubkeys), + m = m) + txoutputtype = self.types.TxOutputType( + multisig = multisig, + amount = amount, + address_n = self.client_class.expand_path(derivation + "/%d/%d"%index), + script_type = script_type) + else: + txoutputtype = self.types.TxOutputType() + txoutputtype.amount = amount + if _type == TYPE_SCRIPT: + txoutputtype.script_type = self.types.OutputScriptType.PAYTOOPRETURN + txoutputtype.op_return_data = address[2:] + elif _type == TYPE_ADDRESS: + txoutputtype.script_type = self.types.OutputScriptType.PAYTOADDRESS + txoutputtype.address = address + + outputs.append(txoutputtype) + + return outputs + + def electrum_tx_to_txtype(self, tx): + t = self.types.TransactionType() + d = deserialize(tx.raw) + t.version = d['version'] + t.lock_time = d['lockTime'] + inputs = self.tx_inputs(tx) + t._extend_inputs(inputs) + for vout in d['outputs']: + o = t._add_bin_outputs() + o.amount = vout['value'] + o.script_pubkey = bfh(vout['scriptPubKey']) + return t + + # This function is called from the trezor libraries (via tx_api) + def get_tx(self, tx_hash): + tx = self.prev_tx[tx_hash] + return self.electrum_tx_to_txtype(tx) diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py index 2440daee7672..8a3a036efbb1 100644 --- a/plugins/trezor/qt_generic.py +++ b/plugins/trezor/qt_generic.py @@ -4,14 +4,14 @@ from PyQt5.Qt import Qt from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton from PyQt5.Qt import QVBoxLayout, QLabel -from electrum_gui.qt.util import * -from .trezor import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC +from electrum_xzc_gui.qt.util import * +from .plugin import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC from ..hw_wallet.qt import QtHandlerBase, QtPluginBase -from electrum.i18n import _ -from electrum.plugins import hook, DeviceMgr -from electrum.util import PrintError, UserCancelled, bh2u -from electrum.wallet import Wallet, Standard_Wallet +from electrum_xzc.i18n import _ +from electrum_xzc.plugins import hook, DeviceMgr +from electrum_xzc.util import PrintError, UserCancelled, bh2u +from electrum_xzc.wallet import Wallet, Standard_Wallet PASSPHRASE_HELP_SHORT =_( "Passphrases allow you to access new wallets, each " @@ -23,10 +23,10 @@ "accessible behind its own passphrase.") RECOMMEND_PIN = _( "You should enable PIN protection. Your PIN is the only protection " - "for your bitcoins if your device is lost or stolen.") + "for your zcoins if your device is lost or stolen.") PASSPHRASE_NOT_PIN = _( "If you forget a passphrase you will be unable to access any " - "bitcoins in the wallet behind it. A passphrase is not a PIN. " + "zcoins in the wallet behind it. A passphrase is not a PIN. " "Only change this if you are sure you understand it.") CHARACTER_RECOVERY = ( "Use the recovery cipher shown on your device to input your seed words. " @@ -188,14 +188,13 @@ def create_handler(self, window): @hook def receive_menu(self, menu, addrs, wallet): - if len(addrs) != 1: + if type(wallet) is not Standard_Wallet: return - for keystore in wallet.get_keystores(): - if type(keystore) == self.keystore_class: - def show_address(): - keystore.thread.add(partial(self.show_address, wallet, keystore, addrs[0])) - menu.addAction(_("Show on {}").format(self.device), show_address) - break + keystore = wallet.get_keystore() + if type(keystore) == self.keystore_class and len(addrs) == 1: + def show_address(): + keystore.thread.add(partial(self.show_address, wallet, addrs[0])) + menu.addAction(_("Show on %s") % self.device, show_address) def show_settings_dialog(self, window, keystore): device_id = self.choose_device(window, keystore) @@ -243,7 +242,7 @@ def clean_text(widget): else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): - from electrum.keystore import is_xprv + from electrum_xzc.keystore import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False @@ -293,7 +292,7 @@ class SettingsDialog(WindowModalDialog): their PIN.''' def __init__(self, window, plugin, keystore, device_id): - title = _("{} Settings").format(plugin.device) + title = _("%s Settings") % plugin.device super(SettingsDialog, self).__init__(window, title) self.setMaximumWidth(540) @@ -413,7 +412,7 @@ def wipe_device(): if wallet and sum(wallet.get_balance()): title = _("Confirm Device Wipe") msg = _("Are you SURE you want to wipe the device?\n" - "Your wallet still has bitcoins in it!") + "Your wallet still has zcoins in it!") if not self.question(msg, title=title, icon=QMessageBox.Critical): return @@ -464,9 +463,9 @@ def slider_released(): settings_glayout = QGridLayout() # Settings tab - Label - label_msg = QLabel(_("Name this {}. If you have mutiple devices " + label_msg = QLabel(_("Name this %s. If you have mutiple devices " "their labels help distinguish them.") - .format(plugin.device)) + % plugin.device) label_msg.setWordWrap(True) label_label = QLabel(_("Device Label")) label_edit = QLineEdit() @@ -488,8 +487,8 @@ def slider_released(): settings_glayout.addWidget(pin_button, 2, 1) pin_msg = QLabel(_("PIN protection is strongly recommended. " "A PIN is your only protection against someone " - "stealing your bitcoins if they obtain physical " - "access to your {}.").format(plugin.device)) + "stealing your zcoins if they obtain physical " + "access to your %s.") % plugin.device) pin_msg.setWordWrap(True) pin_msg.setStyleSheet("color: red") settings_glayout.addWidget(pin_msg, 3, 1, 1, -1) @@ -504,8 +503,8 @@ def slider_released(): homescreen_clear_button.clicked.connect(clear_homescreen) homescreen_msg = QLabel(_("You can set the homescreen on your " "device to personalize it. You must " - "choose a {} x {} monochrome black and " - "white image.").format(hs_rows, hs_cols)) + "choose a %d x %d monochrome black and " + "white image.") % (hs_rows, hs_cols)) homescreen_msg.setWordWrap(True) settings_glayout.addWidget(homescreen_label, 4, 0) settings_glayout.addWidget(homescreen_change_button, 4, 1) @@ -548,7 +547,7 @@ def slider_released(): clear_pin_button.clicked.connect(clear_pin) clear_pin_warning = QLabel( _("If you disable your PIN, anyone with physical access to your " - "{} device can spend your bitcoins.").format(plugin.device)) + "%s device can spend your zcoins.") % plugin.device) clear_pin_warning.setWordWrap(True) clear_pin_warning.setStyleSheet("color: red") advanced_glayout.addWidget(clear_pin_button, 0, 2) @@ -573,7 +572,7 @@ def slider_released(): wipe_device_msg.setWordWrap(True) wipe_device_warning = QLabel( _("Only wipe a device if you have the recovery seed written down " - "and the device wallet(s) are empty, otherwise the bitcoins " + "and the device wallet(s) are empty, otherwise the zcoins " "will be lost forever.")) wipe_device_warning.setWordWrap(True) wipe_device_warning.setStyleSheet("color: red") diff --git a/plugins/trezor/trezor.py b/plugins/trezor/trezor.py index f80346c71ac3..5ee31d390e96 100644 --- a/plugins/trezor/trezor.py +++ b/plugins/trezor/trezor.py @@ -1,451 +1,36 @@ -import threading +from .plugin import TrezorCompatiblePlugin, TrezorCompatibleKeyStore -from binascii import hexlify, unhexlify -from electrum.util import bfh, bh2u, versiontuple -from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey, - TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants) -from electrum.i18n import _ -from electrum.plugins import BasePlugin, Device -from electrum.transaction import deserialize -from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey - -from ..hw_wallet import HW_PluginBase - - -# TREZOR initialization methods -TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) - -# script "generation" -SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3) - - -class TrezorKeyStore(Hardware_KeyStore): +class TrezorKeyStore(TrezorCompatibleKeyStore): hw_type = 'trezor' device = 'TREZOR' - def get_derivation(self): - return self.derivation - - def get_script_gen(self): - def is_p2sh_segwit(): - return self.derivation.startswith("m/49'/") - - def is_native_segwit(): - return self.derivation.startswith("m/84'/") - - if is_native_segwit(): - return SCRIPT_GEN_NATIVE_SEGWIT - elif is_p2sh_segwit(): - return SCRIPT_GEN_P2SH_SEGWIT - else: - return SCRIPT_GEN_LEGACY - - def get_client(self, force_pair=True): - return self.plugin.get_client(self, force_pair) - - def decrypt_message(self, sequence, message, password): - raise RuntimeError(_('Encryption and decryption are not implemented by {}').format(self.device)) - - def sign_message(self, sequence, message, password): - client = self.get_client() - address_path = self.get_derivation() + "/%d/%d"%sequence - address_n = client.expand_path(address_path) - msg_sig = client.sign_message(self.plugin.get_coin_name(), address_n, message) - return msg_sig.signature - - def sign_transaction(self, tx, password): - if tx.is_complete(): - return - # previous transactions used as inputs - prev_tx = {} - # path of the xpubs that are involved - xpub_path = {} - for txin in tx.inputs(): - pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin) - tx_hash = txin['prevout_hash'] - prev_tx[tx_hash] = txin['prev_tx'] - for x_pubkey in x_pubkeys: - if not is_xpubkey(x_pubkey): - continue - xpub, s = parse_xpubkey(x_pubkey) - if xpub == self.get_master_public_key(): - xpub_path[xpub] = self.get_derivation() - - self.plugin.sign_transaction(self, tx, prev_tx, xpub_path) - - -class TrezorPlugin(HW_PluginBase): - # Derived classes provide: - # - # class-static variables: client_class, firmware_URL, handler_class, - # libraries_available, libraries_URL, minimum_firmware, - # wallet_class, ckd_public, types - +class TrezorPlugin(TrezorCompatiblePlugin): firmware_URL = 'https://wallet.trezor.io' libraries_URL = 'https://github.com/trezor/python-trezor' minimum_firmware = (1, 5, 2) keystore_class = TrezorKeyStore - minimum_library = (0, 9, 0) - - MAX_LABEL_LEN = 32 - - def __init__(self, parent, config, name): - HW_PluginBase.__init__(self, parent, config, name) - self.main_thread = threading.current_thread() + def __init__(self, *args): try: - # Minimal test if python-trezor is installed + from . import client import trezorlib - try: - library_version = trezorlib.__version__ - except AttributeError: - # python-trezor only introduced __version__ in 0.9.0 - library_version = 'unknown' - if library_version == 'unknown' or \ - versiontuple(library_version) < self.minimum_library: - self.libraries_available_message = ( - _("Library version for '{}' is too old.").format(name) - + '\nInstalled: {}, Needed: {}' - .format(library_version, self.minimum_library)) - self.print_stderr(self.libraries_available_message) - raise ImportError() + import trezorlib.ckd_public + import trezorlib.transport_hid + import trezorlib.messages + self.client_class = client.TrezorClient + self.ckd_public = trezorlib.ckd_public + self.types = trezorlib.messages + self.DEVICE_IDS = (trezorlib.transport_hid.DEV_TREZOR1, trezorlib.transport_hid.DEV_TREZOR2) self.libraries_available = True except ImportError: self.libraries_available = False - return - - from . import client - import trezorlib.ckd_public - import trezorlib.messages - self.client_class = client.TrezorClient - self.ckd_public = trezorlib.ckd_public - self.types = trezorlib.messages - self.DEVICE_IDS = ('TREZOR',) - - self.device_manager().register_enumerate_func(self.enumerate) - - def enumerate(self): - from trezorlib.device import TrezorDevice - return [Device(d.get_path(), -1, d.get_path(), 'TREZOR', 0) for d in TrezorDevice.enumerate()] - - def create_client(self, device, handler): - from trezorlib.device import TrezorDevice - try: - self.print_error("connecting to device at", device.path) - transport = TrezorDevice.find_by_path(device.path) - except BaseException as e: - self.print_error("cannot connect at", device.path, str(e)) - return None - - if not transport: - self.print_error("cannot connect at", device.path) - return - - self.print_error("connected to device at", device.path) - client = self.client_class(transport, handler, self) - - # Try a ping for device sanity - try: - client.ping('t') - except BaseException as e: - self.print_error("ping failed", str(e)) - return None - - if not client.atleast_version(*self.minimum_firmware): - msg = (_('Outdated {} firmware for device labelled {}. Please ' - 'download the updated firmware from {}') - .format(self.device, client.label(), self.firmware_URL)) - self.print_error(msg) - handler.show_error(msg) - return None - - return client - - def get_client(self, keystore, force_pair=True): - devmgr = self.device_manager() - handler = keystore.handler - with devmgr.hid_lock: - client = devmgr.client_for_keystore(self, handler, keystore, force_pair) - # returns the client for a given keystore. can use xpub - if client: - client.used() - return client - - def get_coin_name(self): - return "Testnet" if NetworkConstants.TESTNET else "Bitcoin" - - def initialize_device(self, device_id, wizard, handler): - # Initialization method - msg = _("Choose how you want to initialize your {}.\n\n" - "The first two methods are secure as no secret information " - "is entered into your computer.\n\n" - "For the last two methods you input secrets on your keyboard " - "and upload them to your {}, and so you should " - "only do those on a computer you know to be trustworthy " - "and free of malware." - ).format(self.device, self.device) - choices = [ - # Must be short as QT doesn't word-wrap radio button text - (TIM_NEW, _("Let the device generate a completely new seed randomly")), - (TIM_RECOVER, _("Recover from a seed you have previously written down")), - (TIM_MNEMONIC, _("Upload a BIP39 mnemonic to generate the seed")), - (TIM_PRIVKEY, _("Upload a master private key")) - ] - def f(method): - import threading - settings = self.request_trezor_init_settings(wizard, method, self.device) - t = threading.Thread(target = self._initialize_device, args=(settings, method, device_id, wizard, handler)) - t.setDaemon(True) - t.start() - wizard.loop.exec_() - wizard.choice_dialog(title=_('Initialize Device'), message=msg, choices=choices, run_next=f) - - def _initialize_device(self, settings, method, device_id, wizard, handler): - item, label, pin_protection, passphrase_protection = settings - - if method == TIM_RECOVER: - # FIXME the PIN prompt will appear over this message - # which makes this unreadable - handler.show_error(_( - "You will be asked to enter 24 words regardless of your " - "seed's actual length. If you enter a word incorrectly or " - "misspell it, you cannot change it or go back - you will need " - "to start again from the beginning.\n\nSo please enter " - "the words carefully!")) - - language = 'english' - devmgr = self.device_manager() - client = devmgr.client_by_id(device_id) - - if method == TIM_NEW: - strength = 64 * (item + 2) # 128, 192 or 256 - u2f_counter = 0 - skip_backup = False - client.reset_device(True, strength, passphrase_protection, - pin_protection, label, language, - u2f_counter, skip_backup) - elif method == TIM_RECOVER: - word_count = 6 * (item + 2) # 12, 18 or 24 - client.step = 0 - client.recovery_device(word_count, passphrase_protection, - pin_protection, label, language) - elif method == TIM_MNEMONIC: - pin = pin_protection # It's the pin, not a boolean - client.load_device_by_mnemonic(str(item), pin, - passphrase_protection, - label, language) - else: - pin = pin_protection # It's the pin, not a boolean - client.load_device_by_xprv(item, pin, passphrase_protection, - label, language) - wizard.loop.exit(0) - - def setup_device(self, device_info, wizard, purpose): - devmgr = self.device_manager() - device_id = device_info.device.id_ - client = devmgr.client_by_id(device_id) - # fixme: we should use: client.handler = wizard - client.handler = self.create_handler(wizard) - if not device_info.initialized: - self.initialize_device(device_id, wizard, client.handler) - client.get_xpub('m', 'standard') - client.used() - - def get_xpub(self, device_id, derivation, xtype, wizard): - devmgr = self.device_manager() - client = devmgr.client_by_id(device_id) - client.handler = wizard - xpub = client.get_xpub(derivation, xtype) - client.used() - return xpub - - def sign_transaction(self, keystore, tx, prev_tx, xpub_path): - self.prev_tx = prev_tx - self.xpub_path = xpub_path - client = self.get_client(keystore) - inputs = self.tx_inputs(tx, True, keystore.get_script_gen()) - outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) - signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1] - raw = bh2u(signed_tx) - tx.update_signatures(raw) - - def show_address(self, wallet, keystore, address): - client = self.get_client(keystore) - if not client.atleast_version(1, 3): - keystore.handler.show_error(_("Your device firmware is too old")) - return - change, index = wallet.get_address_index(address) - derivation = keystore.derivation - address_path = "%s/%d/%d"%(derivation, change, index) - address_n = client.expand_path(address_path) - xpubs = wallet.get_master_public_keys() - if len(xpubs) == 1: - script_gen = keystore.get_script_gen() - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.InputScriptType.SPENDWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.InputScriptType.SPENDP2SHWITNESS - else: - script_type = self.types.InputScriptType.SPENDADDRESS - client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) - else: - def f(xpub): - node = self.ckd_public.deserialize(xpub) - return self.types.HDNodePathType(node=node, address_n=[change, index]) - pubkeys = wallet.get_public_keys(address) - # sort xpubs using the order of pubkeys - sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs))) - pubkeys = list(map(f, sorted_xpubs)) - multisig = self.types.MultisigRedeemScriptType( - pubkeys=pubkeys, - signatures=[b''] * wallet.n, - m=wallet.m, - ) - client.get_address(self.get_coin_name(), address_n, True, multisig=multisig) - - def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): - inputs = [] - for txin in tx.inputs(): - txinputtype = self.types.TxInputType() - if txin['type'] == 'coinbase': - prev_hash = "\0"*32 - prev_index = 0xffffffff # signed int -1 - else: - if for_sig: - x_pubkeys = txin['x_pubkeys'] - if len(x_pubkeys) == 1: - x_pubkey = x_pubkeys[0] - xpub, s = parse_xpubkey(x_pubkey) - xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) - txinputtype._extend_address_n(xpub_n + s) - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - txinputtype.script_type = self.types.InputScriptType.SPENDWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - txinputtype.script_type = self.types.InputScriptType.SPENDP2SHWITNESS - else: - txinputtype.script_type = self.types.InputScriptType.SPENDADDRESS - else: - def f(x_pubkey): - if is_xpubkey(x_pubkey): - xpub, s = parse_xpubkey(x_pubkey) - else: - xpub = xpub_from_pubkey(0, bfh(x_pubkey)) - s = [] - node = self.ckd_public.deserialize(xpub) - return self.types.HDNodePathType(node=node, address_n=s) - pubkeys = list(map(f, x_pubkeys)) - multisig = self.types.MultisigRedeemScriptType( - pubkeys=pubkeys, - signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), - m=txin.get('num_sig'), - ) - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.InputScriptType.SPENDWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.InputScriptType.SPENDP2SHWITNESS - else: - script_type = self.types.InputScriptType.SPENDMULTISIG - txinputtype = self.types.TxInputType( - script_type=script_type, - multisig=multisig - ) - # find which key is mine - for x_pubkey in x_pubkeys: - if is_xpubkey(x_pubkey): - xpub, s = parse_xpubkey(x_pubkey) - if xpub in self.xpub_path: - xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) - txinputtype._extend_address_n(xpub_n + s) - break - - prev_hash = unhexlify(txin['prevout_hash']) - prev_index = txin['prevout_n'] - - if 'value' in txin: - txinputtype.amount = txin['value'] - txinputtype.prev_hash = prev_hash - txinputtype.prev_index = prev_index - - if 'scriptSig' in txin: - script_sig = bfh(txin['scriptSig']) - txinputtype.script_sig = script_sig - - txinputtype.sequence = txin.get('sequence', 0xffffffff - 1) - - inputs.append(txinputtype) - - return inputs - - def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): - outputs = [] - has_change = False - - for _type, address, amount in tx.outputs(): - info = tx.output_info.get(address) - if info is not None and not has_change: - has_change = True # no more than one change address - index, xpubs, m = info - if len(xpubs) == 1: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOADDRESS - address_n = self.client_class.expand_path(derivation + "/%d/%d"%index) - txoutputtype = self.types.TxOutputType( - amount = amount, - script_type = script_type, - address_n = address_n, - ) - else: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOMULTISIG - address_n = self.client_class.expand_path("/%d/%d"%index) - nodes = map(self.ckd_public.deserialize, xpubs) - pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes] - multisig = self.types.MultisigRedeemScriptType( - pubkeys = pubkeys, - signatures = [b''] * len(pubkeys), - m = m) - txoutputtype = self.types.TxOutputType( - multisig = multisig, - amount = amount, - address_n = self.client_class.expand_path(derivation + "/%d/%d"%index), - script_type = script_type) - else: - txoutputtype = self.types.TxOutputType() - txoutputtype.amount = amount - if _type == TYPE_SCRIPT: - txoutputtype.script_type = self.types.OutputScriptType.PAYTOOPRETURN - txoutputtype.op_return_data = address[2:] - elif _type == TYPE_ADDRESS: - txoutputtype.script_type = self.types.OutputScriptType.PAYTOADDRESS - txoutputtype.address = address - - outputs.append(txoutputtype) - - return outputs + TrezorCompatiblePlugin.__init__(self, *args) - def electrum_tx_to_txtype(self, tx): - t = self.types.TransactionType() - d = deserialize(tx.raw) - t.version = d['version'] - t.lock_time = d['lockTime'] - inputs = self.tx_inputs(tx) - t._extend_inputs(inputs) - for vout in d['outputs']: - o = t._add_bin_outputs() - o.amount = vout['value'] - o.script_pubkey = bfh(vout['scriptPubKey']) - return t + def hid_transport(self, device): + from trezorlib.transport_hid import HidTransport + return HidTransport.find_by_path(device.path) - # This function is called from the trezor libraries (via tx_api) - def get_tx(self, tx_hash): - tx = self.prev_tx[tx_hash] - return self.electrum_tx_to_txtype(tx) + def bridge_transport(self, d): + from trezorlib.transport_bridge import BridgeTransport + return BridgeTransport(d) diff --git a/plugins/virtualkeyboard/__init__.py b/plugins/virtualkeyboard/__init__.py index c24f19b1a3cf..53c05f17c9f1 100644 --- a/plugins/virtualkeyboard/__init__.py +++ b/plugins/virtualkeyboard/__init__.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_xzc.i18n import _ fullname = 'Virtual Keyboard' description = '%s\n%s' % (_("Add an optional virtual keyboard to the password dialog."), _("Warning: do not use this if it makes you pick a weaker password.")) diff --git a/plugins/virtualkeyboard/qt.py b/plugins/virtualkeyboard/qt.py index 6918aa6e1a8b..ba28bb94abcc 100644 --- a/plugins/virtualkeyboard/qt.py +++ b/plugins/virtualkeyboard/qt.py @@ -1,7 +1,7 @@ from PyQt5.QtGui import * from PyQt5.QtWidgets import (QVBoxLayout, QGridLayout, QPushButton) -from electrum.plugins import BasePlugin, hook -from electrum.i18n import _ +from electrum_xzc.plugins import BasePlugin, hook +from electrum_xzc.i18n import _ import random diff --git a/pubkeys/pooler.asc b/pubkeys/pooler.asc new file mode 100644 index 000000000000..ba5df48110b7 --- /dev/null +++ b/pubkeys/pooler.asc @@ -0,0 +1,44 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: SKS 1.1.5 +Comment: Hostname: pgp.mit.edu + +mQENBFHrqicBCACzAWyV0sxcYxbDC5Y+zEFG2n6wxuKVx4GY4uC9FSXvHvyyJ5pVusDReqsq +zC4g0DmtLOP8ewXSTyWVW07DlNvDt1qfD3gp4WD1QCkPp/gcmHz54gH5v8Tvlq0k/OC1avn2 +BshHUCwWMc4xAU76aJvnjFhxLjlgKBpPB8DV7fFEl6+1OVdoMdfJXJXk3FNioqNi8RAkme7u +cHjnXycQzX6aITw7F3KWp13P2qLNUjHdf6y6YiIaRHqCXA3/78VRmceH9Q+t9wJ4LZrK4jno +YjNMV8sXT4kK/PO7yLc7lQkXCrythfdTayLZ/5W7zMaR3Xs9V+Q3WdRc9iMYmwln2wJ7ABEB +AAG0IHBvb2xlciA8cG9vbGVyQGxpdGVjb2lucG9vbC5vcmc+iQEcBBABAgAGBQJUIt3GAAoJ +EKUn2d0jII5a03sH/iolWAdRdhtYBPK18LFRTA1425QU/5DTDByBMA79XiSsCgXtOg7d5Pm9 +XhRM85kjufKDn5sG8KOun9EK00DhsYkKt8ii3Elh3L+iGHHyOWUjdmQChWjL5CF/rA1zkloJ +voB7KdYhgKayw4xYbMQ6Z9zWghZXgHilwaeGUkXjREKtNE7O95+kmaK/H47LolwCHiK3QArT +BMB9rEOI0140dktOMMIzgA7XjVn0vf6VUOXcbspeQAnYBmvk1x/QOprEpFdOmp1ZeuR09olq +V7rLOMi3ah+6s5SJfv8ePgRDAY/4m0qOGcecGfys/dFLKKMrQfR6L0aG9E1CncSU/2cYgLqJ +ATgEEwECACIFAlHrqicCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEG/Eyffxvo/q +RH4H/jYJf9AZDlTXSVcQo+wy43Yq/K40l3bQQv+240QXDQFt8/1vN78RY3mDpc9y2Fq3LVpT +DBeAFxD+2WEbzxdCa4pMf8xt49+43c1p3pTOWGGPhe3pCQ2sf4h8APvCMCAQXMg4c0DRHFe4 +92Lxm/s7D383OKZKcG4pJXmseddU2oSIf1NG8LZ6YRKihFQeUJLu/ra505Ir4aNHZ2x8T/JU +5Mz809sTnAkFOXLRtxIAhpI7yp0KXotIkKTkkdD8u90rkzfw3bat/dLyHnab55tKf7sYG7cj +lam4g2r1mJ4OUqGLx3Ew+29ib3+5zB+MA1m4WNA7k/njgzNm4H/rsPoaWH6JAhwEEwECAAYF +AlNvSNAACgkQgorB+U7yYFM27A/+KXDqwKe7WsS0V8TBBpuZE1lNegL8WTN2Y90Dw3/7i5DN +x92tCMVXB6doBFC5o08lggFYXuBtC+uMcnOHJOKl8xfZ5QYJTBGD45kQeJ9pPzHs3cbb9dDE +7iH4PjPxLI/X/wftFKIf599h+TPFAIJWbYu1wOqBsCGsVeONBRt8MeagJBbaYoE4hyoBWDbS +7o/2YHwdLijnpze8sbjf4DjqT9lr6MR1fKwdZEwk/mEg5HBGFR7OnLpBcw6nwXiqM4+0suno +KRAxzhNA0yjrOlTwrlovddsgkNU/Ln5Jl2Y5jlmoLh55Z/fSPeLanQsDGCOsai8HtVyuM/xe +2+czBus5v22ipiWp7L+v2B+PRCJLyo49RjbNd1EzAflXR+bG76f36ctUpSrgxgqIo7cjpxFi +iwfs31W9VKQ3LYDA5Ag5aGvV6jrZBaqfTRZks6g6lSatOcCoxetnLobrS9qxetsye0mNSOpM +QhdL6cFz2L9dqBkfcokizbffO3m7tjK11sgCXOlyQNA8vontKfxqZbkkQIG4uVRS+abSgqzu +Vnh9udeDfOpiGxKpJl5eD4EUaB2WtfyLAH5SiIE5gwd5c8/a1t0YmAAwsioZGAjYGoKFGQqI +g7Js2cDF6+OX6mAOnM5E6qUgmbiw+ewOmpIXztLaVzO9KUEmLmUsyQ4JVFSjBqe5AQ0EUeuq +JwEIAN/ax0gIitrxBguJNmb96vTXq09U88uxuh22dlzHISDXGJ2SaBjGlP97nDhhdmJGwHtU +NmVophd9bc0axdjohs3v/dtSyNFhAdq4OLn7hX5YFwYLuyZtA0J8iw+45KoQC3uymPaqskrx +bM/NaJu805Dt7md70d+BLt9vNJTb+e5iCVVmBZhk9Z9ADIywT7bX7EtHMK7rfE5YFzzbRtEo +EgrvJ0iLRkKmqKT69nEt54tBspyVwW1v4eJy5pIKedoeJ70YJlZRzOgSEVDhMLl3f6w1llpJ +hdsNJzk9qL+vABrvDeJJKFXq8pLV6SXoBi/46KAczxtBjwF9NIgJAC2KLM8AEQEAAYkBHwQY +AQIACQUCUeuqJwIbDAAKCRBvxMn38b6P6nP9B/0RO/ECyvYyoQhGwiWYv2FSxhwjbaOF2zMt +qjoFmnDl1OQ4qrAxSHhAxyKlUQQGnyzyx7PTEffkvuNLRr7jUrrG4wcQOOpojNpDLDnblvCk +btg/UpL2n7LC9CIjnPlX96F2Zjo9fyF03KxS2Z6u3XPSHO9gMaVnhqKv6o79X42k4WJLxiKg +oVH3rZsGOZglmgc0HwEbTVT1p8Skdf+VUMYO5ACiiUPv8iq7htegOn8eo0wwvu8sTnX0Xmpc +aNa1xLDtoo3jWyrdrsR5Rz3MQX85r8adWjpnHYxtnrUtmBvNwYGS/jfTvqPBWxLG0OHo3NNb +BwcU0VFUcdtQwcB4KXxZ +=Vz9L +-----END PGP PUBLIC KEY BLOCK----- diff --git a/requirements_travis.txt b/requirements_travis.txt new file mode 100644 index 000000000000..b0aaeff51c85 --- /dev/null +++ b/requirements_travis.txt @@ -0,0 +1,3 @@ +tox +python-coveralls +tox-travis diff --git a/scripts/bip70 b/scripts/bip70 index 2e04bfe76f03..789edcd8f9ec 100755 --- a/scripts/bip70 +++ b/scripts/bip70 @@ -3,14 +3,14 @@ import tlslite -from electrum.transaction import Transaction -from electrum import paymentrequest -from electrum import paymentrequest_pb2 as pb2 +from electrum_xzc.transaction import Transaction +from electrum_xzc import paymentrequest +from electrum_xzc import paymentrequest_pb2 as pb2 chain_file = 'mychain.pem' cert_file = 'mycert.pem' amount = 1000000 -address = "18U5kpCAU4s8weFF8Ps5n8HAfpdUjDVF64" +address = "LSh322VzYj7CCSwQJXrP49Lvt2zktLjQbz" memo = "blah" out_file = "payreq" diff --git a/scripts/block_headers b/scripts/block_headers index 82f6b100f42c..25d65c1795be 100755 --- a/scripts/block_headers +++ b/scripts/block_headers @@ -3,8 +3,8 @@ # A simple script that connects to a server and displays block headers import time -from electrum import SimpleConfig, Network -from electrum.util import print_msg, json_encode +from electrum_xzc import SimpleConfig, Network +from electrum_xzc.util import print_msg, json_encode # start network c = SimpleConfig() diff --git a/scripts/get_history b/scripts/get_history index b78fcc58af69..90af86b9d198 100755 --- a/scripts/get_history +++ b/scripts/get_history @@ -1,14 +1,14 @@ #!/usr/bin/env python3 import sys -from electrum import Network -from electrum.util import json_encode, print_msg -from electrum import bitcoin +from electrum_xzc import Network +from electrum_xzc.util import json_encode, print_msg +from electrum_xzc import bitcoin try: addr = sys.argv[1] except Exception: - print("usage: get_history ") + print("usage: get_history ") sys.exit(1) n = Network() diff --git a/scripts/peers b/scripts/peers index 773926915fa3..b7e13e4cb2c4 100755 --- a/scripts/peers +++ b/scripts/peers @@ -2,8 +2,8 @@ import util -from electrum.network import filter_protocol -from electrum.blockchain import hash_header +from electrum_xzc.network import filter_protocol +from electrum_xzc.blockchain import hash_header peers = util.get_peers() peers = filter_protocol(peers, 's') diff --git a/scripts/servers b/scripts/servers index 1f8cc6826fdc..e3f4dc8f66d5 100755 --- a/scripts/servers +++ b/scripts/servers @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -from electrum import set_verbosity -from electrum.network import filter_version +from electrum_xzc import set_verbosity +from electrum_xzc.network import filter_version import util, json set_verbosity(False) diff --git a/scripts/util.py b/scripts/util.py index db14a384dd9a..3b4b83ce36a9 100644 --- a/scripts/util.py +++ b/scripts/util.py @@ -1,8 +1,8 @@ import select, time, queue -# import electrum -from electrum import Connection, Interface, SimpleConfig +# import electrum_xzc as electrum +from electrum_xzc import Connection, Interface, SimpleConfig -from electrum.network import parse_servers +from electrum_xzc.network import parse_servers from collections import defaultdict # electrum.util.set_verbosity(1) diff --git a/scripts/watch_address b/scripts/watch_address index 461e41863017..4df8d8e390fb 100755 --- a/scripts/watch_address +++ b/scripts/watch_address @@ -2,13 +2,13 @@ import sys import time -from electrum import SimpleConfig, Network -from electrum.util import print_msg, json_encode +from electrum_xzc import SimpleConfig, Network +from electrum_xzc.util import print_msg, json_encode try: addr = sys.argv[1] except Exception: - print("usage: watch_address ") + print("usage: watch_address ") sys.exit(1) # start network diff --git a/setup.py b/setup.py index 63581a614106..20a903906284 100755 --- a/setup.py +++ b/setup.py @@ -9,18 +9,12 @@ import imp import argparse -with open('contrib/requirements/requirements.txt') as f: - requirements = f.read().splitlines() - -with open('contrib/requirements/requirements-hw.txt') as f: - requirements_hw = f.read().splitlines() - version = imp.load_source('version', 'lib/version.py') if sys.version_info[:3] < (3, 4, 0): sys.exit("Error: Electrum requires Python version >= 3.4.0...") -data_files = ['contrib/requirements/' + r for r in ['requirements.txt', 'requirements-hw.txt']] +data_files = [] if platform.system() in ['Linux', 'FreeBSD', 'DragonFly']: parser = argparse.ArgumentParser() @@ -34,42 +28,48 @@ else: usr_share = os.path.expanduser('~/.local/share') data_files += [ - (os.path.join(usr_share, 'applications/'), ['electrum.desktop']), - (os.path.join(usr_share, 'pixmaps/'), ['icons/electrum.png']) + (os.path.join(usr_share, 'applications/'), ['electrum-xzc.desktop']), + (os.path.join(usr_share, 'pixmaps/'), ['icons/electrum-xzc.png']) ] setup( - name="Electrum", + name="Electrum-XZC", version=version.ELECTRUM_VERSION, - install_requires=requirements, - extras_require={ - 'hardware': requirements_hw, - }, + install_requires=[ + 'pyaes>=0.1a1', + 'ecdsa>=0.9', + 'pbkdf2', + 'requests', + 'qrcode', + 'scrypt>=0.6.0', + 'protobuf', + 'dnspython', + 'jsonrpclib-pelix', + 'PySocks>=1.6.6', + ], packages=[ - 'electrum', - 'electrum_gui', - 'electrum_gui.qt', - 'electrum_plugins', - 'electrum_plugins.audio_modem', - 'electrum_plugins.cosigner_pool', - 'electrum_plugins.email_requests', - 'electrum_plugins.greenaddress_instant', - 'electrum_plugins.hw_wallet', - 'electrum_plugins.keepkey', - 'electrum_plugins.labels', - 'electrum_plugins.ledger', - 'electrum_plugins.trezor', - 'electrum_plugins.digitalbitbox', - 'electrum_plugins.trustedcoin', - 'electrum_plugins.virtualkeyboard', + 'electrum_xzc', + 'electrum_xzc_gui', + 'electrum_xzc_gui.qt', + 'electrum_xzc_plugins', + 'electrum_xzc_plugins.audio_modem', + 'electrum_xzc_plugins.cosigner_pool', + 'electrum_xzc_plugins.email_requests', + 'electrum_xzc_plugins.hw_wallet', + 'electrum_xzc_plugins.keepkey', + 'electrum_xzc_plugins.labels', + 'electrum_xzc_plugins.ledger', + 'electrum_xzc_plugins.trezor', + 'electrum_xzc_plugins.digitalbitbox', + 'electrum_xzc_plugins.virtualkeyboard', ], package_dir={ - 'electrum': 'lib', - 'electrum_gui': 'gui', - 'electrum_plugins': 'plugins', + 'electrum_xzc': 'lib', + 'electrum_xzc_gui': 'gui', + 'electrum_xzc_plugins': 'plugins', }, package_data={ - 'electrum': [ + 'electrum_xzc': [ 'servers.json', 'servers_testnet.json', 'currencies.json', @@ -80,12 +80,12 @@ 'locale/*/LC_MESSAGES/electrum.mo', ] }, - scripts=['electrum'], + scripts=['electrum-xzc'], data_files=data_files, - description="Lightweight Bitcoin Wallet", + description="Lightweight Zcoin Wallet", author="Thomas Voegtlin", author_email="thomasv@electrum.org", license="MIT Licence", - url="https://electrum.org", - long_description="""Lightweight Bitcoin Wallet""" + url="http://electrum-xzc.org", + long_description="""Lightweight Zcoin Wallet""" ) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 5c3fcf18f0b1..c437dfb89bdd 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,23 +1,23 @@ -name: electrum +name: electrum-xzc version: master -summary: Bitcoin thin client +summary: Zcoin thin client description: | - Lightweight Bitcoin client + Lightweight Zcoin client grade: devel # must be 'stable' to release into candidate/stable channels confinement: strict apps: - electrum: - command: desktop-launch electrum + electrum-xzc: + command: desktop-launch electrum-xzc plugs: [network, network-bind, x11, unity7] parts: - electrum: + electrum-xzc: source: . plugin: python python-version: python3 stage-packages: [python3-pyqt5] build-packages: [pyqt5-dev-tools] - install: pyrcc5 icons.qrc -o $SNAPCRAFT_PART_INSTALL/lib/python3.5/site-packages/electrum_gui/qt/icons_rc.py + install: pyrcc5 icons.qrc -o $SNAPCRAFT_PART_INSTALL/lib/python3.5/site-packages/electrum_xzc_gui/qt/icons_rc.py after: [desktop-qt5]