aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiel van Schijndel <me@mortis.eu>2012-06-24 12:34:15 +0200
committerGiel van Schijndel <me@mortis.eu>2012-06-24 12:34:15 +0200
commit415a87ef363396fe689ec452a30d36b1752eab2e (patch)
tree1f68453bf98ac1a4a94394e2792fd3175480cd52
parent896899e0d66e25f6549a92749d237c8a87b12f08 (diff)
parent817ee0d826087d418b5f0bffcdd92429574284e2 (diff)
Merge branch 'master' into async-ipv6-rpc
-rw-r--r--contrib/gitian-downloader/luke-jr-key.pgpbin5467 -> 7322 bytes
-rw-r--r--contrib/gitian-downloader/sipa-key.pgpbin108922 -> 109468 bytes
-rw-r--r--doc/Tor.txt96
-rw-r--r--doc/build-msw.txt2
-rw-r--r--doc/build-osx.txt20
-rw-r--r--doc/build-unix.txt4
-rw-r--r--src/bignum.h22
-rw-r--r--src/bitcoinrpc.cpp18
-rw-r--r--src/db.cpp60
-rw-r--r--src/db.h1
-rw-r--r--src/init.cpp32
-rw-r--r--src/key.cpp3
-rw-r--r--src/main.cpp24
-rw-r--r--src/main.h1
-rw-r--r--src/mruset.h2
-rw-r--r--src/net.cpp13
-rw-r--r--src/net.h4
-rw-r--r--src/netbase.cpp241
-rw-r--r--src/netbase.h12
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/forms/sendcoinsdialog.ui9
-rw-r--r--src/qt/guiutil.cpp16
-rw-r--r--src/qt/guiutil.h6
-rw-r--r--src/qt/overviewpage.cpp24
-rw-r--r--src/qt/overviewpage.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp16
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/sendcoinsentry.cpp18
-rw-r--r--src/qt/sendcoinsentry.h1
-rw-r--r--src/qt/transactiontablemodel.cpp7
-rw-r--r--src/qt/transactiontablemodel.h1
-rw-r--r--src/test/base32_tests.cpp20
-rw-r--r--src/test/bignum_tests.cpp125
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp102
-rw-r--r--src/util.cpp188
-rw-r--r--src/util.h7
37 files changed, 898 insertions, 205 deletions
diff --git a/contrib/gitian-downloader/luke-jr-key.pgp b/contrib/gitian-downloader/luke-jr-key.pgp
index c40917d78c..275b041d20 100644
--- a/contrib/gitian-downloader/luke-jr-key.pgp
+++ b/contrib/gitian-downloader/luke-jr-key.pgp
Binary files differ
diff --git a/contrib/gitian-downloader/sipa-key.pgp b/contrib/gitian-downloader/sipa-key.pgp
index a52a5deb1b..ffa09bb4ad 100644
--- a/contrib/gitian-downloader/sipa-key.pgp
+++ b/contrib/gitian-downloader/sipa-key.pgp
Binary files differ
diff --git a/doc/Tor.txt b/doc/Tor.txt
new file mode 100644
index 0000000000..f44b016f22
--- /dev/null
+++ b/doc/Tor.txt
@@ -0,0 +1,96 @@
+TOR SUPPORT IN BITCOIN
+======================
+
+It is possible to run Bitcoin as a Tor hidden service, and connect to such services.
+
+The following assumes you have a Tor proxy running on port 9050. Many distributions
+default to having a SOCKS proxy listening on port 9050, but others may not.
+In particular, the Tor Browser Bundle defaults to listening on a random port. See
+https://www.torproject.org/docs/faq.html.en#TBBSocksPort for how to properly
+configure Tor.
+
+
+1. Run bitcoin behind a Tor proxy
+---------------------------------
+
+The first step is running Bitcoin behind a Tor proxy. This will already make all
+outgoing connections be anonimized, but more is possible.
+
+-socks=5 SOCKS5 supports connecting-to-hostname, which can be used instead
+ of doing a (leaking) local DNS lookup. SOCKS5 is the default,
+ but SOCKS4 does not support this. (SOCKS4a does, but isn't
+ implemented).
+
+-proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy
+ server will be used to try to reach .onion addresses as well.
+
+-tor=ip:port Set the proxy server to use for tor hidden services. You do not
+ need to set this if it's the same as -proxy. You can use -notor
+ to explicitly disable access to hidden service.
+
+-dnsseed DNS seeds are not resolved directly when a SOCKS5 proxy server is
+ set. Rather, a short-lived proxy connection to the dns seed
+ hostname is attempted, and peer addresses are requested.
+
+-listen When using -proxy, listening is disabled by default. If you want
+ to run a hidden service (see next section), you'll need to enable
+ it explicitly.
+
+-connect=X When behing a Tor proxy, you can specify .onion addresses instead
+-addnode=X of IP addresses or hostnames in these parameters. It requires
+-seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with
+ other P2P nodes.
+
+In a typical situation, this suffices to run behind a Tor proxy:
+
+ ./bitcoin -proxy=127.0.0.1:9050
+
+
+2. Run a bitcoin hidden server
+------------------------------
+
+If you configure your Tor system accordingly, it is possible to make your node also
+reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent
+config file):
+
+ HiddenServiceDir /var/lib/tor/bitcoin-service/
+ HiddenServicePort 8333 127.0.0.1:8333
+
+The directory can be different of course, but (both) 8333's should be equal to your
+bitcoind's P2P listen port (8333 by default).
+
+-externalip=X You can tell bitcoin about its publically reachable address using
+ this option, and this can be a .onion address. Given the above
+ configuration, you can find your onion address in
+ /var/lib/tor/bitcoin-service/hostname. Onion addresses are given
+ preference for your node to advertize itself with, for connections
+ coming from unroutable addresses (such as 127.0.0.1, where the
+ Tor proxy typically runs).
+
+-listen You'll need to enable listening for incoming connections, as this
+ is off by default behind a proxy.
+
+-discover When -externalip is specified, no attempt is made to discover local
+ IPv4 or IPv6 addresses. If you want to run a dual stack, reachable
+ from both Tor and IPv4 (or IPv6), you'll need to either pass your
+ other addresses using -externalip, or explicitly enable -discover.
+ Note that both addresses of a dual-stack system may be easily
+ linkable using traffic analysis.
+
+In a typical situation, where you're only reachable via Tor, this should suffice:
+
+ ./bitcoind -proxy=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -listen
+
+(obviously replace the Onion address with your own). If you don't care too much
+about hiding your node, and want to be reachable on IPv4 as well, additionally
+specify:
+
+ ./bitcoind ... -discover
+
+and open port 8333 on your firewall (or use -upnp).
+
+If you only want to use Tor to reach onion addresses, but not use it as a proxy
+for normal IPv4/IPv6 communication, use:
+
+ ./bitcoin -tor=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover
+
diff --git a/doc/build-msw.txt b/doc/build-msw.txt
index 73ea81275f..ad23e68675 100644
--- a/doc/build-msw.txt
+++ b/doc/build-msw.txt
@@ -7,7 +7,7 @@ cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP
software written by Thomas Bernard.
-See readme-qt.rst for instructions on building Bitcoin QT, the
+See readme-qt.rst for instructions on building Bitcoin-Qt, the
graphical user interface.
WINDOWS BUILD NOTES
diff --git a/doc/build-osx.txt b/doc/build-osx.txt
index 256614f7ab..24e825ca8c 100644
--- a/doc/build-osx.txt
+++ b/doc/build-osx.txt
@@ -1,10 +1,10 @@
Copyright (c) 2009-2012 Bitcoin Developers
-Distributed under the MIT/X11 software license, see the accompanying file
-license.txt or http://www.opensource.org/licenses/mit-license.php. This
-product includes software developed by the OpenSSL Project for use in the
-OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic
-software written by Eric Young (eay@cryptsoft.com) and UPnP software written by
-Thomas Bernard.
+Distributed under the MIT/X11 software license, see the accompanying
+file license.txt or http://www.opensource.org/licenses/mit-license.php.
+This product includes software developed by the OpenSSL Project for use in
+the OpenSSL Toolkit (http://www.openssl.org/). This product includes
+cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP
+software written by Thomas Bernard.
Mac OS X bitcoind build instructions
@@ -12,17 +12,17 @@ Laszlo Hanyecz <solar@heliacal.net>
Douglas Huff <dhuff@jrbobdobbs.org>
-See readme-qt.rst for instructions on building Bitcoin QT, the
+See readme-qt.rst for instructions on building Bitcoin-Qt, the
graphical user interface.
-Tested on 10.5 and 10.6 intel. PPC is not supported because it's big-endian.
+Tested on 10.5, 10.6 and 10.7 intel. PPC is not supported because it's big-endian.
All of the commands should be executed in Terminal.app.. it's in
/Applications/Utilities
You need to install XCode with all the options checked so that the compiler and
-everything is available in /usr not just /Developer I think it comes on the DVD
-but you can get the current version from http://developer.apple.com
+everything is available in /usr not just /Developer. XCode should be available on your OS X
+install DVD, but if not, you can get the current version from https://developer.apple.com/xcode/
1. Clone the github tree to get the source code:
diff --git a/doc/build-unix.txt b/doc/build-unix.txt
index 9033301ab0..825491bba3 100644
--- a/doc/build-unix.txt
+++ b/doc/build-unix.txt
@@ -16,8 +16,8 @@ To Build
cd src/
make -f makefile.unix # Headless bitcoin
-See readme-qt.rst for instructions on building Bitcoin QT,
-the graphical bitcoin.
+See readme-qt.rst for instructions on building Bitcoin-Qt,
+the graphical user interface.
Dependencies
------------
diff --git a/src/bignum.h b/src/bignum.h
index 307017b0ab..9af934051a 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -122,16 +122,30 @@ public:
return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
}
- void setint64(int64 n)
+ void setint64(int64 sn)
{
- unsigned char pch[sizeof(n) + 6];
+ unsigned char pch[sizeof(sn) + 6];
unsigned char* p = pch + 4;
- bool fNegative = false;
- if (n < (int64)0)
+ bool fNegative;
+ uint64 n;
+
+ if (sn < (int64)0)
{
+ // We negate in 2 steps to avoid signed subtraction overflow,
+ // i.e. -(-2^63), which is an undefined operation and causes SIGILL
+ // when compiled with -ftrapv.
+ //
+ // Note that uint64_t n = sn, when sn is an int64_t, is a
+ // well-defined operation and n will be equal to sn + 2^64 when sn
+ // is negative.
+ n = sn;
n = -n;
fNegative = true;
+ } else {
+ n = sn;
+ fNegative = false;
}
+
bool fLeadingZeroes = true;
for (int i = 0; i < 8; i++)
{
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index a35d33e14e..25ff6c1e5f 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -2198,6 +2198,23 @@ Value getmemorypool(const Array& params, bool fHelp)
}
}
+Value getrawmempool(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getrawmempool\n"
+ "Returns all transaction ids in memory pool.");
+
+ vector<uint256> vtxid;
+ mempool.queryHashes(vtxid);
+
+ Array a;
+ BOOST_FOREACH(const uint256& hash, vtxid)
+ a.push_back(hash.ToString());
+
+ return a;
+}
+
Value getblockhash(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -2321,6 +2338,7 @@ static const CRPCCommand vRPCCommands[] =
{ "sendfrom", &sendfrom, false },
{ "sendmany", &sendmany, false },
{ "addmultisigaddress", &addmultisigaddress, false },
+ { "getrawmempool", &getrawmempool, true },
{ "getblock", &getblock, false },
{ "getblockhash", &getblockhash, false },
{ "gettransaction", &gettransaction, false },
diff --git a/src/db.cpp b/src/db.cpp
index 4f4e1d84b7..ecdf32a8f0 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -404,66 +404,6 @@ bool CTxDB::ContainsTx(uint256 hash)
return Exists(make_pair(string("tx"), hash));
}
-bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
-{
- assert(!fClient);
- vtx.clear();
-
- // Get cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- return false;
-
- unsigned int fFlags = DB_SET_RANGE;
- loop
- {
- // Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
- ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- {
- pcursor->close();
- return false;
- }
-
- // Unserialize
- string strType;
- uint160 hashItem;
- CDiskTxPos pos;
- int nItemHeight;
-
- try {
- ssKey >> strType >> hashItem >> pos;
- ssValue >> nItemHeight;
- }
- catch (std::exception &e) {
- return error("%s() : deserialize error", __PRETTY_FUNCTION__);
- }
-
- // Read transaction
- if (strType != "owner" || hashItem != hash160)
- break;
- if (nItemHeight >= nMinHeight)
- {
- vtx.resize(vtx.size()+1);
- if (!vtx.back().ReadFromDisk(pos))
- {
- pcursor->close();
- return false;
- }
- }
- }
-
- pcursor->close();
- return true;
-}
-
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
{
assert(!fClient);
diff --git a/src/db.h b/src/db.h
index 5527054560..1030a40c48 100644
--- a/src/db.h
+++ b/src/db.h
@@ -307,7 +307,6 @@ public:
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
bool EraseTxIndex(const CTransaction& tx);
bool ContainsTx(uint256 hash);
- bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(uint256 hash, CTransaction& tx);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
diff --git a/src/init.cpp b/src/init.cpp
index 4e0947a16a..34a8509b84 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -223,6 +223,7 @@ std::string HelpMessage()
" -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
+ " -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
" -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
" -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
" -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
@@ -230,12 +231,12 @@ std::string HelpMessage()
" -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" +
" -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
" -externalip=<ip> " + _("Specify your own public address") + "\n" +
- " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4 or IPv6)") + "\n" +
+ " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" +
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
" -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
- " -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" +
+ " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
" -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)") + "\n" +
@@ -345,7 +346,7 @@ bool AppInit2()
SoftSetBoolArg("-listen", false);
}
- if (GetBoolArg("-listen", true)) {
+ if (!GetBoolArg("-listen", true)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-discover", false);
@@ -359,6 +360,13 @@ bool AppInit2()
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
+
+ // -debug implies fDebug*
+ if (fDebug)
+ fDebugNet = true;
+ else
+ fDebugNet = GetBoolArg("-debugnet");
+
bitdb.SetDetach(GetBoolArg("-detachdb", false));
#if !defined(WIN32) && !defined(QT_GUI)
@@ -470,8 +478,10 @@ bool AppInit2()
}
}
+ CService addrProxy;
+ bool fProxy = false;
if (mapArgs.count("-proxy")) {
- CService addrProxy = CService(mapArgs["-proxy"], 9050);
+ addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
@@ -484,6 +494,20 @@ bool AppInit2()
#endif
SetNameProxy(addrProxy, nSocksVersion);
}
+ fProxy = true;
+ }
+
+ // -tor can override normal proxy, -notor disables tor entirely
+ if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) {
+ CService addrOnion;
+ if (!mapArgs.count("-tor"))
+ addrOnion = addrProxy;
+ else
+ addrOnion = CService(mapArgs["-tor"], 9050);
+ if (!addrOnion.IsValid())
+ return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"].c_str()));
+ SetProxy(NET_TOR, addrOnion, 5);
+ SetReachable(NET_TOR);
}
// see Step 2: parameter interactions for more information about these
diff --git a/src/key.cpp b/src/key.cpp
index 57ab842bc4..c943a38ea6 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -129,6 +129,8 @@ void CKey::SetCompressedPubKey()
void CKey::Reset()
{
fCompressedPubKey = false;
+ if (pkey != NULL)
+ EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey == NULL)
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
@@ -137,6 +139,7 @@ void CKey::Reset()
CKey::CKey()
{
+ pkey = NULL;
Reset();
}
diff --git a/src/main.cpp b/src/main.cpp
index be2733192e..b46866221f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -180,8 +180,8 @@ bool AddOrphanTx(const CDataStream& vMsg)
// at most 500 megabytes of orphans:
if (pvMsg->size() > 5000)
{
- delete pvMsg;
printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
+ delete pvMsg;
return false;
}
@@ -652,7 +652,15 @@ bool CTxMemPool::remove(CTransaction &tx)
return true;
}
+void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
+{
+ vtxid.clear();
+ LOCK(cs);
+ vtxid.reserve(mapTx.size());
+ for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
+ vtxid.push_back((*mi).first);
+}
@@ -1317,8 +1325,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
// already refuses previously-known transaction id's entirely.
// This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC.
- // On testnet it is enabled as of februari 20, 2012, 0:00 UTC.
- if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000))
+ if (pindex->nTime > 1331769600)
{
BOOST_FOREACH(CTransaction& tx, vtx)
{
@@ -1332,8 +1339,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
}
}
- // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
- int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
+ // BIP16 didn't become active until Apr 1 2012
+ int64 nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
//// issue here: it doesn't know the version
@@ -2419,7 +2426,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
- printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+ printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
cPeerBlockCounts.input(pfrom->nStartingHeight);
}
@@ -2475,7 +2482,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
static uint256 hashSalt;
if (hashSalt == 0)
hashSalt = GetRandHash();
- int64 hashAddr = addr.GetHash();
+ uint64 hashAddr = addr.GetHash();
uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
@@ -3143,7 +3150,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(txdb, inv))
{
- printf("sending getdata: %s\n", inv.ToString().c_str());
+ if (fDebugNet)
+ printf("sending getdata: %s\n", inv.ToString().c_str());
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
diff --git a/src/main.h b/src/main.h
index 29c9a8bce3..bb094ad3c7 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1604,6 +1604,7 @@ public:
bool fCheckInputs, bool* pfMissingInputs);
bool addUnchecked(CTransaction &tx);
bool remove(CTransaction &tx);
+ void queryHashes(std::vector<uint256>& vtxid);
unsigned long size()
{
diff --git a/src/mruset.h b/src/mruset.h
index ad2e160d3a..a52735182d 100644
--- a/src/mruset.h
+++ b/src/mruset.h
@@ -51,7 +51,7 @@ public:
size_type max_size(size_type s)
{
if (s)
- while (queue.size() >= s)
+ while (queue.size() > s)
{
set.erase(queue.front());
queue.pop_front();
diff --git a/src/net.cpp b/src/net.cpp
index 804cb0f543..77fd334ee4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -206,6 +206,14 @@ void static AdvertizeLocal()
}
}
+void SetReachable(enum Network net, bool fFlag)
+{
+ LOCK(cs_mapLocalHost);
+ vfReachable[net] = fFlag;
+ if (net == NET_IPV6 && fFlag)
+ vfReachable[NET_IPV4] = true;
+}
+
// learn a new local address
bool AddLocal(const CService& addr, int nScore)
{
@@ -228,9 +236,7 @@ bool AddLocal(const CService& addr, int nScore)
info.nScore = nScore;
info.nPort = addr.GetPort() + (fAlready ? 1 : 0);
}
- enum Network net = addr.GetNetwork();
- vfReachable[net] = true;
- if (net == NET_IPV6) vfReachable[NET_IPV4] = true;
+ SetReachable(addr.GetNetwork());
}
AdvertizeLocal();
@@ -543,6 +549,7 @@ void CNode::PushVersion()
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+ printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str());
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
}
diff --git a/src/net.h b/src/net.h
index c9c965722e..29b116eb3b 100644
--- a/src/net.h
+++ b/src/net.h
@@ -64,6 +64,7 @@ bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(const CNetAddr &addr);
+void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
@@ -296,7 +297,8 @@ public:
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64& nRequestTime = mapAlreadyAskedFor[inv];
- printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
+ if (fDebugNet)
+ printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
// Make sure not to reuse time indexes to keep things in the same order
int64 nNow = (GetTime() - 1) * 1000000;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index d1ead79ebb..aa767cd3eb 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -33,9 +33,39 @@ enum Network ParseNetwork(std::string net) {
return NET_UNROUTABLE;
}
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
+ size_t colon = in.find_last_of(':');
+ // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
+ bool fHaveColon = colon != in.npos;
+ bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
+ bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
+ if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
+ char *endp = NULL;
+ int n = strtol(in.c_str() + colon + 1, &endp, 10);
+ if (endp && *endp == 0 && n >= 0) {
+ in = in.substr(0, colon);
+ if (n > 0 && n < 0x10000)
+ portOut = n;
+ }
+ }
+ if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
+ hostOut = in.substr(1, in.size()-2);
+ else
+ hostOut = in;
+}
+
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
vIP.clear();
+
+ {
+ CNetAddr addr;
+ if (addr.SetSpecial(std::string(pszName))) {
+ vIP.push_back(addr);
+ return true;
+ }
+ }
+
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
@@ -44,19 +74,17 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
#ifdef WIN32
# ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC;
- aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
# else
aiHint.ai_family = AF_INET;
- aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
# endif
+ aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
#else
# ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC;
- aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
# else
aiHint.ai_family = AF_INET;
- aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
# endif
+ aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif
struct addrinfo *aiRes = NULL;
int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
@@ -114,36 +142,11 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault,
if (pszName[0] == 0)
return false;
int port = portDefault;
- char psz[256];
- char *pszHost = psz;
- strlcpy(psz, pszName, sizeof(psz));
- char* pszColon = strrchr(psz+1,':');
- char *pszPortEnd = NULL;
- int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
- if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
- {
- if (psz[0] == '[' && pszColon[-1] == ']')
- {
- pszHost = psz+1;
- pszColon[-1] = 0;
- }
- else
- pszColon[0] = 0;
- if (port >= 0 && port <= USHRT_MAX)
- port = portParsed;
- }
- else
- {
- if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
- {
- pszHost = psz+1;
- psz[strlen(psz)-1] = 0;
- }
-
- }
+ std::string hostname = "";
+ SplitHostPort(std::string(pszName), port, hostname);
std::vector<CNetAddr> vIP;
- bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
+ bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
if (!fRet)
return false;
vAddr.resize(vIP.size());
@@ -496,22 +499,9 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
{
- string strDest(pszDest);
+ string strDest;
int port = portDefault;
-
- // split hostname and port
- size_t colon = strDest.find_last_of(':');
- if (colon != strDest.npos) {
- char *endp = NULL;
- int n = strtol(pszDest + colon + 1, &endp, 10);
- if (endp && *endp == 0 && n >= 0) {
- strDest = strDest.substr(0, colon);
- if (n > 0 && n < 0x10000)
- port = n;
- }
- }
- if (strDest[0] == '[' && strDest[strDest.size()-1] == ']')
- strDest = strDest.substr(1, strDest.size()-2);
+ SplitHostPort(string(pszDest), port, strDest);
SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
@@ -549,6 +539,32 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
memcpy(ip, ipIn.ip, sizeof(ip));
}
+static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
+
+bool CNetAddr::SetSpecial(const std::string &strName)
+{
+ if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
+ std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
+ if (vchAddr.size() != 16-sizeof(pchOnionCat))
+ return false;
+ memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
+ for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
+ ip[i + sizeof(pchOnionCat)] = vchAddr[i];
+ return true;
+ }
+ if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") {
+ std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str());
+ if (vchAddr.size() != 16-sizeof(pchGarliCat))
+ return false;
+ memcpy(ip, pchOnionCat, sizeof(pchGarliCat));
+ for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++)
+ ip[i + sizeof(pchGarliCat)] = vchAddr[i];
+ return true;
+ }
+ return false;
+}
+
CNetAddr::CNetAddr()
{
Init();
@@ -595,7 +611,7 @@ bool CNetAddr::IsIPv4() const
bool CNetAddr::IsIPv6() const
{
- return (!IsIPv4());
+ return (!IsIPv4() && !IsTor() && !IsI2P());
}
bool CNetAddr::IsRFC1918() const
@@ -654,15 +670,13 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
}
-bool CNetAddr::IsOnionCat() const
+bool CNetAddr::IsTor() const
{
- static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
}
-bool CNetAddr::IsGarliCat() const
+bool CNetAddr::IsI2P() const
{
- static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
}
@@ -724,7 +738,7 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal());
+ return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal());
}
enum Network CNetAddr::GetNetwork() const
@@ -735,10 +749,10 @@ enum Network CNetAddr::GetNetwork() const
if (IsIPv4())
return NET_IPV4;
- if (IsOnionCat())
+ if (IsTor())
return NET_TOR;
- if (IsGarliCat())
+ if (IsI2P())
return NET_I2P;
return NET_IPV6;
@@ -746,6 +760,10 @@ enum Network CNetAddr::GetNetwork() const
std::string CNetAddr::ToStringIP() const
{
+ if (IsTor())
+ return EncodeBase32(&ip[6], 10) + ".onion";
+ if (IsI2P())
+ return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p";
CService serv(*this, 0);
#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
@@ -758,7 +776,7 @@ std::string CNetAddr::ToStringIP() const
if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
return std::string(name);
}
- if (IsIPv4())
+ if (IsIPv4())
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
else
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
@@ -847,6 +865,18 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
vchRet.push_back(GetByte(2) ^ 0xFF);
return vchRet;
}
+ else if (IsTor())
+ {
+ nClass = NET_TOR;
+ nStartByte = 6;
+ nBits = 4;
+ }
+ else if (IsI2P())
+ {
+ nClass = NET_I2P;
+ nStartByte = 6;
+ nBits = 4;
+ }
// for he.net, use /36 groups
else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
nBits = 36;
@@ -867,10 +897,10 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
return vchRet;
}
-int64 CNetAddr::GetHash() const
+uint64 CNetAddr::GetHash() const
{
uint256 hash = Hash(&ip[0], &ip[16]);
- int64 nRet;
+ uint64 nRet;
memcpy(&nRet, &hash, sizeof(nRet));
return nRet;
}
@@ -880,27 +910,82 @@ void CNetAddr::print() const
printf("CNetAddr(%s)\n", ToString().c_str());
}
-// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners:
-// 0 - unroutable // 0 - unroutable // 0 - unroutable
-// 1 - teredo // 1 - teredo // 1 - ipv4
-// 2 - tunneled ipv6 // 2 - tunneled ipv6
-// 3 - ipv4 // 3 - ipv6
-// 4 - ipv6 // 4 - ipv4
+// private extensions to enum Network, only returned by GetExtNetwork,
+// and only used in GetReachabilityFrom
+static const int NET_UNKNOWN = NET_MAX + 0;
+static const int NET_TEREDO = NET_MAX + 1;
+int static GetExtNetwork(const CNetAddr *addr)
+{
+ if (addr == NULL)
+ return NET_UNKNOWN;
+ if (addr->IsRFC4380())
+ return NET_TEREDO;
+ return addr->GetNetwork();
+}
+
+/** Calculates a metric for how reachable (*this) is from a given partner */
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
{
- if (!IsValid() || !IsRoutable())
- return 0;
- if (paddrPartner && paddrPartner->IsIPv4())
- return IsIPv4() ? 1 : 0;
- if (IsRFC4380())
- return 1;
- if (IsRFC3964() || IsRFC6052())
- return 2;
- bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable();
- if (fRealIPv6)
- return IsIPv4() ? 3 : 4;
- else
- return IsIPv4() ? 4 : 3;
+ enum Reachability {
+ REACH_UNREACHABLE,
+ REACH_DEFAULT,
+ REACH_TEREDO,
+ REACH_IPV6_WEAK,
+ REACH_IPV4,
+ REACH_IPV6_STRONG,
+ REACH_PRIVATE
+ };
+
+ if (!IsRoutable())
+ return REACH_UNREACHABLE;
+
+ int ourNet = GetExtNetwork(this);
+ int theirNet = GetExtNetwork(paddrPartner);
+ bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
+
+ switch(theirNet) {
+ case NET_IPV4:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_IPV6:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunneled
+ }
+ case NET_TOR:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
+ case NET_TOR: return REACH_PRIVATE;
+ }
+ case NET_I2P:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_I2P: return REACH_PRIVATE;
+ }
+ case NET_TEREDO:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_UNKNOWN:
+ case NET_UNROUTABLE:
+ default:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are
+ case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address
+ }
+ }
}
void CService::Init()
@@ -1055,7 +1140,7 @@ std::string CService::ToStringPort() const
std::string CService::ToStringIPPort() const
{
- if (IsIPv4()) {
+ if (IsIPv4() || IsTor() || IsI2P()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
diff --git a/src/netbase.h b/src/netbase.h
index 0f6fc9b499..f097d7f5ae 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -25,7 +25,7 @@ enum Network
NET_TOR,
NET_I2P,
- NET_MAX
+ NET_MAX,
};
extern int nConnectTimeout;
@@ -44,8 +44,9 @@ class CNetAddr
explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false);
void Init();
void SetIP(const CNetAddr& ip);
+ bool SetSpecial(const std::string &strName); // for Tor and I2P addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
- bool IsIPv6() const; // IPv6 address (not IPv4)
+ bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
@@ -56,8 +57,8 @@ class CNetAddr
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
- bool IsOnionCat() const;
- bool IsGarliCat() const;
+ bool IsTor() const;
+ bool IsI2P() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsValid() const;
@@ -66,7 +67,7 @@ class CNetAddr
std::string ToString() const;
std::string ToStringIP() const;
int GetByte(int n) const;
- int64 GetHash() const;
+ uint64 GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
@@ -133,6 +134,7 @@ class CService : public CNetAddr
};
enum Network ParseNetwork(std::string net);
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy);
bool IsProxy(const CNetAddr &addr);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 8c8c73f065..b4e751077e 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -212,7 +212,7 @@ int main(int argc, char *argv[])
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
GUIUtil::HelpMessageBox help;
- help.exec();
+ help.showOrPrint();
return 1;
}
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 023a72ac2b..10a1586d4a 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -70,6 +70,9 @@
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -93,6 +96,9 @@
<property name="autoRepeatDelay">
<number>300</number>
</property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -109,6 +115,9 @@
</item>
<item>
<widget class="QLabel" name="labelBalance">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>123.456 BTC</string>
</property>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index a8c2328853..50ed2eed04 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -441,15 +441,21 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) :
setDetailedText(coreOptions + "\n" + uiOptions);
}
-void HelpMessageBox::exec()
+void HelpMessageBox::printToConsole()
{
-#if defined(WIN32)
- // On windows, show a message box, as there is no stderr in windowed applications
- QMessageBox::exec();
-#else
// On other operating systems, the expected action is to print the message to the console.
QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
fprintf(stderr, "%s", strUsage.toStdString().c_str());
+}
+
+void HelpMessageBox::showOrPrint()
+{
+#if defined(WIN32)
+ // On windows, show a message box, as there is no stderr/stdout in windowed applications
+ exec();
+#else
+ // On other operating systems, print help text to console
+ printToConsole();
#endif
}
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index ca06348519..0240695505 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -103,7 +103,11 @@ namespace GUIUtil
public:
HelpMessageBox(QWidget *parent = 0);
- void exec();
+ /** Show message box or print help message to standard output, based on operating system. */
+ void showOrPrint();
+
+ /** Print help message to console */
+ void printToConsole();
private:
QString header;
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 35d48581e3..07be9c520a 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -152,7 +152,7 @@ void OverviewPage::setNumTransactions(int count)
void OverviewPage::setModel(WalletModel *model)
{
this->model = model;
- if(model)
+ if(model && model->getOptionsModel())
{
// Set up transaction list
filter = new TransactionFilterProxy();
@@ -172,19 +172,25 @@ void OverviewPage::setModel(WalletModel *model)
setNumTransactions(model->getNumTransactions());
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged()));
+ connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
+
+ // update the display unit, to not use the default ("BTC")
+ updateDisplayUnit();
}
-void OverviewPage::displayUnitChanged()
+void OverviewPage::updateDisplayUnit()
{
- if(!model || !model->getOptionsModel())
- return;
- if(currentBalance != -1)
- setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
+ if(model && model->getOptionsModel())
+ {
+ if(currentBalance != -1)
+ setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
- txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
- ui->listTransactions->update();
+ // Update txdelegate->unit with the current unit
+ txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
+
+ ui->listTransactions->update();
+ }
}
void OverviewPage::showOutOfSyncWarning(bool fShow)
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index c7d3a4242c..00048cc8f8 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -44,7 +44,7 @@ private:
TransactionFilterProxy *filter;
private slots:
- void displayUnitChanged();
+ void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
};
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 76952e44ec..86c2b01fec 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -46,10 +46,11 @@ void SendCoinsDialog::setModel(WalletModel *model)
entry->setModel(model);
}
}
- if(model)
+ if(model && model->getOptionsModel())
{
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
+ connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
}
@@ -202,7 +203,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
QCoreApplication::instance()->processEvents();
QScrollBar* bar = ui->scrollArea->verticalScrollBar();
- if (bar)
+ if(bar)
bar->setSliderPosition(bar->maximum());
return entry;
}
@@ -245,7 +246,7 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
{
- if (!fNewRecipientAllowed)
+ if(!fNewRecipientAllowed)
return;
SendCoinsEntry *entry = 0;
@@ -289,3 +290,12 @@ void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint
int unit = model->getOptionsModel()->getDisplayUnit();
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
}
+
+void SendCoinsDialog::updateDisplayUnit()
+{
+ if(model && model->getOptionsModel())
+ {
+ // Update labelBalance with the current balance and the current unit
+ ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance()));
+ }
+}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 915b7ad465..def2f83c30 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -47,8 +47,8 @@ private:
private slots:
void on_sendButton_clicked();
-
void removeEntry(SendCoinsEntry* entry);
+ void updateDisplayUnit();
};
#endif // SENDCOINSDIALOG_H
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 5960597c77..71891e79ca 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -68,6 +68,10 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
void SendCoinsEntry::setModel(WalletModel *model)
{
this->model = model;
+
+ if(model && model->getOptionsModel())
+ connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+
clear();
}
@@ -82,10 +86,8 @@ void SendCoinsEntry::clear()
ui->addAsLabel->clear();
ui->payAmount->clear();
ui->payTo->setFocus();
- if(model && model->getOptionsModel())
- {
- ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
- }
+ // update the display unit, to not use the default ("BTC")
+ updateDisplayUnit();
}
void SendCoinsEntry::on_deleteButton_clicked()
@@ -160,3 +162,11 @@ void SendCoinsEntry::setFocus()
ui->payTo->setFocus();
}
+void SendCoinsEntry::updateDisplayUnit()
+{
+ if(model && model->getOptionsModel())
+ {
+ // Update payAmount with the current unit
+ ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
+ }
+}
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index cdbf893264..db6cba0d80 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -45,6 +45,7 @@ private slots:
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
void on_pasteButton_clicked();
+ void updateDisplayUnit();
private:
Ui::SendCoinsEntry *ui;
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index a86b1f7c56..b3e001ea1d 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -230,6 +230,8 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
timer->start(MODEL_UPDATE_DELAY);
+
+ connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
TransactionTableModel::~TransactionTableModel()
@@ -624,3 +626,8 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex
}
}
+void TransactionTableModel::updateDisplayUnit()
+{
+ // emit dataChanged to update Amount column with the current unit
+ emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
+}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 0aafa70915..fd321ce280 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -76,6 +76,7 @@ private:
public slots:
void updateTransaction(const QString &hash, int status);
void updateConfirmations();
+ void updateDisplayUnit();
friend class TransactionTablePriv;
};
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
new file mode 100644
index 0000000000..fdf3285913
--- /dev/null
+++ b/src/test/base32_tests.cpp
@@ -0,0 +1,20 @@
+#include <boost/test/unit_test.hpp>
+
+#include "util.h"
+
+BOOST_AUTO_TEST_SUITE(base32_tests)
+
+BOOST_AUTO_TEST_CASE(base32_testvectors)
+{
+ static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"};
+ static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"};
+ for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
+ {
+ std::string strEnc = EncodeBase32(vstrIn[i]);
+ BOOST_CHECK(strEnc == vstrOut[i]);
+ std::string strDec = DecodeBase32(vstrOut[i]);
+ BOOST_CHECK(strDec == vstrIn[i]);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp
new file mode 100644
index 0000000000..8620f81f17
--- /dev/null
+++ b/src/test/bignum_tests.cpp
@@ -0,0 +1,125 @@
+#include <boost/test/unit_test.hpp>
+#include <limits>
+
+#include "bignum.h"
+#include "util.h"
+
+BOOST_AUTO_TEST_SUITE(bignum_tests)
+
+// Unfortunately there's no standard way of preventing a function from being
+// inlined, so we define a macro for it.
+//
+// You should use it like this:
+// NOINLINE void function() {...}
+#if defined(__GNUC__)
+// This also works and will be defined for any compiler implementing gcc
+// extensions, such as clang and icc.
+#define NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define NOINLINE __declspec(noinline)
+#else
+// We give out a warning because it impacts the correctness of one bignum test.
+#warning You should define NOINLINE for your compiler.
+#define NOINLINE
+#endif
+
+// For the following test case, it is useful to use additional tools.
+//
+// The simplest one to use is the compiler flag -ftrapv, which detects integer
+// overflows and similar errors. However, due to optimizations and compilers
+// taking advantage of undefined behavior sometimes it may not actually detect
+// anything.
+//
+// You can also use compiler-based stack protection to possibly detect possible
+// stack buffer overruns.
+//
+// For more accurate diagnostics, you can use an undefined arithmetic operation
+// detector such as the clang-based tool:
+//
+// "IOC: An Integer Overflow Checker for C/C++"
+//
+// Available at: http://embed.cs.utah.edu/ioc/
+//
+// It might also be useful to use Google's AddressSanitizer to detect
+// stack buffer overruns, which valgrind can't currently detect.
+
+// Let's force this code not to be inlined, in order to actually
+// test a generic version of the function. This increases the chance
+// that -ftrapv will detect overflows.
+NOINLINE void mysetint64(CBigNum& num, int64 n)
+{
+ num.setint64(n);
+}
+
+// For each number, we do 2 tests: one with inline code, then we reset the
+// value to 0, then the second one with a non-inlined function.
+BOOST_AUTO_TEST_CASE(bignum_setint64)
+{
+ int64 n;
+
+ {
+ n = 0;
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "0");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "0");
+ }
+ {
+ n = 1;
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "1");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "1");
+ }
+ {
+ n = -1;
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "-1");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "-1");
+ }
+ {
+ n = 5;
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "5");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "5");
+ }
+ {
+ n = -5;
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "-5");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "-5");
+ }
+ {
+ n = std::numeric_limits<int64>::min();
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "-9223372036854775808");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "-9223372036854775808");
+ }
+ {
+ n = std::numeric_limits<int64>::max();
+ CBigNum num(n);
+ BOOST_CHECK(num.ToString() == "9223372036854775807");
+ num.setulong(0);
+ BOOST_CHECK(num.ToString() == "0");
+ mysetint64(num, n);
+ BOOST_CHECK(num.ToString() == "9223372036854775807");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 9cb0efecfd..6bc5e3b99e 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
BOOST_CHECK(addrs[0] == keyaddr[0]);
BOOST_CHECK(addrs[1] == keyaddr[1]);
- BOOST_CHECK(nRequired = 1);
+ BOOST_CHECK(nRequired == 1);
BOOST_CHECK(IsMine(keystore, s));
BOOST_CHECK(!IsMine(emptykeystore, s));
BOOST_CHECK(!IsMine(partialkeystore, s));
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
new file mode 100644
index 0000000000..e5a7562d97
--- /dev/null
+++ b/src/test/netbase_tests.cpp
@@ -0,0 +1,102 @@
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+#include <vector>
+
+#include "netbase.h"
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(netbase_tests)
+
+BOOST_AUTO_TEST_CASE(netbase_networks)
+{
+ BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
+ BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE);
+ BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4);
+ BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6);
+ BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
+}
+
+BOOST_AUTO_TEST_CASE(netbase_properties)
+{
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());
+ BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4());
+ BOOST_CHECK(CNetAddr("::1").IsIPv6());
+ BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918());
+ BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918());
+ BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918());
+ BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849());
+ BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927());
+ BOOST_CHECK(CNetAddr("2002::1").IsRFC3964());
+ BOOST_CHECK(CNetAddr("FC00::").IsRFC4193());
+ BOOST_CHECK(CNetAddr("2001::2").IsRFC4380());
+ BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843());
+ BOOST_CHECK(CNetAddr("FE80::").IsRFC4862());
+ BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052());
+ BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal());
+ BOOST_CHECK(CNetAddr("::1").IsLocal());
+ BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable());
+ BOOST_CHECK(CNetAddr("2001::1").IsRoutable());
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsValid());
+}
+
+bool static TestSplitHost(string test, string host, int port)
+{
+ string hostOut;
+ int portOut = -1;
+ SplitHostPort(test, portOut, hostOut);
+ return hostOut == host && port == portOut;
+}
+
+BOOST_AUTO_TEST_CASE(netbase_splithost)
+{
+ BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80));
+ BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333));
+ BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333));
+ BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333));
+ BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
+ BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
+ BOOST_CHECK(TestSplitHost(":8333", "", 8333));
+ BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
+ BOOST_CHECK(TestSplitHost("", "", -1));
+}
+
+bool static TestParse(string src, string canon)
+{
+ CService addr;
+ if (!LookupNumeric(src.c_str(), addr, 65535))
+ return canon == "";
+ return canon == addr.ToString();
+}
+
+BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
+{
+ BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333"));
+ BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse("::", "[::]:65535"));
+ BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
+ BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse(":::", ""));
+}
+
+BOOST_AUTO_TEST_CASE(onioncat_test)
+{
+ // values from http://www.cypherpunk.at/onioncat/wiki/OnionCat
+ CNetAddr addr1("5wyqrzbvrdsumnok.onion");
+ CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca");
+ BOOST_CHECK(addr1 == addr2);
+ BOOST_CHECK(addr1.IsTor());
+ BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
+ BOOST_CHECK(addr1.IsRoutable());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.cpp b/src/util.cpp
index b07c9c1b7e..9d0f9ab347 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -58,6 +58,7 @@ using namespace std;
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
+bool fDebugNet = false;
bool fPrintToConsole = false;
bool fPrintToDebugger = false;
bool fRequestShutdown = false;
@@ -702,6 +703,193 @@ string DecodeBase64(const string& str)
return string((const char*)&vchRet[0], vchRet.size());
}
+string EncodeBase32(const unsigned char* pch, size_t len)
+{
+ static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
+
+ string strRet="";
+ strRet.reserve((len+4)/5*8);
+
+ int mode=0, left=0;
+ const unsigned char *pchEnd = pch+len;
+
+ while (pch<pchEnd)
+ {
+ int enc = *(pch++);
+ switch (mode)
+ {
+ case 0: // we have no bits
+ strRet += pbase32[enc >> 3];
+ left = (enc & 7) << 2;
+ mode = 1;
+ break;
+
+ case 1: // we have three bits
+ strRet += pbase32[left | (enc >> 6)];
+ strRet += pbase32[(enc >> 1) & 31];
+ left = (enc & 1) << 4;
+ mode = 2;
+ break;
+
+ case 2: // we have one bit
+ strRet += pbase32[left | (enc >> 4)];
+ left = (enc & 15) << 1;
+ mode = 3;
+ break;
+
+ case 3: // we have four bits
+ strRet += pbase32[left | (enc >> 7)];
+ strRet += pbase32[(enc >> 2) & 31];
+ left = (enc & 3) << 3;
+ mode = 4;
+ break;
+
+ case 4: // we have two bits
+ strRet += pbase32[left | (enc >> 5)];
+ strRet += pbase32[enc & 31];
+ mode = 0;
+ }
+ }
+
+ static const int nPadding[5] = {0, 6, 4, 3, 1};
+ if (mode)
+ {
+ strRet += pbase32[left];
+ for (int n=0; n<nPadding[mode]; n++)
+ strRet += '=';
+ }
+
+ return strRet;
+}
+
+string EncodeBase32(const string& str)
+{
+ return EncodeBase32((const unsigned char*)str.c_str(), str.size());
+}
+
+vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
+{
+ static const int decode32_table[256] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ if (pfInvalid)
+ *pfInvalid = false;
+
+ vector<unsigned char> vchRet;
+ vchRet.reserve((strlen(p))*5/8);
+
+ int mode = 0;
+ int left = 0;
+
+ while (1)
+ {
+ int dec = decode32_table[(unsigned char)*p];
+ if (dec == -1) break;
+ p++;
+ switch (mode)
+ {
+ case 0: // we have no bits and get 5
+ left = dec;
+ mode = 1;
+ break;
+
+ case 1: // we have 5 bits and keep 2
+ vchRet.push_back((left<<3) | (dec>>2));
+ left = dec & 3;
+ mode = 2;
+ break;
+
+ case 2: // we have 2 bits and keep 7
+ left = left << 5 | dec;
+ mode = 3;
+ break;
+
+ case 3: // we have 7 bits and keep 4
+ vchRet.push_back((left<<1) | (dec>>4));
+ left = dec & 15;
+ mode = 4;
+ break;
+
+ case 4: // we have 4 bits, and keep 1
+ vchRet.push_back((left<<4) | (dec>>1));
+ left = dec & 1;
+ mode = 5;
+ break;
+
+ case 5: // we have 1 bit, and keep 6
+ left = left << 5 | dec;
+ mode = 6;
+ break;
+
+ case 6: // we have 6 bits, and keep 3
+ vchRet.push_back((left<<2) | (dec>>3));
+ left = dec & 7;
+ mode = 7;
+ break;
+
+ case 7: // we have 3 bits, and keep 0
+ vchRet.push_back((left<<5) | dec);
+ mode = 0;
+ break;
+ }
+ }
+
+ if (pfInvalid)
+ switch (mode)
+ {
+ case 0: // 8n base32 characters processed: ok
+ break;
+
+ case 1: // 8n+1 base32 characters processed: impossible
+ case 3: // +3
+ case 6: // +6
+ *pfInvalid = true;
+ break;
+
+ case 2: // 8n+2 base32 characters processed: require '======'
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 4: // 8n+4 base32 characters processed: require '===='
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 5: // 8n+5 base32 characters processed: require '==='
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 7: // 8n+7 base32 characters processed: require '='
+ if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)
+ *pfInvalid = true;
+ break;
+ }
+
+ return vchRet;
+}
+
+string DecodeBase32(const string& str)
+{
+ vector<unsigned char> vchRet = DecodeBase32(str.c_str());
+ return string((const char*)&vchRet[0], vchRet.size());
+}
+
bool WildcardMatch(const char* psz, const char* mask)
{
diff --git a/src/util.h b/src/util.h
index c1c91bdbc9..7b2c678916 100644
--- a/src/util.h
+++ b/src/util.h
@@ -105,6 +105,7 @@ inline void Sleep(int64 n)
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
extern bool fDebug;
+extern bool fDebugNet;
extern bool fPrintToConsole;
extern bool fPrintToDebugger;
extern bool fRequestShutdown;
@@ -146,6 +147,10 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
std::string EncodeBase64(const std::string& str);
+std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);
+std::string DecodeBase32(const std::string& str);
+std::string EncodeBase32(const unsigned char* pch, size_t len);
+std::string EncodeBase32(const std::string& str);
void ParseParameters(int argc, const char*const argv[]);
bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
@@ -272,7 +277,7 @@ inline int64 GetPerformanceCounter()
#else
timeval t;
gettimeofday(&t, NULL);
- nCounter = t.tv_sec * 1000000 + t.tv_usec;
+ nCounter = (int64) t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}