diff --git a/.gitignore b/.gitignore index f3f2b590..07865821 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ dist/ *.egg/ contrib/pyinstaller/ Electrum.egg-info/ -locale/ +electrum/locale/ .devlocaltmp/ *_trial_temp packages diff --git a/MANIFEST.in b/MANIFEST.in index d09f4f5d..7caf98b0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include LICENCE RELEASE-NOTES AUTHORS include README.rst -include electrum.conf.sample include electrum.desktop include *.py include run_electrum @@ -15,4 +14,6 @@ graft electrum prune electrum/tests global-exclude __pycache__ -global-exclude *.py[co] +global-exclude *.py[co~] +global-exclude *.py.orig +global-exclude *.py.rej diff --git a/README.rst b/README.rst index 6dfb6994..ff3c18c1 100644 --- a/README.rst +++ b/README.rst @@ -91,25 +91,25 @@ Create translations (optional):: Creating Binaries ================= +Linux +----- -To create binaries, create the 'packages' directory:: +See :code:`contrib/build-linux/README.md`. - ./contrib/make_packages - -This directory contains the python dependencies used by Electrum. Mac OS X / macOS --------- +---------------- + +See :code:`contrib/osx/README.md`. -See `contrib/osx/`. Windows ------- -See `contrib/build-wine/`. +See :code:`contrib/build-wine/docker/README.md`. Android ------- -See `electrum/gui/kivy/Readme.md` file. +See :code:`electrum/gui/kivy/Readme.md`. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index ecf3ecb8..568fdecf 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,3 +1,14 @@ +# Release 3.3.3 - (January 25, 2019) + + * Do not expose users to server error messages (#4968) + * Notify users of new releases. Release announcements must be signed, + and they are verified byElectrum using a hardcoded Bitcoin address. + * Hardware wallet fixes (#4991, #4993, #5006) + * Display only QR code in QRcode Window + * Fixed code signing on MacOS + * Randomise locktime of transactions + + # Release 3.3.2 - (December 21, 2018) * Fix Qt history export bug diff --git a/contrib/build-linux/README.md b/contrib/build-linux/README.md new file mode 100644 index 00000000..8d45038c --- /dev/null +++ b/contrib/build-linux/README.md @@ -0,0 +1,20 @@ +Source tarballs +=============== + +1. Build locale files + + ``` + contrib/make_locale + ``` + +2. Prepare python dependencies used by Electrum. + + ``` + contrib/make_packages + ``` + +3. Create source tarball. + + ``` + contrib/make_tgz + ``` diff --git a/contrib/build-wine/prepare-wine.sh b/contrib/build-wine/prepare-wine.sh index e80259f5..f9e6941f 100755 --- a/contrib/build-wine/prepare-wine.sh +++ b/contrib/build-wine/prepare-wine.sh @@ -116,7 +116,7 @@ $PYTHON -m pip install pip --upgrade $PYTHON -m pip install -r $here/../deterministic-build/requirements-binaries.txt # Install PyInstaller -$PYTHON -m pip install pyinstaller==3.4 +$PYTHON -m pip install pyinstaller==3.4 --no-use-pep517 # Install ZBar download_if_not_exist $ZBAR_FILENAME "$ZBAR_URL" diff --git a/contrib/deterministic-build/electrum-icons b/contrib/deterministic-build/electrum-icons index d586021b..201d45cd 160000 --- a/contrib/deterministic-build/electrum-icons +++ b/contrib/deterministic-build/electrum-icons @@ -1 +1 @@ -Subproject commit d586021ba0d4820d6587cff000756b3d035d4f08 +Subproject commit 201d45cd5d855c4f9de5680ab5c53621574dc6b6 diff --git a/contrib/deterministic-build/electrum-locale b/contrib/deterministic-build/electrum-locale index caba5f30..e5b28e47 160000 --- a/contrib/deterministic-build/electrum-locale +++ b/contrib/deterministic-build/electrum-locale @@ -1 +1 @@ -Subproject commit caba5f30b134ec08d3e29150b33c87200597181a +Subproject commit e5b28e4717d8c8a736d6d4e5398fa4fa67db80d0 diff --git a/contrib/deterministic-build/requirements-binaries.txt b/contrib/deterministic-build/requirements-binaries.txt index e615ae3a..12fbcf06 100644 --- a/contrib/deterministic-build/requirements-binaries.txt +++ b/contrib/deterministic-build/requirements-binaries.txt @@ -1,34 +1,35 @@ -pip==18.1 \ - --hash=sha256:7909d0a0932e88ea53a7014dfd14522ffef91a464daaaf5c573343852ef98550 \ - --hash=sha256:c0a292bd977ef590379a3f05d7b7f65135487b67470f6281289a94e015650ea1 -pycryptodomex==3.7.2 \ - --hash=sha256:09f433a6ca4b96a4c89096af9eaa20c5d5e9029a03266f6a80062163d2042030 \ - --hash=sha256:0bb7686dd46d40cace053941638d2db4f9d86a50a62d6100f14157162e56e82f \ - --hash=sha256:13ef8e8a26a9ac7ae84616e9c500ca0cf721d3725d740124f68dda1b58e7d408 \ - --hash=sha256:195b6540f31cbe3dc7bf3877177bb4fe1a145ce02191efdd0cb6399bff275d4b \ - --hash=sha256:329ca5986c5e5f6a60edc3ff8b70c28d6cb259491e35e44870db6a8d92430e50 \ - --hash=sha256:42b2eccccb9da547e0ff140784037ea31c1a37012488706b51cbcadb885d2053 \ - --hash=sha256:4b2817bd02dd7dd36f223917f9bcc90d658bb66124bc596d7e3a0c250509acf7 \ - --hash=sha256:5b765870e17bf82a992f2ebb312207da76dbf8694ce865fee847005cce9244e4 \ - --hash=sha256:5d4e10ad9ff7940da534119ef92a500dcf7c28351d15e12d74ef0ce025e37d5b \ - --hash=sha256:75186284b593df724451869035bfab4a03b6b388ed6eea284ad7fe84c9b64ea0 \ - --hash=sha256:77928b02c28adb4d1d637c609aba380d890fb40ad63c58c826bef871c84cf488 \ - --hash=sha256:7cd21c1a4dd0879dc3b289afeb0033a9382da7d0a50cb9de8d0e59c1ab0977a7 \ - --hash=sha256:83b7fe71fb9d27ff12df9dd3f57ea84153a86f45a674ee2b4763aaaf8ca84988 \ - --hash=sha256:8a67f26365ddad6ae53c0b3800edce16d164e675ee773de31c110624e63736d8 \ - --hash=sha256:8e08238f8d146caabf9d80cca09dd31323a333f74f62323aabd075e7effbc45c \ - --hash=sha256:938af93204c93d1f576acdef970e95dfd0bbe40133f4bbf73c4b12b67f7bd4ed \ - --hash=sha256:b2f33943f91c764f2b27a1504cd3ec2c075deb7d1b8fcc3ab4d575bede7037a8 \ - --hash=sha256:b7efd0ac8b38dfdf8b2d387e84b007c843a66de9da437a950a86caa2d1437e1e \ - --hash=sha256:b95b14e5baaa4ca77ecb7a3d0f85fd13a8e31ada83c5a2bae5652d446414d63d \ - --hash=sha256:bad0c66c42d16e81eef2199b3c4fb78c873f54c7f9d156e69664e2138155747c \ - --hash=sha256:c384a85bede5396eed50f6c0374d8c51490fc10fdc65dffc8e613b57e5ab0ee0 \ - --hash=sha256:c58a324a8eb48f767abe8c906295d76e04330aa0a03d99dd58d9a42938ee0596 \ - --hash=sha256:d498731d66f9b9ad978c9a8018b0c6cfc4081e202a79c6e283ade7dcf2a72c18 \ - --hash=sha256:d516746fc25daff1c5e84d3f816d134d75a10e3551ffac92aa957a75b6b0208f \ - --hash=sha256:ec51ea9f11b11df2719a01ea1cacdcf80858542a93f530a25a3bc742d0fe2f4b \ - --hash=sha256:ef2792281138a29e54bdd7302fdab72be140192485dc622bb9e7e9a6f9cee4f9 \ - --hash=sha256:f79650ec8812b01f20aca503763b93b0b1b347423ecf9fd3a9ebb611bee84079 +pip==19.0.1 \ + --hash=sha256:aae79c7afe895fb986ec751564f24d97df1331bb99cdfec6f70dada2f40c0044 \ + --hash=sha256:e81ddd35e361b630e94abeda4a1eddd36d47a90e71eb00f38f46b57f787cd1a5 +pycryptodomex==3.7.3 \ + --hash=sha256:0bda549e20db1eb8e29fb365d10acf84b224d813b1131c828fc830b2ce313dcd \ + --hash=sha256:1210c0818e5334237b16d99b5785aa0cee815d9997ee258bd5e2936af8e8aa50 \ + --hash=sha256:2090dc8cd7843eae75bd504b9be86792baa171fc5a758ea3f60188ab67ca95cf \ + --hash=sha256:22e6784b65dfdd357bf9a8a842db445192b227103e2c3137a28c489c46742135 \ + --hash=sha256:2edb8c3965a77e3092b5c5c1233ffd32de083f335202013f52d662404191ac79 \ + --hash=sha256:310fe269ac870135ff610d272e88dcb594ee58f40ac237a688d7c972cbca43e8 \ + --hash=sha256:456136b7d459f000794a67b23558351c72e21f0c2d4fcaa09fc99dae7844b0ef \ + --hash=sha256:463e49a9c5f1fa7bd36aff8debae0b5c487868c1fb66704529f2ad7e92f0cc9f \ + --hash=sha256:4a33b2828799ef8be789a462e6645ea6fe2c42b0df03e6763ccbfd1789c453e6 \ + --hash=sha256:5ff02dff1b03929e6339226b318aa59bd0b5c362f96e3e0eb7f3401d30594ed3 \ + --hash=sha256:6b1db8234b8ee2b30435d9e991389c2eeae4d45e09e471ffe757ba1dfae682bb \ + --hash=sha256:6eb67ee02de143cd19e36a52bd3869a9dc53e9184cd6bed5c39ff71dee2f6a45 \ + --hash=sha256:6f42eea5afc7eee29494fdfddc6bb7173953d4197d9200e4f67096c2a24bc21b \ + --hash=sha256:87bc8082e2de2247df7d0b161234f8edb1384294362cc0c8db9324463097578b \ + --hash=sha256:8df93d34bc0e3a28a27652070164683a07d8a50c628119d6e0f7710f4d01b42f \ + --hash=sha256:989952c39e8fef1c959f0a0f85656e29c41c01162e33a3f5fd8ce71e47262ae9 \ + --hash=sha256:a4a203077e2f312ec8677dde80a5c4e6fe5a82a46173a8edc8da668602a3e073 \ + --hash=sha256:a793c1242dffd39f585ae356344e8935d30f01f6be7d4c62ffc87af376a2f5f9 \ + --hash=sha256:b70fe991564e178af02ccf89435a8f9e8d052707a7c4b95bf6027cb785da3175 \ + --hash=sha256:b83594196e3661cb78c97b80a62fbfbba2add459dfd532b58e7a7c62dd06aab4 \ + --hash=sha256:ba27725237d0a3ea66ec2b6b387259471840908836711a3b215160808dffed0f \ + --hash=sha256:d1ab8ad1113cdc553ca50c4d5f0142198c317497364c0c70443d69f7ad1c9288 \ + --hash=sha256:dce039a8a8a318d7af83cae3fd08d58cefd2120075dfac0ae14d706974040f63 \ + --hash=sha256:e3213037ea33c85ab705579268cbc8a4433357e9fb99ec7ce9fdcc4d4eec1d50 \ + --hash=sha256:ec8d8023d31ef72026d46e9fb301ff8759eff5336bcf3d1510836375f53f96a9 \ + --hash=sha256:ece65730d50aa57a1330d86d81582a2d1587b2ca51cb34f586da8551ddc68fee \ + --hash=sha256:ed21fc515e224727793e4cc3fb3d00f33f59e3a167d3ad6ac1475ab3b05c2f9e \ + --hash=sha256:eec1132d878153d61a05424f35f089f951bd6095a4f6c60bdd2ef8919d44425e PyQt5==5.11.3 \ --hash=sha256:517e4339135c4874b799af0d484bc2e8c27b54850113a68eec40a0b56534f450 \ --hash=sha256:ac1eb5a114b6e7788e8be378be41c5e54b17d5158994504e85e43b5fca006a39 \ diff --git a/contrib/deterministic-build/requirements-hw.txt b/contrib/deterministic-build/requirements-hw.txt index 60ff68b6..fad4e540 100644 --- a/contrib/deterministic-build/requirements-hw.txt +++ b/contrib/deterministic-build/requirements-hw.txt @@ -14,35 +14,35 @@ click==7.0 \ --hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7 construct==2.9.45 \ --hash=sha256:2271a0efd0798679dea825ff47e22a4c550456a5db0ba8baa82f7eae0af0118c -Cython==0.29.2 \ - --hash=sha256:004c181b75f926f48dc0570372ca2cfb06a1b3210cb647185977ce9fde98b66e \ - --hash=sha256:085d596c016130f5b1e2fe72446e3e63bfcf67535e7ff6772eaa05c5d2ad6fd5 \ - --hash=sha256:1014758344717844a05882c92ebd76d8fab15b0a8e9b42b378a99a6c5299ab3b \ - --hash=sha256:12c007d3704ca9840734748fd6c052960be67562ff15609c3b85d1ca638289d2 \ - --hash=sha256:1a20f575197e814453f2814829715fcb21436075e298d883a34c7ffe4d567a1d \ - --hash=sha256:1b6f201228368ec9b307261b46512f3605f84d4994bb6eb78cdab71455810424 \ - --hash=sha256:2ac187ff998a95abb7fae452b5178f91e1a713698c9ced89836c94e6b1d3f41e \ - --hash=sha256:3585fbe18d8666d91ecb3b3366ca6e9ea49001cd0a7c38a226cececb7852aa0d \ - --hash=sha256:3669dfe4117ee8825a48cf527cb4ac15a39a0142fcb72ecedfd75fe6545b2cda \ - --hash=sha256:382c1e0f8f8be36e9057264677fd60b669a41c5810113694cbbb4060ee0cefc0 \ - --hash=sha256:44bb606d8c60d8acaa7f72b3bbc2ebd9816785124c58d33c057ca326f1185dae \ - --hash=sha256:6f1a5344ff1f0f44023c41d4b0e52215b490658b42e017520cb89a56250ecbca \ - --hash=sha256:7a29f9d780ac497dcd76ce814a9d170575bedddeb89ecc25fe738abef4c87172 \ - --hash=sha256:8022a5b83ef442584f2efd941fe8678de1c67e28bf81e6671b20627ec8a79387 \ - --hash=sha256:998af90092cd1231990eb878e2c71ed92716d6a758aa03a2e6673e077a7dd072 \ - --hash=sha256:9e60b83afe8914ab6607f7150fd282d1cb0531a45cf98d2a40159f976ae4cd7a \ - --hash=sha256:a6581d3dda15adea19ac70b89211aadbf21f45c7f3ee3bc8e1536e5437c9faf9 \ - --hash=sha256:af515924b8aebb729f631590eb43300ce948fa67d3885fdae9238717c0a68821 \ - --hash=sha256:b49ea3bb357bc34eaa7b461633ce7c2d79186fe681297115ff9e2b8f5ceba2fd \ - --hash=sha256:bc524cc603f0aa23af00111ddd1aa0aad12d629f5a9a5207f425a1af66393094 \ - --hash=sha256:ca7daccffb14896767b20d69bfc8de9e41e9589b9377110292c3af8460ef9c2b \ - --hash=sha256:cdfb68eb11c6c4e90e34cf54ffd678a7813782fae980d648db6185e6b0c8a0ba \ - --hash=sha256:d21fb6e7a3831f1f8346275839d46ed1eb2abd350fc81bad2fdf208cc9e4f998 \ - --hash=sha256:e17104c6871e7c0eee4de12717892a1083bd3b8b1da0ec103fa464b1c6c80964 \ - --hash=sha256:e7f71b489959d478cff72d8dcab1531efd43299341e3f8b85ab980beec452ded \ - --hash=sha256:e8420326e4b40bcbb06f070efb218ca2ca21827891b7c69d4cc4802b3ce1afc9 \ - --hash=sha256:eec1b890cf5c16cb656a7062769ac276c0fccf898ce215ff8ef75eac740063f7 \ - --hash=sha256:f04e21ba7c117b20f57b0af2d4c8ed760495e5bb3f21b0352dbcfe5d2221678b +Cython==0.29.3 \ + --hash=sha256:1327655db47beb665961d3dc0365e20c9e8e80c234513ab2c7d06ec0dd9d63eb \ + --hash=sha256:142400f13102403f43576bb92d808a668e29deda5625388cfa39fe0bcf37b3d1 \ + --hash=sha256:1b4204715141281a631337378f0c15fe660b35e1b6888ca05f1f3f49df3b97d5 \ + --hash=sha256:23aabaaf8887e6db99df2145de6742f8c92830134735778bf2ae26338f2b406f \ + --hash=sha256:2a724c6f21fdf4e3c1e8c5c862ff87f5420fdaecf53a5a0417915e483d90217f \ + --hash=sha256:2c9c8c1c6e8bd3587e5f5db6f865a42195ff2dedcaf5cdb63fdea10c98bd6246 \ + --hash=sha256:3a1be38b774423605189d60652b3d8a324fc81d213f96569720c8093784245ab \ + --hash=sha256:46be5297a76513e4d5d6e746737d4866a762cfe457e57d7c54baa7ef8fea7e9a \ + --hash=sha256:48dc2ea4c4d3f34ddcad5bc71b1f1cf49830f868832d3e5df803c811e7395b6e \ + --hash=sha256:53f33e04d2ed078ac02841741bcd536b546e1f416608084468ab30a87638a466 \ + --hash=sha256:57b10588618ca19a4cc870f381aa8805bc5fe0c62d19d7f940232ff8a373887c \ + --hash=sha256:6001038341b52301450bb9c62e5d5da825788944572679277e137ffb3596e718 \ + --hash=sha256:70bef52e735607060f327d729be35c820d9018d260a875e4f98b20ba8c4fff96 \ + --hash=sha256:7d0f76b251699be8f1f1064dcb12d4b3b2b676ce15ff30c104e0c2091a015142 \ + --hash=sha256:9440b64c1569c26a184b7c778bb221cf9987c5c8486d32cda02302c66ea78980 \ + --hash=sha256:956cc97eac6f9d3b16e3b2d2a94c5586af3403ba97945e9d88a4a0f029899646 \ + --hash=sha256:ae430ad8cce937e07ea566d1d7899eef1fedc8ec512b4d5fa37ebf2c1f879936 \ + --hash=sha256:bdb575149881978d62167dd8427402a5872a79bd83e9d51219680670e9f80b40 \ + --hash=sha256:c0ffcddd3dbdf22aae3980931112cc8b2732315a6273988f3205cf5dacf36f45 \ + --hash=sha256:c133e2efc57426974366ac74f2ef0f1171b860301ac27f72316deacff4ccdc17 \ + --hash=sha256:c6e9521d0b77eb1da89e8264eb98c8f5cda7c49a49b8128acfd35f0ca50e56d0 \ + --hash=sha256:c7cac0220ecb733024e8acfcfb6b593a007185690f2ea470d2392b72510b7187 \ + --hash=sha256:d53483820ac28f2be2ff13eedd56c0f36a4c583727b551d3d468023556e2336a \ + --hash=sha256:d60210784186d61e0ec808d5dbee5d661c7457a57f93cb5fdc456394607ce98c \ + --hash=sha256:d687fb1cd9df28c1515666174c62e54bd894a6a6d0862f89705063cd47739f83 \ + --hash=sha256:d926764d9c768a48b0a16a91696aaa25498057e060934f968fa4c5629b942d85 \ + --hash=sha256:d94a2f4ad74732f58d1c771fc5d90a62c4fe4c98d0adfecbc76cd0d8d14bf044 \ + --hash=sha256:def76a546eeec059666f5f4117dfdf9c78e50fa1f95bdd23b04618c7adf845cd ecdsa==0.13 \ --hash=sha256:40d002cf360d0e035cf2cb985e1308d41aaa087cbfc135b2dc2d844296ea546c \ --hash=sha256:64cf1ee26d1cde3c73c6d7d107f835fed7c6a2904aef9eac223d57ad800c43fa @@ -61,17 +61,19 @@ hidapi==0.7.99.post21 \ idna==2.8 \ --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \ --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c -keepkey==4.0.2 \ - --hash=sha256:cddee60ae405841cdff789cbc54168ceaeb2282633420f2be155554c25c69138 +keepkey==6.0.2 \ + --hash=sha256:3236dd701bde74768c41a92e724e322ea5e01b90985e2e6215eb85b77f9a0ae1 \ + --hash=sha256:677e07deacc2ff97bee313b8dd7ae55faebab02e7d17b9a8e49b889996a36010 \ + --hash=sha256:af107f610fb0e2417fc7a9d87a2fa22aac9b80b79559370d178be424bb85489a libusb1==1.7 \ --hash=sha256:9d4f66d2ed699986b06bc3082cd262101cb26af7a76a34bd15b7eb56cba37e0f mnemonic==0.18 \ --hash=sha256:02a7306a792370f4a0c106c2cf1ce5a0c84b9dbd7e71c6792fdb9ad88a727f1d pbkdf2==1.3 \ --hash=sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979 -pip==18.1 \ - --hash=sha256:7909d0a0932e88ea53a7014dfd14522ffef91a464daaaf5c573343852ef98550 \ - --hash=sha256:c0a292bd977ef590379a3f05d7b7f65135487b67470f6281289a94e015650ea1 +pip==19.0.1 \ + --hash=sha256:aae79c7afe895fb986ec751564f24d97df1331bb99cdfec6f70dada2f40c0044 \ + --hash=sha256:e81ddd35e361b630e94abeda4a1eddd36d47a90e71eb00f38f46b57f787cd1a5 protobuf==3.6.1 \ --hash=sha256:10394a4d03af7060fa8a6e1cbf38cea44be1467053b0aea5bbfcb4b13c4b88c4 \ --hash=sha256:1489b376b0f364bcc6f89519718c057eb191d7ad6f1b395ffd93d1aa45587811 \ @@ -114,13 +116,13 @@ setuptools==40.6.3 \ six==1.12.0 \ --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \ --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 -trezor==0.11.0 \ - --hash=sha256:1132f6a97afb0979c5018b067494bc8917b881c02d965f991270a70543b5050c \ - --hash=sha256:ce8f6ff2502b530d0cd3c5aa4b59330a56abbc6046a34f22c7eb0b2713b4f09d -typing-extensions==3.6.6 \ - --hash=sha256:2a6c6e78e291a4b6cbd0bbfd30edc0baaa366de962129506ec8fe06bdec66457 \ - --hash=sha256:51e7b7f3dcabf9ad22eed61490f3b8d23d9922af400fe6656cb08e66656b701f \ - --hash=sha256:55401f6ed58ade5638eb566615c150ba13624e2f0c1eedd080fc3c1b6cb76f1d +trezor==0.11.1 \ + --hash=sha256:6043f321d856e1b45b9df0c37810264f08d065bb56cd999f61a05fe2906e9e18 \ + --hash=sha256:6119b30cf9a136667753935bd06c5f341e78950b35e8ccbadaecc65c12f1946d +typing-extensions==3.7.2 \ + --hash=sha256:07b2c978670896022a43c4b915df8958bec4a6b84add7f2c87b2b728bda3ba64 \ + --hash=sha256:f3f0e67e1d42de47b5c67c32c9b26641642e9170fe7e292991793705cd5fef7c \ + --hash=sha256:fb2cd053238d33a8ec939190f30cfd736c00653a85a2919415cecf7dc3d9da71 urllib3==1.24.1 \ --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \ --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 diff --git a/contrib/deterministic-build/requirements.txt b/contrib/deterministic-build/requirements.txt index 9c5faa02..68cabfd6 100644 --- a/contrib/deterministic-build/requirements.txt +++ b/contrib/deterministic-build/requirements.txt @@ -1,31 +1,32 @@ -aiohttp==3.4.4 \ - --hash=sha256:0419705a36b43c0ac6f15469f9c2a08cad5c939d78bd12a5c23ea167c8253b2b \ - --hash=sha256:1812fc4bc6ac1bde007daa05d2d0f61199324e0cc893b11523e646595047ca08 \ - --hash=sha256:2214b5c0153f45256d5d52d1e0cafe53f9905ed035a142191727a5fb620c03dd \ - --hash=sha256:275909137f0c92c61ba6bb1af856a522d5546f1de8ea01e4e726321c697754ac \ - --hash=sha256:3983611922b561868428ea1e7269e757803713f55b53502423decc509fef1650 \ - --hash=sha256:51afec6ffa50a9da4cdef188971a802beb1ca8e8edb40fa429e5e529db3475fa \ - --hash=sha256:589f2ec8a101a0f340453ee6945bdfea8e1cd84c8d88e5be08716c34c0799d95 \ - --hash=sha256:789820ddc65e1f5e71516adaca2e9022498fa5a837c79ba9c692a9f8f916c330 \ - --hash=sha256:7a968a0bdaaf9abacc260911775611c9a602214a23aeb846f2eb2eeaa350c4dc \ - --hash=sha256:7aeefbed253f59ea39e70c5848de42ed85cb941165357fc7e87ab5d8f1f9592b \ - --hash=sha256:7b2eb55c66512405103485bd7d285a839d53e7fdc261ab20e5bcc51d7aaff5de \ - --hash=sha256:87bc95d3d333bb689c8d755b4a9d7095a2356108002149523dfc8e607d5d32a4 \ - --hash=sha256:9d80e40db208e29168d3723d1440ecbb06054d349c5ece6a2c5a611490830dd7 \ - --hash=sha256:a1b442195c2a77d33e4dbee67c9877ccbdd3a1f686f91eb479a9577ed8cc326b \ - --hash=sha256:ab3d769413b322d6092f169f316f7b21cd261a7589f7e31db779d5731b0480d8 \ - --hash=sha256:b066d3dec5d0f5aee6e34e5765095dc3d6d78ef9839640141a2b20816a0642bd \ - --hash=sha256:b24e7845ae8de3e388ef4bcfcf7f96b05f52c8e633b33cf8003a6b1d726fc7c2 \ - --hash=sha256:c59a953c3f8524a7c86eaeaef5bf702555be12f5668f6384149fe4bb75c52698 \ - --hash=sha256:cf2cc6c2c10d242790412bea7ccf73726a9a44b4c4b073d2699ef3b48971fd95 \ - --hash=sha256:e0c9c8d4150ae904f308ff27b35446990d2b1dfc944702a21925937e937394c6 \ - --hash=sha256:f1839db4c2b08a9c8f9788112644f8a8557e8e0ecc77b07091afabb941dc55d0 \ - --hash=sha256:f3df52362be39908f9c028a65490fae0475e4898b43a03d8aa29d1e765b45e07 -aiohttp-socks==0.2.1 \ - --hash=sha256:8bcfde1bb0d394b0ff0d8c284de7459c38507bff1f7c144ac734a6de49f36a29 -aiorpcX==0.10.1 \ - --hash=sha256:0c0a3342a43d939f00af84684fd08c0c5e7de4fa3eb21740063bea98f6070798 \ - --hash=sha256:58fe42b3695bc4e761b61b9a61416b0c6d69b220630be222b9b129b96ac9c331 +aiohttp==3.5.4 \ + --hash=sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55 \ + --hash=sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed \ + --hash=sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10 \ + --hash=sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5 \ + --hash=sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1 \ + --hash=sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939 \ + --hash=sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390 \ + --hash=sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa \ + --hash=sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc \ + --hash=sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5 \ + --hash=sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d \ + --hash=sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf \ + --hash=sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6 \ + --hash=sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72 \ + --hash=sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12 \ + --hash=sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366 \ + --hash=sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4 \ + --hash=sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300 \ + --hash=sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d \ + --hash=sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303 \ + --hash=sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6 \ + --hash=sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889 +aiohttp-socks==0.2.2 \ + --hash=sha256:e473ee222b001fe33798957b9ce3352b32c187cf41684f8e2259427925914993 \ + --hash=sha256:eebd8939a7c3c1e3e7e1b2552c60039b4c65ef6b8b2351efcbdd98290538e310 +aiorpcX==0.10.2 \ + --hash=sha256:23a59e625ca50cdf2866a2d8bd54256e648582a8d44d4495b34252f3dbc30e23 \ + --hash=sha256:d2bf57fc46ae37d769ab3f5e58ebee4b44acab626e597b5150a201284b9808dd async_timeout==3.0.1 \ --hash=sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f \ --hash=sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3 @@ -49,9 +50,9 @@ idna==2.8 \ --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c idna_ssl==1.1.0 \ --hash=sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c -jsonrpclib-pelix==0.3.2 \ - --hash=sha256:14d288d1b3d3273cf96a729dd21a2470851c4962be8509f3dd62f0137ff90339 \ - --hash=sha256:27fcd919d3dbf6179bcce587f73e1bad006922ae23c83c308e01227b8533178c +jsonrpclib-pelix==0.4.0 \ + --hash=sha256:19c558e169a51480b39548783067ca55046b62b2409ab4559931255e12f635de \ + --hash=sha256:a966d17f2f739ee89031cf5c807d85d92db6b2715fb2b2f8a88bbfc87f468b12 multidict==4.5.2 \ --hash=sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f \ --hash=sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3 \ @@ -82,9 +83,9 @@ multidict==4.5.2 \ --hash=sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9 \ --hash=sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7 \ --hash=sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b -pip==18.1 \ - --hash=sha256:7909d0a0932e88ea53a7014dfd14522ffef91a464daaaf5c573343852ef98550 \ - --hash=sha256:c0a292bd977ef590379a3f05d7b7f65135487b67470f6281289a94e015650ea1 +pip==19.0.1 \ + --hash=sha256:aae79c7afe895fb986ec751564f24d97df1331bb99cdfec6f70dada2f40c0044 \ + --hash=sha256:e81ddd35e361b630e94abeda4a1eddd36d47a90e71eb00f38f46b57f787cd1a5 protobuf==3.6.1 \ --hash=sha256:10394a4d03af7060fa8a6e1cbf38cea44be1467053b0aea5bbfcb4b13c4b88c4 \ --hash=sha256:1489b376b0f364bcc6f89519718c057eb191d7ad6f1b395ffd93d1aa45587811 \ @@ -108,15 +109,19 @@ pyaes==1.6.1 \ QDarkStyle==2.5.4 \ --hash=sha256:3eb60922b8c4d9cedecb6897ca4c9f8a259d81bdefe5791976ccdf12432de1f0 \ --hash=sha256:51331fc6490b38c376e6ba8d8c814320c8d2d1c2663055bc396321a7c28fa8be -qrcode==6.0 \ - --hash=sha256:037b0db4c93f44586e37f84c3da3f763874fcac85b2974a69a98e399ac78e1bf \ - --hash=sha256:de4ffc15065e6ff20a551ad32b6b41264f3c75275675406ddfa8e3530d154be3 +qrcode==6.1 \ + --hash=sha256:3996ee560fc39532910603704c82980ff6d4d5d629f9c3f25f34174ce8606cf5 \ + --hash=sha256:505253854f607f2abf4d16092c61d4e9d511a3b4392e60bff957a68592b04369 setuptools==40.6.3 \ --hash=sha256:3b474dad69c49f0d2d86696b68105f3a6f195f7ab655af12ef9a9c326d2b08f8 \ --hash=sha256:e2c1ce9a832f34cf7a31ed010aabcab5008eb65ce8f2aadc04622232c14bdd0b six==1.12.0 \ --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \ --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 +typing-extensions==3.7.2 \ + --hash=sha256:07b2c978670896022a43c4b915df8958bec4a6b84add7f2c87b2b728bda3ba64 \ + --hash=sha256:f3f0e67e1d42de47b5c67c32c9b26641642e9170fe7e292991793705cd5fef7c \ + --hash=sha256:fb2cd053238d33a8ec939190f30cfd736c00653a85a2919415cecf7dc3d9da71 wheel==0.32.3 \ --hash=sha256:029703bf514e16c8271c3821806a1c171220cc5bdd325cbf4e7da1e056a01db6 \ --hash=sha256:1e53cdb3f808d5ccd0df57f964263752aa74ea7359526d3da6c02114ec1e1d44 diff --git a/electrum.desktop b/electrum.desktop index 481f3b93..e4010671 100644 --- a/electrum.desktop +++ b/electrum.desktop @@ -10,7 +10,8 @@ Icon=electrum Name[en_US]=Electrum Bitcoin Wallet Name=Electrum Bitcoin Wallet Categories=Finance;Network; -StartupNotify=false +StartupNotify=true +StartupWMClass=electrum Terminal=false Type=Application MimeType=x-scheme-handler/bitcoin; diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py index ee1b6c0f..08cbde22 100644 --- a/electrum/bitcoin.py +++ b/electrum/bitcoin.py @@ -235,28 +235,28 @@ def b58_address_to_hash160(addr: str) -> Tuple[int, bytes]: def hash160_to_p2pkh(h160: bytes, *, net=None) -> str: - if net is None: - net = constants.net + if net is None: net = constants.net return hash160_to_b58_address(h160, net.ADDRTYPE_P2PKH) def hash160_to_p2sh(h160: bytes, *, net=None) -> str: - if net is None: - net = constants.net + if net is None: net = constants.net return hash160_to_b58_address(h160, net.ADDRTYPE_P2SH) -def public_key_to_p2pkh(public_key: bytes) -> str: - return hash160_to_p2pkh(hash_160(public_key)) +def public_key_to_p2pkh(public_key: bytes, *, net=None) -> str: + if net is None: net = constants.net + return hash160_to_p2pkh(hash_160(public_key), net=net) def hash_to_segwit_addr(h: bytes, witver: int, *, net=None) -> str: - if net is None: - net = constants.net + if net is None: net = constants.net return segwit_addr.encode(net.SEGWIT_HRP, witver, h) -def public_key_to_p2wpkh(public_key: bytes) -> str: - return hash_to_segwit_addr(hash_160(public_key), witver=0) +def public_key_to_p2wpkh(public_key: bytes, *, net=None) -> str: + if net is None: net = constants.net + return hash_to_segwit_addr(hash_160(public_key), witver=0, net=net) -def script_to_p2wsh(script: str) -> str: - return hash_to_segwit_addr(sha256(bfh(script)), witver=0) +def script_to_p2wsh(script: str, *, net=None) -> str: + if net is None: net = constants.net + return hash_to_segwit_addr(sha256(bfh(script)), witver=0, net=net) def p2wpkh_nested_script(pubkey: str) -> str: pkh = bh2u(hash_160(bfh(pubkey))) @@ -266,25 +266,27 @@ def p2wsh_nested_script(witness_script: str) -> str: wsh = bh2u(sha256(bfh(witness_script))) return '00' + push_script(wsh) -def pubkey_to_address(txin_type: str, pubkey: str) -> str: +def pubkey_to_address(txin_type: str, pubkey: str, *, net=None) -> str: + if net is None: net = constants.net if txin_type == 'p2pkh': - return public_key_to_p2pkh(bfh(pubkey)) + return public_key_to_p2pkh(bfh(pubkey), net=net) elif txin_type == 'p2wpkh': - return public_key_to_p2wpkh(bfh(pubkey)) + return public_key_to_p2wpkh(bfh(pubkey), net=net) elif txin_type == 'p2wpkh-p2sh': scriptSig = p2wpkh_nested_script(pubkey) - return hash160_to_p2sh(hash_160(bfh(scriptSig))) + return hash160_to_p2sh(hash_160(bfh(scriptSig)), net=net) else: raise NotImplementedError(txin_type) -def redeem_script_to_address(txin_type: str, redeem_script: str) -> str: +def redeem_script_to_address(txin_type: str, redeem_script: str, *, net=None) -> str: + if net is None: net = constants.net if txin_type == 'p2sh': - return hash160_to_p2sh(hash_160(bfh(redeem_script))) + return hash160_to_p2sh(hash_160(bfh(redeem_script)), net=net) elif txin_type == 'p2wsh': - return script_to_p2wsh(redeem_script) + return script_to_p2wsh(redeem_script, net=net) elif txin_type == 'p2wsh-p2sh': scriptSig = p2wsh_nested_script(redeem_script) - return hash160_to_p2sh(hash_160(bfh(scriptSig))) + return hash160_to_p2sh(hash_160(bfh(scriptSig)), net=net) else: raise NotImplementedError(txin_type) @@ -296,8 +298,7 @@ def script_to_address(script: str, *, net=None) -> str: return addr def address_to_script(addr: str, *, net=None) -> str: - if net is None: - net = constants.net + if net is None: net = constants.net if not is_address(addr, net=net): raise BitcoinException(f"invalid bitcoin address: {addr}") witver, witprog = segwit_addr.decode(net.SEGWIT_HRP, addr) diff --git a/electrum/commands.py b/electrum/commands.py index 773a83ca..07ec6a5f 100644 --- a/electrum/commands.py +++ b/electrum/commands.py @@ -220,6 +220,11 @@ class Commands: self.wallet.storage.write() return {'password':self.wallet.has_password()} + @command('w') + def get(self, key): + """Return item from wallet storage""" + return self.wallet.storage.get(key) + @command('') def getconfig(self, key): """Return a configuration variable. """ diff --git a/electrum/daemon.py b/electrum/daemon.py index 0db918c4..b4b021dd 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -294,7 +294,10 @@ class Daemon(DaemonThread): kwargs[x] = (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)) cmd_runner = Commands(config, wallet, self.network) func = getattr(cmd_runner, cmd.name) - result = func(*args, **kwargs) + try: + result = func(*args, **kwargs) + except TypeError as e: + raise Exception("Wrapping TypeError to prevent JSONRPC-Pelix from hiding traceback") from e return result def run(self): diff --git a/electrum/ecc.py b/electrum/ecc.py index feb56ce7..cf682c57 100644 --- a/electrum/ecc.py +++ b/electrum/ecc.py @@ -37,6 +37,7 @@ from .util import bfh, bh2u, assert_bytes, print_error, to_bytes, InvalidPasswor from .crypto import (sha256d, aes_encrypt_with_iv, aes_decrypt_with_iv, hmac_oneshot) from .ecc_fast import do_monkey_patching_of_python_ecdsa_internals_with_libsecp256k1 from . import msqr +from . import constants do_monkey_patching_of_python_ecdsa_internals_with_libsecp256k1() @@ -309,16 +310,17 @@ def msg_magic(message: bytes) -> bytes: return b"\x18Bitcoin Signed Message:\n" + length + message -def verify_message_with_address(address: str, sig65: bytes, message: bytes): +def verify_message_with_address(address: str, sig65: bytes, message: bytes, *, net=None): from .bitcoin import pubkey_to_address assert_bytes(sig65, message) + if net is None: net = constants.net try: h = sha256d(msg_magic(message)) public_key, compressed = ECPubkey.from_signature65(sig65, h) # check public key using the address pubkey_hex = public_key.get_public_key_hex(compressed) for txin_type in ['p2pkh','p2wpkh','p2wpkh-p2sh']: - addr = pubkey_to_address(txin_type, pubkey_hex) + addr = pubkey_to_address(txin_type, pubkey_hex, net=net) if address == addr: break else: diff --git a/electrum/gui/kivy/Readme.md b/electrum/gui/kivy/Readme.md index b11ee9f0..edf6b9e2 100644 --- a/electrum/gui/kivy/Readme.md +++ b/electrum/gui/kivy/Readme.md @@ -74,3 +74,11 @@ $ sudo docker run -it --rm \ ### How do I get more verbose logs? See `log_level` in `buildozer.spec` + + +### Kivy can be run directly on Linux Desktop. How? +Install Kivy. + +Build atlas: `(cd electrum/gui/kivy/; make theming)` + +Run electrum with the `-g` switch: `electrum -g kivy` diff --git a/electrum/gui/kivy/tools/Dockerfile b/electrum/gui/kivy/tools/Dockerfile index 4e8f2b3b..67661da0 100644 --- a/electrum/gui/kivy/tools/Dockerfile +++ b/electrum/gui/kivy/tools/Dockerfile @@ -11,7 +11,7 @@ RUN apt -y update -qq \ ENV ANDROID_NDK_HOME="${ANDROID_HOME}/android-ndk" -ENV ANDROID_NDK_VERSION="14b" +ENV ANDROID_NDK_VERSION="17c" ENV ANDROID_NDK_HOME_V="${ANDROID_NDK_HOME}-r${ANDROID_NDK_VERSION}" # get the latest version from https://developer.android.com/ndk/downloads/index.html @@ -122,6 +122,10 @@ USER ${USER} RUN pip install --upgrade cython==0.29 RUN python3 -m pip install --upgrade cython==0.29 +# prepare git +RUN git config --global user.name "John Doe" \ + && git config --global user.email johndoe@example.com + # install buildozer RUN cd /opt \ && git clone https://github.com/kivy/buildozer \ @@ -134,7 +138,9 @@ RUN cd /opt \ && cd python-for-android \ && git remote add sombernight https://github.com/SomberNight/python-for-android \ && git fetch --all \ - && git checkout 86eeec7c19679a5886d5e095ce0a43f1da138f87 \ + && git checkout fad5dd2fdc9b116b7621470deac501e4a7c4cc11 \ + # allowBackup="false": + && git cherry-pick 86eeec7c19679a5886d5e095ce0a43f1da138f87 \ && python3 -m pip install -e . # build env vars diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index a0d41c9f..1ba1bd00 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -226,6 +226,28 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): gui_object.timer.timeout.connect(self.timer_actions) self.fetch_alias() + # If the option hasn't been set yet + if config.get('check_updates') is None: + choice = QMessageBox.question(self, + "Electrum - " + _("Enable update check"), + _("For security reasons we advise that you always use the latest version of Electrum.") + " " + + _("Would you like to be notified when there is a newer version of Electrum available?"), + QMessageBox.Yes, + QMessageBox.No) + config.set_key('check_updates', choice == QMessageBox.Yes, save=True) + + if config.get('check_updates', False): + # The references to both the thread and the window need to be stored somewhere + # to prevent GC from getting in our way. + def on_version_received(v): + if UpdateCheck.is_newer(v): + self.update_check_button.setText(_("Update to Electrum {} is available").format(v)) + self.update_check_button.clicked.connect(lambda: self.show_update_check(v)) + self.update_check_button.show() + self._update_check_thread = UpdateCheckThread(self) + self._update_check_thread.checked.connect(on_version_received) + self._update_check_thread.start() + def on_history(self, b): self.wallet.clear_coin_price_cache() self.new_fx_history_signal.emit() @@ -577,6 +599,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): help_menu = menubar.addMenu(_("&Help")) help_menu.addAction(_("&About"), self.show_about) + help_menu.addAction(_("&Check for updates"), self.show_update_check) help_menu.addAction(_("&Official website"), lambda: webbrowser.open("https://electrum.org")) help_menu.addSeparator() help_menu.addAction(_("&Documentation"), lambda: webbrowser.open("http://docs.electrum.org/")).setShortcut(QKeySequence.HelpContents) @@ -604,6 +627,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): "servers that handle the most complicated parts of the FLO system.") + "\n\n" + _("Uses icons from the Icons8 icon pack (icons8.com)."))) + def show_update_check(self, version=None): + self.gui_object._update_check = UpdateCheck(self, version) + def show_report_bug(self): msg = ' '.join([ _("Please report any bugs as issues on github:
"), @@ -2005,7 +2031,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): sb = QStatusBar() sb.setFixedHeight(35) - qtVersion = qVersion() self.balance_label = QLabel("Loading wallet...") self.balance_label.setTextInteractionFlags(Qt.TextSelectableByMouse) @@ -2017,6 +2042,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): self.search_box.hide() sb.addPermanentWidget(self.search_box) + self.update_check_button = QPushButton("") + self.update_check_button.setFlat(True) + self.update_check_button.setCursor(QCursor(Qt.PointingHandCursor)) + self.update_check_button.setIcon(QIcon(":icons/update.png")) + self.update_check_button.hide() + sb.addPermanentWidget(self.update_check_button) + self.lock_icon = QIcon() self.password_button = StatusBarButton(self.lock_icon, _("Password"), self.change_password_dialog ) sb.addPermanentWidget(self.password_button) @@ -2912,6 +2944,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): colortheme_combo.currentIndexChanged.connect(on_colortheme) gui_widgets.append((colortheme_label, colortheme_combo)) + updatecheck_cb = QCheckBox(_("Automatically check for software updates")) + updatecheck_cb.setChecked(self.config.get('check_updates', False)) + def on_set_updatecheck(v): + self.config.set_key('check_updates', v == Qt.Checked, save=True) + updatecheck_cb.stateChanged.connect(on_set_updatecheck) + gui_widgets.append((updatecheck_cb, None)) + usechange_cb = QCheckBox(_('Use change addresses')) usechange_cb.setChecked(self.wallet.use_change) if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False) @@ -3085,7 +3124,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): tabs_info = [ (fee_widgets, _('Fees')), (tx_widgets, _('Transactions')), - (gui_widgets, _('Appearance')), + (gui_widgets, _('General')), (fiat_widgets, _('Fiat')), (id_widgets, _('Identity')), ] diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index a8358ba5..aee7bc1b 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -1,17 +1,24 @@ +import asyncio import os.path import time import sys import platform import queue +import traceback +from distutils.version import StrictVersion from functools import partial from typing import NamedTuple, Callable, Optional, TYPE_CHECKING +import base64 from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * +from electrum import version +from electrum import ecc +from electrum import constants from electrum.i18n import _, languages -from electrum.util import FileImportFailed, FileExportFailed +from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, PrintError from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED if TYPE_CHECKING: @@ -819,6 +826,124 @@ class FromList(QTreeWidget): self.header().setSectionResizeMode(0, sm) self.header().setSectionResizeMode(1, sm) + +class UpdateCheck(QWidget, PrintError): + url = "https://electrum.org/version" + download_url = "https://electrum.org/#download" + + VERSION_ANNOUNCEMENT_SIGNING_KEYS = ( + "13xjmVAB1EATPP8RshTE8S8sNwwSUM9p1P", + ) + + def __init__(self, main_window, latest_version=None): + self.main_window = main_window + QWidget.__init__(self) + self.setWindowTitle('Electrum - ' + _('Update Check')) + self.content = QVBoxLayout() + self.content.setContentsMargins(*[10]*4) + + self.heading_label = QLabel() + self.content.addWidget(self.heading_label) + + self.detail_label = QLabel() + self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse) + self.detail_label.setOpenExternalLinks(True) + self.content.addWidget(self.detail_label) + + self.pb = QProgressBar() + self.pb.setMaximum(0) + self.pb.setMinimum(0) + self.content.addWidget(self.pb) + + versions = QHBoxLayout() + versions.addWidget(QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION)))) + self.latest_version_label = QLabel(_("Latest version: {}".format(" "))) + versions.addWidget(self.latest_version_label) + self.content.addLayout(versions) + + self.update_view(latest_version) + + self.update_check_thread = UpdateCheckThread(self.main_window) + self.update_check_thread.checked.connect(self.on_version_retrieved) + self.update_check_thread.failed.connect(self.on_retrieval_failed) + self.update_check_thread.start() + + close_button = QPushButton(_("Close")) + close_button.clicked.connect(self.close) + self.content.addWidget(close_button) + self.setLayout(self.content) + self.show() + + def on_version_retrieved(self, version): + self.update_view(version) + + def on_retrieval_failed(self): + self.heading_label.setText('

' + _("Update check failed") + '

') + self.detail_label.setText(_("Sorry, but we were unable to check for updates. Please try again later.")) + self.pb.hide() + + @staticmethod + def is_newer(latest_version): + return latest_version > StrictVersion(version.ELECTRUM_VERSION) + + def update_view(self, latest_version=None): + if latest_version: + self.pb.hide() + self.latest_version_label.setText(_("Latest version: {}".format(latest_version))) + if self.is_newer(latest_version): + self.heading_label.setText('

' + _("There is a new update available") + '

') + url = "{u}".format(u=UpdateCheck.download_url) + self.detail_label.setText(_("You can download the new version from {}.").format(url)) + else: + self.heading_label.setText('

' + _("Already up to date") + '

') + self.detail_label.setText(_("You are already on the latest version of Electrum.")) + else: + self.heading_label.setText('

' + _("Checking for updates...") + '

') + self.detail_label.setText(_("Please wait while Electrum checks for available updates.")) + + +class UpdateCheckThread(QThread, PrintError): + checked = pyqtSignal(object) + failed = pyqtSignal() + + def __init__(self, main_window): + super().__init__() + self.main_window = main_window + + async def get_update_info(self): + async with make_aiohttp_session(proxy=self.main_window.network.proxy) as session: + async with session.get(UpdateCheck.url) as result: + signed_version_dict = await result.json(content_type=None) + # example signed_version_dict: + # { + # "version": "3.9.9", + # "signatures": { + # "1Lqm1HphuhxKZQEawzPse8gJtgjm9kUKT4": "IA+2QG3xPRn4HAIFdpu9eeaCYC7S5wS/sDxn54LJx6BdUTBpse3ibtfq8C43M7M1VfpGkD5tsdwl5C6IfpZD/gQ=" + # } + # } + version_num = signed_version_dict['version'] + sigs = signed_version_dict['signatures'] + for address, sig in sigs.items(): + if address not in UpdateCheck.VERSION_ANNOUNCEMENT_SIGNING_KEYS: + continue + sig = base64.b64decode(sig) + msg = version_num.encode('utf-8') + if ecc.verify_message_with_address(address=address, sig65=sig, message=msg, + net=constants.BitcoinMainnet): + self.print_error(f"valid sig for version announcement '{version_num}' from address '{address}'") + break + else: + raise Exception('no valid signature for version announcement') + return StrictVersion(version_num.strip()) + + def run(self): + try: + self.checked.emit(asyncio.run_coroutine_threadsafe(self.get_update_info(), self.main_window.network.asyncio_loop).result()) + except Exception: + self.print_error(traceback.format_exc()) + self.failed.emit() + + if __name__ == "__main__": app = QApplication([]) t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done")) diff --git a/electrum/gui/qt/utxo_list.py b/electrum/gui/qt/utxo_list.py index 046f30fc..5bd1703c 100644 --- a/electrum/gui/qt/utxo_list.py +++ b/electrum/gui/qt/utxo_list.py @@ -30,6 +30,7 @@ from electrum.i18n import _ from .util import * class UTXOList(MyTreeView): + headers = [ _('Address'), _('Label'), _('Amount'), _('Height'), _('Output point')] filter_columns = [0, 1] # Address, Label def __init__(self, parent=None): @@ -44,7 +45,7 @@ class UTXOList(MyTreeView): utxos = self.wallet.get_utxos() self.utxo_dict = {} self.model().clear() - self.update_headers([ _('Address'), _('Label'), _('Amount'), _('Height'), _('Output point')]) + self.update_headers(self.__class__.headers) for idx, x in enumerate(utxos): address = x.get('address') height = x.get('height') diff --git a/electrum/plugins/hw_wallet/cmdline.py b/electrum/plugins/hw_wallet/cmdline.py index de29780c..fc4aaadf 100644 --- a/electrum/plugins/hw_wallet/cmdline.py +++ b/electrum/plugins/hw_wallet/cmdline.py @@ -1,17 +1,17 @@ -from electrum.util import print_msg, print_error, raw_input +from electrum.util import print_error, print_stderr, raw_input class CmdLineHandler: def get_passphrase(self, msg, confirm): import getpass - print_msg(msg) + print_stderr(msg) return getpass.getpass('') def get_pin(self, msg): t = { 'a':'7', 'b':'8', 'c':'9', 'd':'4', 'e':'5', 'f':'6', 'g':'1', 'h':'2', 'i':'3'} - print_msg(msg) - print_msg("a b c\nd e f\ng h i\n-----") + print_stderr(msg) + print_stderr("a b c\nd e f\ng h i\n-----") o = raw_input() try: return ''.join(map(lambda x: t[x], o)) @@ -20,24 +20,24 @@ class CmdLineHandler: def prompt_auth(self, msg): import getpass - print_msg(msg) + print_stderr(msg) response = getpass.getpass('') if len(response) == 0: return None return response def yes_no_question(self, msg): - print_msg(msg) + print_stderr(msg) return raw_input() in 'yY' def stop(self): pass def show_message(self, msg, on_cancel=None): - print_msg(msg) + print_stderr(msg) def show_error(self, msg, blocking=False): - print_msg(msg) + print_stderr(msg) def update_status(self, b): print_error('hw device status', b) diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py index 699ea9d7..d88ca07c 100644 --- a/electrum/plugins/keepkey/keepkey.py +++ b/electrum/plugins/keepkey/keepkey.py @@ -289,7 +289,8 @@ class KeepKeyPlugin(HW_PluginBase): client = self.get_client(keystore) inputs = self.tx_inputs(tx, True) outputs = self.tx_outputs(keystore.get_derivation(), tx) - signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] + signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, + lock_time=tx.locktime, version=tx.version)[0] signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py index f153e6ad..24604f0f 100644 --- a/electrum/plugins/safe_t/safe_t.py +++ b/electrum/plugins/safe_t/safe_t.py @@ -306,7 +306,8 @@ class SafeTPlugin(HW_PluginBase): client = self.get_client(keystore) inputs = self.tx_inputs(tx, True) outputs = self.tx_outputs(keystore.get_derivation(), tx) - signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] + signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, + lock_time=tx.locktime, version=tx.version)[0] signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index 1df9d663..26a6af19 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -310,7 +310,7 @@ class TrezorPlugin(HW_PluginBase): client = self.get_client(keystore) inputs = self.tx_inputs(tx, xpub_path, True) outputs = self.tx_outputs(keystore.get_derivation(), tx) - details = SignTx(lock_time=tx.locktime) + details = SignTx(lock_time=tx.locktime, version=tx.version) signatures, _ = client.sign_tx(self.get_coin_name(), inputs, outputs, details=details, prev_txes=prev_tx) signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) diff --git a/electrum/version.py b/electrum/version.py index 6b986aa4..a80d45f4 100644 --- a/electrum/version.py +++ b/electrum/version.py @@ -1,5 +1,5 @@ -ELECTRUM_VERSION = '3.3.2' # version of the client package -APK_VERSION = '3.3.2.0' # read by buildozer.spec +ELECTRUM_VERSION = '3.3.3' # version of the client package +APK_VERSION = '3.3.3.0' # read by buildozer.spec PROTOCOL_VERSION = '1.4' # protocol version requested diff --git a/icons.qrc b/icons.qrc index cd77e912..ab4318dc 100644 --- a/icons.qrc +++ b/icons.qrc @@ -63,6 +63,7 @@ icons/unconfirmed.png icons/unpaid.png icons/unlock.png + icons/update.png icons/warning.png icons/zoom.png diff --git a/icons/update.png b/icons/update.png new file mode 100644 index 00000000..e774ee10 Binary files /dev/null and b/icons/update.png differ