aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/devtools/optimize-pngs.py73
-rw-r--r--contrib/gitian-downloader/jonasschnelli.pgpbin0 -> 4460 bytes
-rw-r--r--depends/packages/openssl.mk6
-rw-r--r--doc/build-osx.md16
-rwxr-xr-xqa/rpc-tests/httpbasics.py26
-rwxr-xr-xqa/rpc-tests/test_framework.py5
-rw-r--r--src/ecwrapper.cpp30
-rw-r--r--src/init.cpp28
-rw-r--r--src/main.cpp18
-rw-r--r--src/qt/bitcoinamountfield.cpp39
-rw-r--r--src/qt/bitcoingui.cpp20
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/forms/signverifymessagedialog.ui4
-rw-r--r--src/qt/paymentrequestplus.cpp10
-rw-r--r--src/qt/paymentserver.cpp32
-rw-r--r--src/qt/paymentserver.h3
-rw-r--r--src/qt/res/icons/about.pngbin5925 -> 4726 bytes
-rw-r--r--src/qt/res/icons/about_qt.pngbin3107 -> 2338 bytes
-rw-r--r--src/qt/res/icons/add.pngbin15199 -> 712 bytes
-rw-r--r--src/qt/res/icons/address-book.pngbin16150 -> 1275 bytes
-rw-r--r--src/qt/res/icons/bitcoin.pngbin350390 -> 312944 bytes
-rw-r--r--src/qt/res/icons/clock1.pngbin2448 -> 1921 bytes
-rw-r--r--src/qt/res/icons/clock2.pngbin2269 -> 1731 bytes
-rw-r--r--src/qt/res/icons/clock3.pngbin2184 -> 1557 bytes
-rw-r--r--src/qt/res/icons/clock4.pngbin1995 -> 1395 bytes
-rw-r--r--src/qt/res/icons/clock5.pngbin2682 -> 1889 bytes
-rw-r--r--src/qt/res/icons/configure.pngbin3891 -> 2865 bytes
-rw-r--r--src/qt/res/icons/connect0.pngbin16890 -> 2290 bytes
-rw-r--r--src/qt/res/icons/connect1.pngbin16870 -> 2242 bytes
-rw-r--r--src/qt/res/icons/connect2.pngbin16566 -> 1966 bytes
-rw-r--r--src/qt/res/icons/connect3.pngbin16566 -> 1966 bytes
-rw-r--r--src/qt/res/icons/connect4.pngbin16117 -> 1490 bytes
-rw-r--r--src/qt/res/icons/debugwindow.pngbin15930 -> 1327 bytes
-rw-r--r--src/qt/res/icons/edit.pngbin2544 -> 1847 bytes
-rw-r--r--src/qt/res/icons/editcopy.pngbin1295 -> 883 bytes
-rw-r--r--src/qt/res/icons/editpaste.pngbin15778 -> 1024 bytes
-rw-r--r--src/qt/res/icons/export.pngbin17005 -> 1750 bytes
-rw-r--r--src/qt/res/icons/eye.pngbin2806 -> 2241 bytes
-rw-r--r--src/qt/res/icons/eye_minus.pngbin3087 -> 2438 bytes
-rw-r--r--src/qt/res/icons/eye_plus.pngbin3368 -> 2599 bytes
-rw-r--r--src/qt/res/icons/filesave.pngbin2874 -> 2067 bytes
-rw-r--r--src/qt/res/icons/history.pngbin16271 -> 762 bytes
-rw-r--r--src/qt/res/icons/info.pngbin2895 -> 2028 bytes
-rw-r--r--src/qt/res/icons/key.pngbin2434 -> 1759 bytes
-rw-r--r--src/qt/res/icons/lock_closed.pngbin1686 -> 1197 bytes
-rw-r--r--src/qt/res/icons/lock_open.pngbin1751 -> 1257 bytes
-rw-r--r--src/qt/res/icons/open.pngbin2239 -> 1694 bytes
-rw-r--r--src/qt/res/icons/overview.pngbin2215 -> 1662 bytes
-rw-r--r--src/qt/res/icons/quit.pngbin15766 -> 1091 bytes
-rw-r--r--src/qt/res/icons/receive.pngbin2874 -> 2067 bytes
-rw-r--r--src/qt/res/icons/remove.pngbin16663 -> 1723 bytes
-rw-r--r--src/qt/res/icons/send.pngbin17005 -> 1750 bytes
-rw-r--r--src/qt/res/icons/synced.pngbin16891 -> 1619 bytes
-rw-r--r--src/qt/res/icons/transaction0.pngbin1759 -> 1220 bytes
-rw-r--r--src/qt/res/icons/transaction2.pngbin16891 -> 1619 bytes
-rw-r--r--src/qt/res/icons/transaction_conflicted.pngbin15766 -> 1091 bytes
-rw-r--r--src/qt/res/icons/tx_inout.pngbin2568 -> 1655 bytes
-rw-r--r--src/qt/res/icons/tx_input.pngbin2590 -> 1783 bytes
-rw-r--r--src/qt/res/icons/tx_mined.pngbin2166 -> 1578 bytes
-rw-r--r--src/qt/res/icons/tx_output.pngbin2699 -> 1771 bytes
-rw-r--r--src/qt/res/icons/verify.pngbin2984 -> 2034 bytes
-rw-r--r--src/qt/res/movies/spinner-000.pngbin16636 -> 1835 bytes
-rw-r--r--src/qt/res/movies/spinner-001.pngbin2785 -> 2376 bytes
-rw-r--r--src/qt/res/movies/spinner-002.pngbin2814 -> 2376 bytes
-rw-r--r--src/qt/res/movies/spinner-003.pngbin2775 -> 2355 bytes
-rw-r--r--src/qt/res/movies/spinner-004.pngbin2850 -> 2349 bytes
-rw-r--r--src/qt/res/movies/spinner-005.pngbin2728 -> 2305 bytes
-rw-r--r--src/qt/res/movies/spinner-006.pngbin2734 -> 2304 bytes
-rw-r--r--src/qt/res/movies/spinner-007.pngbin2633 -> 2283 bytes
-rw-r--r--src/qt/res/movies/spinner-008.pngbin2611 -> 2312 bytes
-rw-r--r--src/qt/res/movies/spinner-009.pngbin2074 -> 1810 bytes
-rw-r--r--src/qt/res/movies/spinner-010.pngbin2666 -> 2305 bytes
-rw-r--r--src/qt/res/movies/spinner-011.pngbin2751 -> 2338 bytes
-rw-r--r--src/qt/res/movies/spinner-012.pngbin2828 -> 2352 bytes
-rw-r--r--src/qt/res/movies/spinner-013.pngbin2896 -> 2377 bytes
-rw-r--r--src/qt/res/movies/spinner-014.pngbin2867 -> 2358 bytes
-rw-r--r--src/qt/res/movies/spinner-015.pngbin2860 -> 2405 bytes
-rw-r--r--src/qt/res/movies/spinner-016.pngbin2825 -> 2429 bytes
-rw-r--r--src/qt/res/movies/spinner-017.pngbin2833 -> 2408 bytes
-rw-r--r--src/qt/res/movies/spinner-018.pngbin2147 -> 1831 bytes
-rw-r--r--src/qt/res/movies/spinner-019.pngbin2808 -> 2380 bytes
-rw-r--r--src/qt/res/movies/spinner-020.pngbin2800 -> 2366 bytes
-rw-r--r--src/qt/res/movies/spinner-021.pngbin2833 -> 2368 bytes
-rw-r--r--src/qt/res/movies/spinner-022.pngbin2823 -> 2356 bytes
-rw-r--r--src/qt/res/movies/spinner-023.pngbin2710 -> 2311 bytes
-rw-r--r--src/qt/res/movies/spinner-024.pngbin2732 -> 2315 bytes
-rw-r--r--src/qt/res/movies/spinner-025.pngbin2635 -> 2298 bytes
-rw-r--r--src/qt/res/movies/spinner-026.pngbin2643 -> 2291 bytes
-rw-r--r--src/qt/res/movies/spinner-027.pngbin2099 -> 1816 bytes
-rw-r--r--src/qt/res/movies/spinner-028.pngbin2665 -> 2308 bytes
-rw-r--r--src/qt/res/movies/spinner-029.pngbin2761 -> 2356 bytes
-rw-r--r--src/qt/res/movies/spinner-030.pngbin2832 -> 2346 bytes
-rw-r--r--src/qt/res/movies/spinner-031.pngbin2871 -> 2380 bytes
-rw-r--r--src/qt/res/movies/spinner-032.pngbin2839 -> 2345 bytes
-rw-r--r--src/qt/res/movies/spinner-033.pngbin2829 -> 2401 bytes
-rw-r--r--src/qt/res/movies/spinner-034.pngbin2851 -> 2422 bytes
-rw-r--r--src/qt/res/movies/spinner-035.pngbin2837 -> 2406 bytes
-rw-r--r--src/qt/test/paymentrequestdata.h76
-rw-r--r--src/qt/test/paymentservertests.cpp56
-rw-r--r--src/qt/utilitydialog.cpp7
-rw-r--r--src/rpcserver.cpp2
101 files changed, 379 insertions, 74 deletions
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
new file mode 100755
index 0000000000..38aaa00f31
--- /dev/null
+++ b/contrib/devtools/optimize-pngs.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import subprocess
+import hashlib
+from PIL import Image
+
+def file_hash(filename):
+ '''Return hash of raw file contents'''
+ with open(filename, 'rb') as f:
+ return hashlib.sha256(f.read()).hexdigest()
+
+def content_hash(filename):
+ '''Return hash of RGBA contents of image'''
+ i = Image.open(filename)
+ i = i.convert('RGBA')
+ data = i.tostring()
+ return hashlib.sha256(data).hexdigest()
+
+#optimize png, remove various color profiles, remove ancillary chunks (alla) and text chunks (text)
+#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text
+
+pngcrush = 'pngcrush'
+git = 'git'
+folders = ["src/qt/res/movies", "src/qt/res/icons", "src/qt/res/images"]
+basePath = subprocess.check_output([git, 'rev-parse', '--show-toplevel']).rstrip('\n')
+totalSaveBytes = 0
+
+outputArray = []
+for folder in folders:
+ absFolder=os.path.join(basePath, folder)
+ for file in os.listdir(absFolder):
+ extension = os.path.splitext(file)[1]
+ if extension.lower() == '.png':
+ print("optimizing "+file+"..."),
+ file_path = os.path.join(absFolder, file)
+ fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)};
+ fileMetaMap['contentHashPre'] = content_hash(file_path)
+
+ pngCrushOutput = ""
+ try:
+ pngCrushOutput = subprocess.check_output(
+ [pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path],
+ stderr=subprocess.STDOUT).rstrip('\n')
+ except:
+ print "pngcrush is not installed, aborting..."
+ sys.exit(0)
+
+ #verify
+ if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT):
+ print "PNG file "+file+" is corrupted after crushing, check out pngcursh version"
+ sys.exit(1)
+
+ fileMetaMap['sha256New'] = file_hash(file_path)
+ fileMetaMap['contentHashPost'] = content_hash(file_path)
+
+ if fileMetaMap['contentHashPre'] != fileMetaMap['contentHashPost']:
+ print "Image contents of PNG file "+file+" before and after crushing don't match"
+ sys.exit(1)
+
+ fileMetaMap['psize'] = os.path.getsize(file_path)
+ outputArray.append(fileMetaMap)
+ print("done\n"),
+
+print "summary:\n+++++++++++++++++"
+for fileDict in outputArray:
+ oldHash = fileDict['sha256Old']
+ newHash = fileDict['sha256New']
+ totalSaveBytes += fileDict['osize'] - fileDict['psize']
+ print fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n"
+
+print "completed. Total reduction: "+str(totalSaveBytes)+" bytes"
diff --git a/contrib/gitian-downloader/jonasschnelli.pgp b/contrib/gitian-downloader/jonasschnelli.pgp
new file mode 100644
index 0000000000..96140fe171
--- /dev/null
+++ b/contrib/gitian-downloader/jonasschnelli.pgp
Binary files differ
diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk
index ad64494c1f..22b1017ffc 100644
--- a/depends/packages/openssl.mk
+++ b/depends/packages/openssl.mk
@@ -1,8 +1,8 @@
package=openssl
-$(package)_version=1.0.1j
+$(package)_version=1.0.1k
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=1b60ca8789ba6f03e8ef20da2293b8dc131c39d83814e775069f02d26354edf3
+$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
@@ -23,7 +23,7 @@ $(package)_config_opts_i686_mingw32=mingw
endef
define $(package)_preprocess_cmds
- sed -i.old "/define DATE/d" crypto/Makefile && \
+ sed -i.old "/define DATE/d" util/mkbuildinf.pl && \
sed -i.old "s|engines apps test|engines|" Makefile.org
endef
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c41820f2b1..d6e93cb23d 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -21,12 +21,6 @@ Xcode 4.3 or later, you'll need to install its command line tools. This can
be done in `Xcode > Preferences > Downloads > Components` and generally must
be re-done or updated every time Xcode is updated.
-There's also an assumption that you already have `git` installed. If
-not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/)
-(OS X 10.7+) or
-[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also
-available via Homebrew.
-
You will also need to install [Homebrew](http://brew.sh) in order to install library
dependencies.
@@ -38,7 +32,9 @@ Instructions: Homebrew
#### Install dependencies using Homebrew
- brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt
+ brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt5
+
+NOTE: Building with Qt4 is still supported, however, could result in a broken UI. As such, building with Qt5 is recommended.
#### Installing berkeley-db4 using Homebrew
@@ -46,7 +42,7 @@ The homebrew package for berkeley-db4 has been broken for some time. It will in
Running this command takes you into brew's interactive mode, which allows you to configure, make, and install by hand:
```
-$ brew install https://raw.github.com/mxcl/homebrew/master/Library/Formula/berkeley-db4.rb -–without-java
+$ brew install https://raw.github.com/homebrew/homebrew/master/Library/Formula/berkeley-db4.rb -–without-java
```
The rest of these commands are run inside brew interactive mode:
@@ -73,7 +69,7 @@ After exiting, you'll get a warning that the install is keg-only, which means it
2. Build bitcoind:
./autogen.sh
- ./configure
+ ./configure --with-gui=qt5
make
3. It is also a good idea to build and run the unit tests:
@@ -115,7 +111,7 @@ All dependencies should be compiled with these flags:
-arch x86_64
-isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk
-Once dependencies are compiled, see release-process.md for how the Bitcoin-Qt.app
+Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin-Qt.app
bundle is packaged and signed to create the .dmg disk image that is distributed.
Running
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index 85e85e7f0f..8cbf1d7f4c 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -21,6 +21,9 @@ except ImportError:
import urlparse
class HTTPBasicsTest (BitcoinTestFramework):
+ def setup_nodes(self):
+ return start_nodes(4, self.options.tmpdir, extra_args=[['-rpckeepalive=1'], ['-rpckeepalive=0'], [], []])
+
def run_test(self):
#################################################
@@ -71,6 +74,29 @@ class HTTPBasicsTest (BitcoinTestFramework):
assert_equal('"error":null' in out1, True)
assert_equal(conn.sock!=None, False) #now the connection must be closed after the response
+ #node1 (2nd node) is running with disabled keep-alive option
+ urlNode1 = urlparse.urlparse(self.nodes[1].url)
+ authpair = urlNode1.username + ':' + urlNode1.password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port)
+ conn.connect()
+ conn.request('GET', '/', '{"method": "getbestblockhash"}', headers)
+ out1 = conn.getresponse().read();
+ assert_equal('"error":null' in out1, True)
+ assert_equal(conn.sock!=None, False) #connection must be closed because keep-alive was set to false
+
+ #node2 (third node) is running with standard keep-alive parameters which means keep-alive is off
+ urlNode2 = urlparse.urlparse(self.nodes[2].url)
+ authpair = urlNode2.username + ':' + urlNode2.password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port)
+ conn.connect()
+ conn.request('GET', '/', '{"method": "getbestblockhash"}', headers)
+ out1 = conn.getresponse().read();
+ assert_equal('"error":null' in out1, True)
+ assert_equal(conn.sock!=None, False) #connection must be closed because bitcoind should use keep-alive by default
if __name__ == '__main__':
HTTPBasicsTest ().main ()
diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py
index 6c4ec073c2..4c8a11b821 100755
--- a/qa/rpc-tests/test_framework.py
+++ b/qa/rpc-tests/test_framework.py
@@ -33,8 +33,11 @@ class BitcoinTestFramework(object):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
+ def setup_nodes(self):
+ return start_nodes(4, self.options.tmpdir)
+
def setup_network(self, split = False):
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = self.setup_nodes()
# Connect the nodes as a "chain". This allows us
# to split the network between nodes 1 and 2 to get
diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp
index c29390eb98..5e3aec25ba 100644
--- a/src/ecwrapper.cpp
+++ b/src/ecwrapper.cpp
@@ -117,10 +117,34 @@ bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) {
}
bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
- // -1 = error, 0 = bad sig, 1 = good
- if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+ if (vchSig.empty())
return false;
- return true;
+
+ // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
+ unsigned char *norm_der = NULL;
+ ECDSA_SIG *norm_sig = ECDSA_SIG_new();
+ const unsigned char* sigptr = &vchSig[0];
+ assert(norm_sig);
+ if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL)
+ {
+ /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on
+ * error. But OpenSSL's own use of this function redundantly frees the
+ * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a
+ * clear contract for the function behaving the same way is more
+ * conservative.
+ */
+ ECDSA_SIG_free(norm_sig);
+ return false;
+ }
+ int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der);
+ ECDSA_SIG_free(norm_sig);
+ if (derlen <= 0)
+ return false;
+
+ // -1 = error, 0 = bad sig, 1 = good
+ bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1;
+ OPENSSL_free(norm_der);
+ return ret;
}
bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
diff --git a/src/init.cpp b/src/init.cpp
index 03d67f0aa3..f851fcbbca 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -111,7 +111,28 @@ bool ShutdownRequested()
return fRequestShutdown;
}
+class CCoinsViewErrorCatcher : public CCoinsViewBacked
+{
+public:
+ CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
+ bool GetCoins(const uint256 &txid, CCoins &coins) const {
+ try {
+ return CCoinsViewBacked::GetCoins(txid, coins);
+ } catch(const std::runtime_error& e) {
+ uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR);
+ LogPrintf("Error reading from database: %s\n", e.what());
+ // Starting the shutdown sequence and returning false to the caller would be
+ // interpreted as 'entry not found' (as opposed to unable to read data), and
+ // could lead to invalid interpration. Just exit immediately, as we can't
+ // continue anyway, and all writes should be atomic.
+ abort();
+ }
+ }
+ // Writes do not need similar protection, as failure to write is handled by the caller.
+};
+
static CCoinsViewDB *pcoinsdbview = NULL;
+static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
void Shutdown()
{
@@ -154,6 +175,8 @@ void Shutdown()
}
delete pcoinsTip;
pcoinsTip = NULL;
+ delete pcoinscatcher;
+ pcoinscatcher = NULL;
delete pcoinsdbview;
pcoinsdbview = NULL;
delete pblocktree;
@@ -357,6 +380,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -rpcport=<port> " + strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n";
strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times") + "\n";
strUsage += " -rpcthreads=<n> " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n";
+ strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 0) + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
@@ -990,11 +1014,13 @@ bool AppInit2(boost::thread_group& threadGroup)
UnloadBlockIndex();
delete pcoinsTip;
delete pcoinsdbview;
+ delete pcoinscatcher;
delete pblocktree;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
- pcoinsTip = new CCoinsViewCache(pcoinsdbview);
+ pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
+ pcoinsTip = new CCoinsViewCache(pcoinscatcher);
if (fReindex)
pblocktree->WriteReindexing(true);
diff --git a/src/main.cpp b/src/main.cpp
index 2e9d954458..7cc69c318b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -139,9 +139,14 @@ namespace {
uint256 hash;
CBlockIndex *pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds.
+ int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested.
+ bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
+ /** Number of blocks in flight with validated headers. */
+ int nQueuedValidatedHeaders = 0;
+
/** Number of preferable block download peers. */
int nPreferredDownload = 0;
@@ -323,6 +328,7 @@ void MarkBlockAsReceived(const uint256& hash) {
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
+ nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
state->nStallingSince = 0;
@@ -338,7 +344,8 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
- QueuedBlock newentry = {hash, pindex, GetTimeMicros()};
+ QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL};
+ nQueuedValidatedHeaders += newentry.fValidatedHeaders;
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
@@ -4527,6 +4534,15 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true;
}
+ // In case there is a block that has been in flight from this peer for (1 + 0.5 * N) times the block interval
+ // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
+ // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
+ // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
+ // to unreasonably increase our timeout.
+ if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (2 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
+ LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id);
+ pto->fDisconnect = true;
+ }
//
// Message: getdata (blocks)
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index fdb9bcd6d6..4c00aca985 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -20,6 +20,7 @@
class AmountSpinBox: public QAbstractSpinBox
{
Q_OBJECT
+
public:
explicit AmountSpinBox(QWidget *parent):
QAbstractSpinBox(parent),
@@ -72,23 +73,6 @@ public:
setValue(val);
}
- StepEnabled stepEnabled() const
- {
- StepEnabled rv = 0;
- if(text().isEmpty()) // Allow step-up with empty field
- return StepUpEnabled;
- bool valid = false;
- CAmount val = value(&valid);
- if(valid)
- {
- if(val > 0)
- rv |= StepDownEnabled;
- if(val < BitcoinUnits::maxMoney())
- rv |= StepUpEnabled;
- }
- return rv;
- }
-
void setDisplayUnit(int unit)
{
bool valid = false;
@@ -139,6 +123,7 @@ public:
}
return cachedMinimumSizeHint;
}
+
private:
int currentUnit;
CAmount singleStep;
@@ -179,6 +164,26 @@ protected:
return QAbstractSpinBox::event(event);
}
+ StepEnabled stepEnabled() const
+ {
+ if (isReadOnly()) // Disable steps when AmountSpinBox is read-only
+ return StepNone;
+ if (text().isEmpty()) // Allow step-up with empty field
+ return StepUpEnabled;
+
+ StepEnabled rv = 0;
+ bool valid = false;
+ CAmount val = value(&valid);
+ if(valid)
+ {
+ if(val > 0)
+ rv |= StepDownEnabled;
+ if(val < BitcoinUnits::maxMoney())
+ rv |= StepUpEnabled;
+ }
+ return rv;
+ }
+
signals:
void valueChanged();
};
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2810eae052..3d41dc89f1 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -76,12 +76,14 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
historyAction(0),
quitAction(0),
sendCoinsAction(0),
+ sendCoinsMenuAction(0),
usedSendingAddressesAction(0),
usedReceivingAddressesAction(0),
signMessageAction(0),
verifyMessageAction(0),
aboutAction(0),
receiveCoinsAction(0),
+ receiveCoinsMenuAction(0),
optionsAction(0),
toggleHideAction(0),
encryptWalletAction(0),
@@ -256,6 +258,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
+ sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
+ sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
+ sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
+
receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
@@ -263,6 +269,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
+ receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
+ receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
+ receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
+
historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setStatusTip(tr("Browse transaction history"));
historyAction->setToolTip(historyAction->statusTip());
@@ -277,8 +287,12 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
+ connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
+ connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
+ connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
+ connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
#endif // ENABLE_WALLET
@@ -475,7 +489,9 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
{
overviewAction->setEnabled(enabled);
sendCoinsAction->setEnabled(enabled);
+ sendCoinsMenuAction->setEnabled(enabled);
receiveCoinsAction->setEnabled(enabled);
+ receiveCoinsMenuAction->setEnabled(enabled);
historyAction->setEnabled(enabled);
encryptWalletAction->setEnabled(enabled);
backupWalletAction->setEnabled(enabled);
@@ -522,8 +538,8 @@ void BitcoinGUI::createTrayIconMenu()
// Configuration of the tray icon (or dock icon) icon menu
trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addSeparator();
- trayIconMenu->addAction(sendCoinsAction);
- trayIconMenu->addAction(receiveCoinsAction);
+ trayIconMenu->addAction(sendCoinsMenuAction);
+ trayIconMenu->addAction(receiveCoinsMenuAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(signMessageAction);
trayIconMenu->addAction(verifyMessageAction);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 7509a00734..3216a7398e 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -90,12 +90,14 @@ private:
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
+ QAction *sendCoinsMenuAction;
QAction *usedSendingAddressesAction;
QAction *usedReceivingAddressesAction;
QAction *signMessageAction;
QAction *verifyMessageAction;
QAction *aboutAction;
QAction *receiveCoinsAction;
+ QAction *receiveCoinsMenuAction;
QAction *optionsAction;
QAction *toggleHideAction;
QAction *encryptWalletAction;
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
index 40b2da3228..92f6430c51 100644
--- a/src/qt/forms/signverifymessagedialog.ui
+++ b/src/qt/forms/signverifymessagedialog.ui
@@ -30,7 +30,7 @@
<item>
<widget class="QLabel" name="infoLabel_SM">
<property name="text">
- <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string>
+ <string>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@@ -237,7 +237,7 @@
<item>
<widget class="QLabel" name="infoLabel_VM">
<property name="text">
- <string>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</string>
+ <string>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 35846bc153..39171c89eb 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -9,6 +9,8 @@
#include "paymentrequestplus.h"
+#include "util.h"
+
#include <stdexcept>
#include <openssl/x509.h>
@@ -150,7 +152,13 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
int result = X509_verify_cert(store_ctx);
if (result != 1) {
int error = X509_STORE_CTX_get_error(store_ctx);
- throw SSLVerifyError(X509_verify_cert_error_string(error));
+ // For testing payment requests, we allow self signed root certs!
+ // This option is just shown in the UI options, if -help-debug is enabled.
+ if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", false))) {
+ throw SSLVerifyError(X509_verify_cert_error_string(error));
+ } else {
+ qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true.";
+ }
}
X509_NAME *certname = X509_get_subject_name(signing_cert);
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 66331ee4b4..d642fdae36 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -124,19 +124,22 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// and get 'I don't like X.509 certificates, don't trust anybody' behavior:
QString certFile = QString::fromStdString(GetArg("-rootcertificates", "-system-"));
- if (certFile.isEmpty())
- return; // Empty store
+ // Empty store
+ if (certFile.isEmpty()) {
+ qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
+ return;
+ }
QList<QSslCertificate> certList;
- if (certFile != "-system-")
- {
+ if (certFile != "-system-") {
+ qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
+
certList = QSslCertificate::fromPath(certFile);
// Use those certificates when fetching payment requests, too:
QSslSocket::setDefaultCaCertificates(certList);
- }
- else
- certList = QSslSocket::systemCaCertificates ();
+ } else
+ certList = QSslSocket::systemCaCertificates();
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
@@ -521,8 +524,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
const payments::PaymentDetails& details = request.getDetails();
// Payment request network matches client network?
- if (details.network() != Params().NetworkIDString())
- {
+ if (!verifyNetwork(request.getDetails())) {
emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
CClientUIInterface::MSG_ERROR);
@@ -745,3 +747,15 @@ void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
// currently we don't futher process or store the paymentACK message
emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
}
+
+bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
+{
+ bool fVerified = requestDetails.network() == Params().NetworkIDString();
+ if (!fVerified) {
+ qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
+ .arg(__func__)
+ .arg(QString::fromStdString(requestDetails.network()))
+ .arg(QString::fromStdString(Params().NetworkIDString()));
+ }
+ return fVerified;
+}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 2fc24395f6..9330e9a89c 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -91,6 +91,9 @@ public:
// This is now public, because we use it in paymentservertests.cpp
static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
+ // Verify that the payment request network matches the client network
+ static bool verifyNetwork(const payments::PaymentDetails& requestDetails);
+
signals:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png
index eeef943355..83eb3c07ee 100644
--- a/src/qt/res/icons/about.png
+++ b/src/qt/res/icons/about.png
Binary files differ
diff --git a/src/qt/res/icons/about_qt.png b/src/qt/res/icons/about_qt.png
index d3665e9892..dd27a99d0a 100644
--- a/src/qt/res/icons/about_qt.png
+++ b/src/qt/res/icons/about_qt.png
Binary files differ
diff --git a/src/qt/res/icons/add.png b/src/qt/res/icons/add.png
index ef995cc0b5..7e46672f2d 100644
--- a/src/qt/res/icons/add.png
+++ b/src/qt/res/icons/add.png
Binary files differ
diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png
index 0c9238c18e..b11c7d5356 100644
--- a/src/qt/res/icons/address-book.png
+++ b/src/qt/res/icons/address-book.png
Binary files differ
diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png
index 705a20260a..435621af23 100644
--- a/src/qt/res/icons/bitcoin.png
+++ b/src/qt/res/icons/bitcoin.png
Binary files differ
diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png
index 65adba5e21..ceae5ed0d9 100644
--- a/src/qt/res/icons/clock1.png
+++ b/src/qt/res/icons/clock1.png
Binary files differ
diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png
index 196a79ce4a..159f69a8fc 100644
--- a/src/qt/res/icons/clock2.png
+++ b/src/qt/res/icons/clock2.png
Binary files differ
diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png
index 3d04655ed9..d668e35ffc 100644
--- a/src/qt/res/icons/clock3.png
+++ b/src/qt/res/icons/clock3.png
Binary files differ
diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png
index c3210c5af1..5ebf8ed7ac 100644
--- a/src/qt/res/icons/clock4.png
+++ b/src/qt/res/icons/clock4.png
Binary files differ
diff --git a/src/qt/res/icons/clock5.png b/src/qt/res/icons/clock5.png
index 84a9fa2842..96f15ef7d9 100644
--- a/src/qt/res/icons/clock5.png
+++ b/src/qt/res/icons/clock5.png
Binary files differ
diff --git a/src/qt/res/icons/configure.png b/src/qt/res/icons/configure.png
index fe9c6ec5ec..5333c83d5e 100644
--- a/src/qt/res/icons/configure.png
+++ b/src/qt/res/icons/configure.png
Binary files differ
diff --git a/src/qt/res/icons/connect0.png b/src/qt/res/icons/connect0.png
index 99bb2575d6..58e2c3e965 100644
--- a/src/qt/res/icons/connect0.png
+++ b/src/qt/res/icons/connect0.png
Binary files differ
diff --git a/src/qt/res/icons/connect1.png b/src/qt/res/icons/connect1.png
index dffc692c76..949e7a922d 100644
--- a/src/qt/res/icons/connect1.png
+++ b/src/qt/res/icons/connect1.png
Binary files differ
diff --git a/src/qt/res/icons/connect2.png b/src/qt/res/icons/connect2.png
index 3594fb117c..143b2054fb 100644
--- a/src/qt/res/icons/connect2.png
+++ b/src/qt/res/icons/connect2.png
Binary files differ
diff --git a/src/qt/res/icons/connect3.png b/src/qt/res/icons/connect3.png
index 3594fb117c..143b2054fb 100644
--- a/src/qt/res/icons/connect3.png
+++ b/src/qt/res/icons/connect3.png
Binary files differ
diff --git a/src/qt/res/icons/connect4.png b/src/qt/res/icons/connect4.png
index 0c667c7e06..f96e3455ce 100644
--- a/src/qt/res/icons/connect4.png
+++ b/src/qt/res/icons/connect4.png
Binary files differ
diff --git a/src/qt/res/icons/debugwindow.png b/src/qt/res/icons/debugwindow.png
index 576e57ab03..290fe60864 100644
--- a/src/qt/res/icons/debugwindow.png
+++ b/src/qt/res/icons/debugwindow.png
Binary files differ
diff --git a/src/qt/res/icons/edit.png b/src/qt/res/icons/edit.png
index 4df2229e98..46582716ef 100644
--- a/src/qt/res/icons/edit.png
+++ b/src/qt/res/icons/edit.png
Binary files differ
diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png
index db0c51772c..74ac8b2774 100644
--- a/src/qt/res/icons/editcopy.png
+++ b/src/qt/res/icons/editcopy.png
Binary files differ
diff --git a/src/qt/res/icons/editpaste.png b/src/qt/res/icons/editpaste.png
index be8634674d..7b47f4d52b 100644
--- a/src/qt/res/icons/editpaste.png
+++ b/src/qt/res/icons/editpaste.png
Binary files differ
diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png
index 18d0596194..ac76cc1eff 100644
--- a/src/qt/res/icons/export.png
+++ b/src/qt/res/icons/export.png
Binary files differ
diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png
index 7036708de5..f2f139dbb2 100644
--- a/src/qt/res/icons/eye.png
+++ b/src/qt/res/icons/eye.png
Binary files differ
diff --git a/src/qt/res/icons/eye_minus.png b/src/qt/res/icons/eye_minus.png
index bdbe073627..795bf6436a 100644
--- a/src/qt/res/icons/eye_minus.png
+++ b/src/qt/res/icons/eye_minus.png
Binary files differ
diff --git a/src/qt/res/icons/eye_plus.png b/src/qt/res/icons/eye_plus.png
index 2ba5e68c76..eaab69297a 100644
--- a/src/qt/res/icons/eye_plus.png
+++ b/src/qt/res/icons/eye_plus.png
Binary files differ
diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png
index a53390f594..f4e6f58d05 100644
--- a/src/qt/res/icons/filesave.png
+++ b/src/qt/res/icons/filesave.png
Binary files differ
diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png
index cb723abc5f..68d841fa85 100644
--- a/src/qt/res/icons/history.png
+++ b/src/qt/res/icons/history.png
Binary files differ
diff --git a/src/qt/res/icons/info.png b/src/qt/res/icons/info.png
index 085fa8ea73..692b50c2a9 100644
--- a/src/qt/res/icons/info.png
+++ b/src/qt/res/icons/info.png
Binary files differ
diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png
index d21f81364d..f301c4f38c 100644
--- a/src/qt/res/icons/key.png
+++ b/src/qt/res/icons/key.png
Binary files differ
diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png
index 77914ab2ce..1bd98b21a6 100644
--- a/src/qt/res/icons/lock_closed.png
+++ b/src/qt/res/icons/lock_closed.png
Binary files differ
diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png
index 50615b7336..a7045133b1 100644
--- a/src/qt/res/icons/lock_open.png
+++ b/src/qt/res/icons/lock_open.png
Binary files differ
diff --git a/src/qt/res/icons/open.png b/src/qt/res/icons/open.png
index 390d3dab64..4d958f0e18 100644
--- a/src/qt/res/icons/open.png
+++ b/src/qt/res/icons/open.png
Binary files differ
diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png
index 36e1003c3c..411595413d 100644
--- a/src/qt/res/icons/overview.png
+++ b/src/qt/res/icons/overview.png
Binary files differ
diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png
index 6e44a2d329..55e34de4b8 100644
--- a/src/qt/res/icons/quit.png
+++ b/src/qt/res/icons/quit.png
Binary files differ
diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png
index a53390f594..f4e6f58d05 100644
--- a/src/qt/res/icons/receive.png
+++ b/src/qt/res/icons/receive.png
Binary files differ
diff --git a/src/qt/res/icons/remove.png b/src/qt/res/icons/remove.png
index 3849cdd6d8..8e738d6301 100644
--- a/src/qt/res/icons/remove.png
+++ b/src/qt/res/icons/remove.png
Binary files differ
diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png
index 18d0596194..ac76cc1eff 100644
--- a/src/qt/res/icons/send.png
+++ b/src/qt/res/icons/send.png
Binary files differ
diff --git a/src/qt/res/icons/synced.png b/src/qt/res/icons/synced.png
index d33914f0b4..5ac28d36a3 100644
--- a/src/qt/res/icons/synced.png
+++ b/src/qt/res/icons/synced.png
Binary files differ
diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png
index fd41da0680..1091b86e68 100644
--- a/src/qt/res/icons/transaction0.png
+++ b/src/qt/res/icons/transaction0.png
Binary files differ
diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png
index d33914f0b4..5ac28d36a3 100644
--- a/src/qt/res/icons/transaction2.png
+++ b/src/qt/res/icons/transaction2.png
Binary files differ
diff --git a/src/qt/res/icons/transaction_conflicted.png b/src/qt/res/icons/transaction_conflicted.png
index 6e44a2d329..55e34de4b8 100644
--- a/src/qt/res/icons/transaction_conflicted.png
+++ b/src/qt/res/icons/transaction_conflicted.png
Binary files differ
diff --git a/src/qt/res/icons/tx_inout.png b/src/qt/res/icons/tx_inout.png
index cecd332ad1..0a6e72a898 100644
--- a/src/qt/res/icons/tx_inout.png
+++ b/src/qt/res/icons/tx_inout.png
Binary files differ
diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png
index 1b4cfd967c..9e9ee92932 100644
--- a/src/qt/res/icons/tx_input.png
+++ b/src/qt/res/icons/tx_input.png
Binary files differ
diff --git a/src/qt/res/icons/tx_mined.png b/src/qt/res/icons/tx_mined.png
index 421a9cf639..5a6ef521c0 100644
--- a/src/qt/res/icons/tx_mined.png
+++ b/src/qt/res/icons/tx_mined.png
Binary files differ
diff --git a/src/qt/res/icons/tx_output.png b/src/qt/res/icons/tx_output.png
index 06d9d0adf2..6f66ab6547 100644
--- a/src/qt/res/icons/tx_output.png
+++ b/src/qt/res/icons/tx_output.png
Binary files differ
diff --git a/src/qt/res/icons/verify.png b/src/qt/res/icons/verify.png
index 9ff35c2793..8e2cb2cc14 100644
--- a/src/qt/res/icons/verify.png
+++ b/src/qt/res/icons/verify.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-000.png b/src/qt/res/movies/spinner-000.png
index b296a58481..1e92d859da 100644
--- a/src/qt/res/movies/spinner-000.png
+++ b/src/qt/res/movies/spinner-000.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-001.png b/src/qt/res/movies/spinner-001.png
index 4f6f9a487b..d167f20541 100644
--- a/src/qt/res/movies/spinner-001.png
+++ b/src/qt/res/movies/spinner-001.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-002.png b/src/qt/res/movies/spinner-002.png
index 4f14e3ca93..4a1f1f8e56 100644
--- a/src/qt/res/movies/spinner-002.png
+++ b/src/qt/res/movies/spinner-002.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-003.png b/src/qt/res/movies/spinner-003.png
index d7756e73bf..fb1c2cd4ad 100644
--- a/src/qt/res/movies/spinner-003.png
+++ b/src/qt/res/movies/spinner-003.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-004.png b/src/qt/res/movies/spinner-004.png
index 4b381b81b2..4df2132344 100644
--- a/src/qt/res/movies/spinner-004.png
+++ b/src/qt/res/movies/spinner-004.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-005.png b/src/qt/res/movies/spinner-005.png
index cbdb5b5797..5d6f41e0dc 100644
--- a/src/qt/res/movies/spinner-005.png
+++ b/src/qt/res/movies/spinner-005.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-006.png b/src/qt/res/movies/spinner-006.png
index 55d4540c92..c1f7d18899 100644
--- a/src/qt/res/movies/spinner-006.png
+++ b/src/qt/res/movies/spinner-006.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-007.png b/src/qt/res/movies/spinner-007.png
index b25f59a445..1e794b2626 100644
--- a/src/qt/res/movies/spinner-007.png
+++ b/src/qt/res/movies/spinner-007.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-008.png b/src/qt/res/movies/spinner-008.png
index 6493184a7a..df12ea8719 100644
--- a/src/qt/res/movies/spinner-008.png
+++ b/src/qt/res/movies/spinner-008.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-009.png b/src/qt/res/movies/spinner-009.png
index 938c49f9d3..18fc3a7d16 100644
--- a/src/qt/res/movies/spinner-009.png
+++ b/src/qt/res/movies/spinner-009.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-010.png b/src/qt/res/movies/spinner-010.png
index 7eb645eda5..a79c845fe8 100644
--- a/src/qt/res/movies/spinner-010.png
+++ b/src/qt/res/movies/spinner-010.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-011.png b/src/qt/res/movies/spinner-011.png
index fd4b63ca5a..57baf66895 100644
--- a/src/qt/res/movies/spinner-011.png
+++ b/src/qt/res/movies/spinner-011.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-012.png b/src/qt/res/movies/spinner-012.png
index 10d26a3a53..9deae7853a 100644
--- a/src/qt/res/movies/spinner-012.png
+++ b/src/qt/res/movies/spinner-012.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-013.png b/src/qt/res/movies/spinner-013.png
index 863a9d2908..0659d48dec 100644
--- a/src/qt/res/movies/spinner-013.png
+++ b/src/qt/res/movies/spinner-013.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-014.png b/src/qt/res/movies/spinner-014.png
index d01086cb98..bc1ef51bde 100644
--- a/src/qt/res/movies/spinner-014.png
+++ b/src/qt/res/movies/spinner-014.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-015.png b/src/qt/res/movies/spinner-015.png
index 402dbea693..24b57b62c2 100644
--- a/src/qt/res/movies/spinner-015.png
+++ b/src/qt/res/movies/spinner-015.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-016.png b/src/qt/res/movies/spinner-016.png
index 1db20e6078..d622872651 100644
--- a/src/qt/res/movies/spinner-016.png
+++ b/src/qt/res/movies/spinner-016.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-017.png b/src/qt/res/movies/spinner-017.png
index e2c2e2ef78..f48f688db2 100644
--- a/src/qt/res/movies/spinner-017.png
+++ b/src/qt/res/movies/spinner-017.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-018.png b/src/qt/res/movies/spinner-018.png
index 6f1fe73756..a2c8f38b1d 100644
--- a/src/qt/res/movies/spinner-018.png
+++ b/src/qt/res/movies/spinner-018.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-019.png b/src/qt/res/movies/spinner-019.png
index 5f18f65608..9d7cc35d82 100644
--- a/src/qt/res/movies/spinner-019.png
+++ b/src/qt/res/movies/spinner-019.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-020.png b/src/qt/res/movies/spinner-020.png
index c12ae20016..1a07acc454 100644
--- a/src/qt/res/movies/spinner-020.png
+++ b/src/qt/res/movies/spinner-020.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-021.png b/src/qt/res/movies/spinner-021.png
index d81ceade23..9cea8f2543 100644
--- a/src/qt/res/movies/spinner-021.png
+++ b/src/qt/res/movies/spinner-021.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-022.png b/src/qt/res/movies/spinner-022.png
index 69c6657942..60250f6dea 100644
--- a/src/qt/res/movies/spinner-022.png
+++ b/src/qt/res/movies/spinner-022.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-023.png b/src/qt/res/movies/spinner-023.png
index 7bed5bae85..fc290a0cf2 100644
--- a/src/qt/res/movies/spinner-023.png
+++ b/src/qt/res/movies/spinner-023.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-024.png b/src/qt/res/movies/spinner-024.png
index b3be8d3e8e..c5dcf1eae9 100644
--- a/src/qt/res/movies/spinner-024.png
+++ b/src/qt/res/movies/spinner-024.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-025.png b/src/qt/res/movies/spinner-025.png
index 3a7fa9ab0d..7f3577a4de 100644
--- a/src/qt/res/movies/spinner-025.png
+++ b/src/qt/res/movies/spinner-025.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-026.png b/src/qt/res/movies/spinner-026.png
index dd92fc4fc1..1663ddf44c 100644
--- a/src/qt/res/movies/spinner-026.png
+++ b/src/qt/res/movies/spinner-026.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-027.png b/src/qt/res/movies/spinner-027.png
index 9adefee268..d0e6da4503 100644
--- a/src/qt/res/movies/spinner-027.png
+++ b/src/qt/res/movies/spinner-027.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-028.png b/src/qt/res/movies/spinner-028.png
index 83e7cdd583..2a7aba50e2 100644
--- a/src/qt/res/movies/spinner-028.png
+++ b/src/qt/res/movies/spinner-028.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-029.png b/src/qt/res/movies/spinner-029.png
index 6cbdbb0fe1..c8ca15c1e1 100644
--- a/src/qt/res/movies/spinner-029.png
+++ b/src/qt/res/movies/spinner-029.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-030.png b/src/qt/res/movies/spinner-030.png
index e4a09a44bc..c847c99a93 100644
--- a/src/qt/res/movies/spinner-030.png
+++ b/src/qt/res/movies/spinner-030.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-031.png b/src/qt/res/movies/spinner-031.png
index 3c3d505741..403443144e 100644
--- a/src/qt/res/movies/spinner-031.png
+++ b/src/qt/res/movies/spinner-031.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-032.png b/src/qt/res/movies/spinner-032.png
index 7460f80da3..f9db080567 100644
--- a/src/qt/res/movies/spinner-032.png
+++ b/src/qt/res/movies/spinner-032.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-033.png b/src/qt/res/movies/spinner-033.png
index d327e8fb08..43f57719e7 100644
--- a/src/qt/res/movies/spinner-033.png
+++ b/src/qt/res/movies/spinner-033.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-034.png b/src/qt/res/movies/spinner-034.png
index d8432751da..c26656ff17 100644
--- a/src/qt/res/movies/spinner-034.png
+++ b/src/qt/res/movies/spinner-034.png
Binary files differ
diff --git a/src/qt/res/movies/spinner-035.png b/src/qt/res/movies/spinner-035.png
index c89c959c94..e471f950a3 100644
--- a/src/qt/res/movies/spinner-035.png
+++ b/src/qt/res/movies/spinner-035.png
Binary files differ
diff --git a/src/qt/test/paymentrequestdata.h b/src/qt/test/paymentrequestdata.h
index 37544cdebb..67c9a41e61 100644
--- a/src/qt/test/paymentrequestdata.h
+++ b/src/qt/test/paymentrequestdata.h
@@ -6,16 +6,16 @@
// Data for paymentservertests.cpp
//
-// Base64/DER-encoded fake certificate authority certificate.
+// Base64/DER-encoded fake certificate authority certificates.
// Convert pem to base64/der with:
-// cat file.pem | openssl x509 -inform PEM -outform DER | openssl enc -base64
-//
+// openssl x509 -in cert.pem -inform PEM -outform DER | openssl enc -base64
+
// Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8)
// Issuer: CN=PaymentRequest Test CA
// Subject: CN=PaymentRequest Test CA
// Not Valid After : Dec 8 16:37:24 2022 GMT
//
-const char* caCert_BASE64 =
+const char* caCert1_BASE64 =
"\
MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\
@@ -29,11 +29,36 @@ RtQcf0AJ9olzUMY4syehxbzUJP6aeXhZEYiMvdvcv9D55clq6+WLLlNT3jBgAaVn\
p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\
";
+// Serial Number: f0:da:97:e4:38:d7:64:16
+// Issuer: CN=PaymentRequest Test CA
+// Subject: CN=PaymentRequest Test CA
+// Not Valid After : Jan 8 18:21:06 2025 GMT
+//
+const char* caCert2_BASE64 =
+"\
+MIIC1TCCAb2gAwIBAgIJAPDal+Q412QWMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
+BAMMFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTUwMTExMTgyMTA2WhcNMjUw\
+MTA4MTgyMTA2WjAhMR8wHQYDVQQDDBZQYXltZW50UmVxdWVzdCBUZXN0IENBMIIB\
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1S9wVLfTplJuT/1OaaBgl/Mb\
+I392v8S9kHbzYz7B4OTMslaO7piz0v3SO3TKMh0dswjiRdHrIgpO7XdIUQiU/ugg\
+xDw0kuNehfz1ycaGedlFFtFHTNXqLyIUF3dlwHhQwaomM6RXoJmxLny5BhYHEcmk\
+yWwr3Cdjd9gAZpblugVJB9C1e40uyL8ao4PHdLzOqO27iSe6riP8SwwisJZEbMaz\
+AZpgNEEMbIXPJEFvm5HTRXSMtQCOTSZYMFF0M2yrtmlECnz7hWP19b9bcoDzZQB4\
+ylIsFG/7q2jV7MC/e2STZv+niJiHL08RUdoFpAgzaxMgqj63C7B55HgNDNHJYQID\
+AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBGejPxLxj9\
++crv6gUeEBMZPiUx7pUgcI22Wm5yymP96B4fwI3Y0DBehq20d76vbWGPN17Z6pH3\
+ge7PVY1SYqXtS6hXTo4olCm/BZADli+2Bs2xCiaa+Ltve4ufVej+bKJXN/YnrhvO\
+Kq+klQkuuHywU+GJV/NQeBqToIrSOBgi477NgLFCCCmmx2QWsxHoCFGfuRCBVseT\
+z2k/tMuALCDXGeZBRPTsGHu1y4cj84swAeoDK5QSQcI+Ub7GKc+zkoj02sdDLiMo\
+3wokYPcIy47oclhmb4xubHc+y7nF610yZBoC/zgbhbawnZ65hDDWkdQ/SVAnWZD7\
+9PFfmNnYPTQH\
+";
+
//
// This payment request validates directly against the
-// above certificate authority.
+// caCert1 certificate authority.
//
-const char* paymentrequest1_BASE64 =
+const char* paymentrequest1_cert1_BASE64 =
"\
Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\
@@ -55,7 +80,7 @@ SiWVbw0tX/68iSQEGGfh9n6ee/8Myb3ICdw=\
//
// Signed, but expired, merchant cert in the request
//
-const char* paymentrequest2_BASE64 =
+const char* paymentrequest2_cert1_BASE64 =
"\
Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\
@@ -75,9 +100,9 @@ tejrSPOBNSJ3Mi/q5u2Yl4gJZY2b\
";
//
-// 10-long chain, all intermediates valid
+// 10-long certificate chain, all intermediates valid
//
-const char* paymentrequest3_BASE64 =
+const char* paymentrequest3_cert1_BASE64 =
"\
Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
@@ -184,9 +209,9 @@ chhR/aHOuEMTxmc12K4rNlgYtHCsxLP9zd+6u0cva3TucZ6EzS8PKEib/+r12/52\
";
//
-// Long chain, with an invalid (expired) cert in the middle
+// Long certificate chain, with an expired certificate in the middle
//
-const char* paymentrequest4_BASE64 =
+const char* paymentrequest4_cert1_BASE64 =
"\
Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
@@ -291,7 +316,10 @@ HXQjsfdR58qZQS9CS5DAtRUf0R8+43/wijO/hb49VNaNXmY+/cPHMkahP2aV3tZi\
FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\
";
-const char* paymentrequest5_BASE64 =
+//
+// Validly signed, but by a CA not in our root CA list
+//
+const char* paymentrequest5_cert1_BASE64 =
"\
Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\
@@ -309,3 +337,27 @@ ssymvca1S/1KeM3n8Ydi2fi1JUzAAr59xPvNJRUeqCLP9upHn5z7br3P12Oz9A20\
5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\
XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\
";
+
+//
+// Contains a testnet paytoaddress, so payment request network doesn't match client network
+//
+const char* paymentrequest1_cert2_BASE64 =
+"\
+Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
+BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
+ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
+IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
+mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
+wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
+RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
+KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
+3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
+tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
+yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
+dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iPQoEdGVzdBIhCIDWwowE\
+Ehl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGNeMy6UFKgxKdXN0IFRlc3Rpbmcq\
+gAFwThsozZxkZxzCn4R8WxNiLFV6m0ye9fEtSbolfaW+EjBMpO03lr/dwNnrclhg\
+ew+A05xfZztrAt16XKEY7qKJ/eY2nLd0fVAIu/nIt+7/VYVXT83zLrWc150aRS7W\
+AdJbL3JOJLs6Eyp5zrPbfI8faRttFAdONKDrJgIpuW1E3g==\
+";
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 70254cd75d..e6cdb58ef5 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -65,38 +65,44 @@ void PaymentServerTests::paymentServerTests()
OptionsModel optionsModel;
PaymentServer* server = new PaymentServer(NULL, false);
X509_STORE* caStore = X509_STORE_new();
- X509_STORE_add_cert(caStore, parse_b64der_cert(caCert_BASE64));
+ X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
PaymentServer::LoadRootCAs(caStore);
server->setOptionsModel(&optionsModel);
server->uiReady();
- // Now feed PaymentRequests to server, and observe signals it produces:
- std::vector<unsigned char> data = DecodeBase64(paymentrequest1_BASE64);
- SendCoinsRecipient r = handleRequest(server, data);
+ std::vector<unsigned char> data;
+ SendCoinsRecipient r;
QString merchant;
+
+ // Now feed PaymentRequests to server, and observe signals it produces
+
+ // This payment request validates directly against the
+ // caCert1 certificate authority:
+ data = DecodeBase64(paymentrequest1_cert1_BASE64);
+ r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("testmerchant.org"));
- // Version of the above, with an expired certificate:
- data = DecodeBase64(paymentrequest2_BASE64);
+ // Signed, but expired, merchant cert in the request:
+ data = DecodeBase64(paymentrequest2_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString(""));
- // Long certificate chain:
- data = DecodeBase64(paymentrequest3_BASE64);
+ // 10-long certificate chain, all intermediates valid:
+ data = DecodeBase64(paymentrequest3_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("testmerchant8.org"));
// Long certificate chain, with an expired certificate in the middle:
- data = DecodeBase64(paymentrequest4_BASE64);
+ data = DecodeBase64(paymentrequest4_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString(""));
// Validly signed, but by a CA not in our root CA list:
- data = DecodeBase64(paymentrequest5_BASE64);
+ data = DecodeBase64(paymentrequest5_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString(""));
@@ -104,11 +110,39 @@ void PaymentServerTests::paymentServerTests()
// Try again with no root CA's, verifiedMerchant should be empty:
caStore = X509_STORE_new();
PaymentServer::LoadRootCAs(caStore);
- data = DecodeBase64(paymentrequest1_BASE64);
+ data = DecodeBase64(paymentrequest1_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString(""));
+ // Load second root certificate
+ caStore = X509_STORE_new();
+ X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
+ PaymentServer::LoadRootCAs(caStore);
+
+ QByteArray byteArray;
+
+ // For the tests below we just need the payment request data from
+ // paymentrequestdata.h parsed + stored in r.paymentRequest.
+ //
+ // These tests require us to bypass the following normal client execution flow
+ // shown below to be able to explicitly just trigger a certain condition!
+ //
+ // handleRequest()
+ // -> PaymentServer::eventFilter()
+ // -> PaymentServer::handleURIOrFile()
+ // -> PaymentServer::readPaymentRequestFromFile()
+ // -> PaymentServer::processPaymentRequest()
+
+ // Contains a testnet paytoaddress, so payment request network doesn't match client network:
+ data = DecodeBase64(paymentrequest1_cert2_BASE64);
+ byteArray = QByteArray((const char*)&data[0], data.size());
+ r.paymentRequest.parse(byteArray);
+ // Ensure the request is initialized, because network "main" is default, even for
+ // uninizialized payment requests and that will fail our test here.
+ QVERIFY(r.paymentRequest.IsInitialized());
+ QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);
+
// Just get some random data big enough to trigger BIP70 DoS protection
unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
GetRandBytes(randData, sizeof(randData));
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 06560627f2..4ef42b927e 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -12,6 +12,7 @@
#include "clientversion.h"
#include "init.h"
+#include "util.h"
#include <stdio.h>
@@ -108,6 +109,12 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
cursor.movePosition(QTextCursor::NextRow);
cursor.insertText(tr("UI options") + ":", bold);
cursor.movePosition(QTextCursor::NextRow);
+ if (GetBoolArg("-help-debug", false)) {
+ cursor.insertText("-allowselfsignedrootcertificates");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText(tr("Allow self signed root certificates (default: 0)"));
+ cursor.movePosition(QTextCursor::NextCell);
+ }
cursor.insertText("-choosedatadir");
cursor.movePosition(QTextCursor::NextCell);
cursor.insertText(tr("Choose data directory on startup (default: 0)"));
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index a070ab5bbe..9ebacdbe2e 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -953,7 +953,7 @@ void ServiceConnection(AcceptedConnection *conn)
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE);
// HTTP Keep-Alive is false; close connection immediately
- if (mapHeaders["connection"] == "close")
+ if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", false)))
fRun = false;
// Process via JSON-RPC API