From 4843b55fd167c54d86eb9e1f19525ed363cfe72d Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Sun, 13 May 2012 21:31:59 +0200 Subject: [PATCH 01/36] Make CNetAddr::GetHash() return an unsigned val. This prevents an undefined operation in main.cpp, when shifting the hash value left by 32 bits. Shifting a signed int left into the sign bit is undefined in C++11. --- src/main.cpp | 2 +- src/netbase.cpp | 4 ++-- src/netbase.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 20bb56e96..f71702f0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2440,7 +2440,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) static uint256 hashSalt; if (hashSalt == 0) RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt)); - 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 mapMix; diff --git a/src/netbase.cpp b/src/netbase.cpp index 2131bdf75..c237e2dc4 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -820,10 +820,10 @@ std::vector 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; } diff --git a/src/netbase.h b/src/netbase.h index 514a1ae95..544a66686 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -66,7 +66,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 GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; From fe78c9ae8b4c9701cf6d84a0572a2d503c6ee424 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Mon, 14 May 2012 02:50:01 +0200 Subject: [PATCH 02/36] Don't overflow signed ints in CBigNum::setint64(). CBigNum::setint64() does 'n <<= 8', where n is of type "long long". This leads to shifting onto and past the sign bit, which is undefined behavior in C++11 and can cause problems in the future. --- src/bignum.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/bignum.h b/src/bignum.h index f0971e885..3716c4965 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -122,16 +122,22 @@ public: return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::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) { - n = -n; + n = -sn; fNegative = true; + } else { + n = sn; + fNegative = false; } + bool fLeadingZeroes = true; for (int i = 0; i < 8; i++) { From 62e0453ce0ee0f03fca4626882263ec41dc1d64d Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Mon, 14 May 2012 21:15:27 +0200 Subject: [PATCH 03/36] Add test case for CBigNum::setint64(). One of the test cases currently aborts when using gcc's flag -ftrapv, due to negating an INT64_MIN int64 variable, which is an undefined operation. This will be fixed in a subsequent commit. --- src/test/bignum_tests.cpp | 110 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/test/bignum_tests.cpp diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp new file mode 100644 index 000000000..ca17766d1 --- /dev/null +++ b/src/test/bignum_tests.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include "bignum.h" + +BOOST_AUTO_TEST_SUITE(bignum_tests) + + +// 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. +void mysetint64(CBigNum& num, int64 n) __attribute__((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 = LLONG_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 = LLONG_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() From 5849bd472a3a7296f91b887884946218897ca11f Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Mon, 14 May 2012 21:17:24 +0200 Subject: [PATCH 04/36] Fix signed subtraction overflow in CBigNum::setint64(). As noticed by sipa (Pieter Wuille), this can happen when CBigNum::setint64() is called with an integer value of INT64_MIN (-2^63). When compiled with -ftrapv, the program would crash. Otherwise, it would execute an undefined operation (although in practice, usually the correct one). --- src/bignum.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bignum.h b/src/bignum.h index 3716c4965..5190c2f39 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -131,7 +131,15 @@ public: if (sn < (int64)0) { - n = -sn; + // 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; From 78e851f94f67b56e9baa8a62d6266c6bf979ee9e Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Thu, 31 May 2012 19:12:01 +0200 Subject: [PATCH 05/36] Fix noinline definition so that it works for more compilers. --- src/test/bignum_tests.cpp | 5 ++--- src/util.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index ca17766d1..16e4449e9 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -2,6 +2,7 @@ #include #include "bignum.h" +#include "util.h" BOOST_AUTO_TEST_SUITE(bignum_tests) @@ -29,9 +30,7 @@ BOOST_AUTO_TEST_SUITE(bignum_tests) // 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. -void mysetint64(CBigNum& num, int64 n) __attribute__((noinline)); - -void mysetint64(CBigNum& num, int64 n) +NOINLINE void mysetint64(CBigNum& num, int64 n) { num.setint64(n); } diff --git a/src/util.h b/src/util.h index 8e65fa786..0d5221c33 100644 --- a/src/util.h +++ b/src/util.h @@ -43,6 +43,23 @@ static const int64 CENT = 1000000; #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) #define printf OutputDebugStringF +// 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 + #ifdef snprintf #undef snprintf #endif From 10b45b4c2e11994aa2aed966f83d84f83852d1e1 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Thu, 31 May 2012 20:31:15 +0200 Subject: [PATCH 06/36] Use C++-style numeric limits instead of C-style. --- src/test/bignum_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index 16e4449e9..38c625bba 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "bignum.h" #include "util.h" @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) BOOST_CHECK(num.ToString() == "-5"); } { - n = LLONG_MIN; + n = std::numeric_limits::min(); CBigNum num(n); BOOST_CHECK(num.ToString() == "-9223372036854775808"); num.setulong(0); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) BOOST_CHECK(num.ToString() == "-9223372036854775808"); } { - n = LLONG_MAX; + n = std::numeric_limits::max(); CBigNum num(n); BOOST_CHECK(num.ToString() == "9223372036854775807"); num.setulong(0); From 43346904e15c3f1c3f92eee140dbf37b897c7c21 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Thu, 7 Jun 2012 19:11:15 +0200 Subject: [PATCH 07/36] Don't overflow integer on 32-bit machines. This was causing test_bitcoin to abort on a 32-bit system likely due to -ftrapv. --- src/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.h b/src/util.h index 0d5221c33..cfc20b327 100644 --- a/src/util.h +++ b/src/util.h @@ -288,7 +288,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; } From 31ac53fbdc2346876da201b9e1495565b38b46ba Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Thu, 7 Jun 2012 19:14:18 +0200 Subject: [PATCH 08/36] Move NOINLINE definition to test where it's used. --- src/test/bignum_tests.cpp | 16 ++++++++++++++++ src/util.h | 17 ----------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index 38c625bba..8620f81f1 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -6,6 +6,22 @@ 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. // diff --git a/src/util.h b/src/util.h index cfc20b327..b77eb43c9 100644 --- a/src/util.h +++ b/src/util.h @@ -43,23 +43,6 @@ static const int64 CENT = 1000000; #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) #define printf OutputDebugStringF -// 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 - #ifdef snprintf #undef snprintf #endif From b5782531adfbbe288266178e75cb7ea52aaf630c Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Wed, 13 Jun 2012 18:34:29 +0200 Subject: [PATCH 09/36] set cursor for balance field to IBeamCursor (to show the user it IS selectable) and set autoDefault to false for the buttons that do not need this --- src/qt/forms/sendcoinsdialog.ui | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 023a72ac2..10a1586d4 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -70,6 +70,9 @@ :/icons/add:/icons/add + + false + @@ -93,6 +96,9 @@ 300 + + false + @@ -109,6 +115,9 @@ + + IBeamCursor + 123.456 BTC From 7d72a8c36a872113583e6db85707a8f17f3d3927 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 14 Jun 2012 15:06:23 +0200 Subject: [PATCH 10/36] Show command line options as dialog when opened from debug window On Linux/Mac the command-line options were printed to stderr when the button was pressed in the debug window, resulting in confusion. This is fixed in this commit by adding a separate method. --- src/qt/bitcoin.cpp | 2 +- src/qt/guiutil.cpp | 16 +++++++++++----- src/qt/guiutil.h | 6 +++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 8c8c73f06..b4e751077 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/guiutil.cpp b/src/qt/guiutil.cpp index a8c232885..50ed2eed0 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 ca0634851..024069550 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; From 1e8aeae15a300eca107752d6ef52fa0f5c2410c3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 30 May 2012 22:44:23 +0200 Subject: [PATCH 11/36] Improve parsing of IPv6 addresses Implement the following rules: * Interpret [X]:Y as host=X port=Y, if Y is an integer * Interpret X:Y as host=X port=Y, if Y is an integer and X contains no colon * Interpret X:Y as host=X:Y port=default otherwise --- src/netbase.cpp | 69 +++++++++++++++++++------------------------------ src/netbase.h | 1 + 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index d1ead79eb..343da6365 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -33,6 +33,27 @@ 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& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { vIP.clear(); @@ -114,36 +135,11 @@ bool Lookup(const char *pszName, std::vector& 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 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 +492,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); diff --git a/src/netbase.h b/src/netbase.h index 0f6fc9b49..878ac986b 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -133,6 +133,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); From c4971e24f9bc0b3acc7478b53d03d73a6e64ecbc Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 8 Jun 2012 18:42:05 +0200 Subject: [PATCH 12/36] Add netbase tests --- src/test/netbase_tests.cpp | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/test/netbase_tests.cpp diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp new file mode 100644 index 000000000..77a360aca --- /dev/null +++ b/src/test/netbase_tests.cpp @@ -0,0 +1,92 @@ +#include + +#include +#include + +#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").IsOnionCat()); + 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_CHECK(TestParse("128.5.1", "128.5.0.1:65535")); +} + +BOOST_AUTO_TEST_SUITE_END() From e0873dafc57980caffd1cdff597b4317d9cdcea6 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sat, 9 Jun 2012 15:41:21 +0200 Subject: [PATCH 13/36] add the slot updateDisplayUnit() to overviewpage, sendcoinsdialog, sendcoinsentry and connect it to displayUnitChanged() - this ensures all fields in the GUI, who use a display unit are imediately updated, when the user changes this setting in the optionsdialog / ensure used fields init with the current set display unit --- src/qt/overviewpage.cpp | 24 +++++++++++++++--------- src/qt/overviewpage.h | 2 +- src/qt/sendcoinsdialog.cpp | 16 +++++++++++++--- src/qt/sendcoinsdialog.h | 2 +- src/qt/sendcoinsentry.cpp | 18 ++++++++++++++---- src/qt/sendcoinsentry.h | 1 + 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 35d48581e..07be9c520 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 c7d3a4242..00048cc8f 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 76952e44e..86c2b01fe 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 915b7ad46..def2f83c3 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 5960597c7..71891e79c 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 cdbf89326..db6cba0d8 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; From 3bbb49de55dfae8c608366ceaf79f5bf3c1cc672 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 17 Jun 2012 12:12:56 -0400 Subject: [PATCH 14/36] Fix inverted logic for !Discover/!UPNP when !Listen. --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 08b594f56..4ab7bdc42 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -344,7 +344,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); From 2bbfcd2d0270c0b4106cfd7e39db6324018cc30c Mon Sep 17 00:00:00 2001 From: Fordy Date: Mon, 18 Jun 2012 14:57:28 +0800 Subject: [PATCH 15/36] Update OSX build instructions --- doc/build-osx.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/build-osx.txt b/doc/build-osx.txt index 256614f7a..b0c752e8f 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -15,14 +15,14 @@ Douglas Huff 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 OSX +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: From 8b7b3be76529612ebe219e315a273d05066d2118 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 18 Jun 2012 21:58:20 +0800 Subject: [PATCH 16/36] Further updates to build instructions --- doc/build-msw.txt | 2 +- doc/build-osx.txt | 16 ++++++++-------- doc/build-unix.txt | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/build-msw.txt b/doc/build-msw.txt index 73ea81275..ad23e6867 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 b0c752e8f..81e9960d5 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -1,18 +1,18 @@ 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 +Mac OSX bitcoind build instructions Laszlo Hanyecz Douglas Huff -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, 10.6 and 10.7 intel. PPC is not supported because it's big-endian. diff --git a/doc/build-unix.txt b/doc/build-unix.txt index 9033301ab..825491bba 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 ------------ From baf814f3dae1fa6d7fb69e1f1234074e83318eef Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 18 Jun 2012 22:09:19 +0800 Subject: [PATCH 17/36] OS X not OSX --- doc/build-osx.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/build-osx.txt b/doc/build-osx.txt index 81e9960d5..24e825ca8 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -7,7 +7,7 @@ cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. -Mac OSX bitcoind build instructions +Mac OS X bitcoind build instructions Laszlo Hanyecz Douglas Huff @@ -21,7 +21,7 @@ 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. XCode should be available on your OSX +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/ From 4c6b210af0d6047aafe0f600cbcc5122df4132a1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 19 Jun 2012 02:22:09 +0200 Subject: [PATCH 18/36] Fix netbase tests * Do not rely on "a.b.c" being interpreted as "a.0.b.c" * Parse numeric addresses for address families for which no device is configured --- src/netbase.cpp | 6 ++---- src/test/netbase_tests.cpp | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 953ef13f1..ffd3ea68a 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -65,19 +65,17 @@ bool static LookupIntern(const char *pszName, std::vector& 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); diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 77a360aca..f0828f39f 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -86,7 +86,6 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) BOOST_CHECK(TestParse("[::]:8333", "[::]:8333")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); BOOST_CHECK(TestParse(":::", "")); - BOOST_CHECK(TestParse("128.5.1", "128.5.0.1:65535")); } BOOST_AUTO_TEST_SUITE_END() From 16d567194305d728ca433de4b78eb049a86aa450 Mon Sep 17 00:00:00 2001 From: xanatos Date: Tue, 19 Jun 2012 09:48:00 +0300 Subject: [PATCH 19/36] If (for example) the new max_size must be 5 then at the end the queue.size() must be <= 5, so the exit condition must be <=, so the continuing condition must be > (and not >= as it was). --- src/mruset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mruset.h b/src/mruset.h index ad2e160d3..a52735182 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(); From c283b3c569d6ea67a07e96a6dea3c1645d7be259 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Tue, 19 Jun 2012 15:50:12 -0400 Subject: [PATCH 20/36] print large orphan warning BEFORE deleting pvMsg --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 0654ff889..2d3e35138 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; } From 229c34f818dabf569a4bc90c9b335aeeda8f8558 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Mon, 18 Jun 2012 22:48:35 +0200 Subject: [PATCH 21/36] GUI: ensure a changed bitcoin unit immediately updates the tx list amounts --- src/qt/transactiontablemodel.cpp | 7 +++++++ src/qt/transactiontablemodel.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index a86b1f7c5..b3e001ea1 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 0aafa7091..fd321ce28 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; }; From 70f6049f713a7c8b0672d573b8222b70b6912631 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Jun 2012 15:07:41 +0200 Subject: [PATCH 22/36] Remove CTxDB::ReadOwnerTxes. It seems it wasn't ever used since 0.1.5. --- src/db.cpp | 60 ------------------------------------------------------ src/db.h | 1 - 2 files changed, 61 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 4f4e1d84b..ecdf32a8f 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& 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 552705456..1030a40c4 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& vtx); bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); bool ReadDiskTx(uint256 hash, CTransaction& tx); bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); From d65e959baeb36a5d739fc693442ee6fdcfb8b47a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Jun 2012 18:13:16 +0200 Subject: [PATCH 23/36] Update my GPG key --- contrib/gitian-downloader/sipa-key.pgp | Bin 108922 -> 109468 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contrib/gitian-downloader/sipa-key.pgp b/contrib/gitian-downloader/sipa-key.pgp index a52a5deb1b6c4691bb7073fc819080f66df6d2f2..ffa09bb4ad276c2380686a7e1619d18dce71c8a1 100644 GIT binary patch delta 1670 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 From 0783bcceef7c0adda3396ad1dd6478d1133ba2c8 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 20 Jun 2012 16:15:46 +0000 Subject: [PATCH 24/36] gitian-downloader: Update luke-jr's key --- contrib/gitian-downloader/luke-jr-key.pgp | Bin 5467 -> 7322 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contrib/gitian-downloader/luke-jr-key.pgp b/contrib/gitian-downloader/luke-jr-key.pgp index c40917d78c512ac13414b0d9e92c59f57e6a9c77..275b041d2059ece19e1a4ade74b32654ab3a2c56 100644 GIT binary patch delta 5057 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 delta 3198 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 From a3d12f445ab17141c52a20bc53e6533a9410ccc9 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Thu, 21 Jun 2012 12:05:06 +0200 Subject: [PATCH 25/36] fix a memory leak in key.cpp - add EC_KEY_free() in CKey::Reset() when pkey != NULL - init pkey with NULL in CKey constructor --- src/key.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/key.cpp b/src/key.cpp index 57ab842bc..c943a38ea 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(); } From fdfdb5cd7db579e46d863ca99178f4d78402d28b Mon Sep 17 00:00:00 2001 From: xanatos Date: Thu, 21 Jun 2012 21:37:49 +0300 Subject: [PATCH 26/36] = instead of == in multisig_tests.cpp --- src/test/multisig_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 9cb0efecf..6bc5e3b99 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)); From c4c99ade653e8e8f62ed4af4c22e196c8310d0d8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 22 Jan 2012 20:32:58 +0100 Subject: [PATCH 27/36] Base32 encoding/decoding --- src/util.cpp | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 4 ++ 2 files changed, 191 insertions(+) diff --git a/src/util.cpp b/src/util.cpp index b07c9c1b7..931d27ba0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -702,6 +702,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> 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 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 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 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 c9b2b2f17..058f90979 100644 --- a/src/util.h +++ b/src/util.h @@ -146,6 +146,10 @@ std::vector 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 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); From e0be8da3924031ea115c93551dfa463f84d3a120 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 29 Jan 2012 11:38:33 +0100 Subject: [PATCH 28/36] Unit tests for base32 encode/decode --- src/test/base32_tests.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/base32_tests.cpp diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp new file mode 100644 index 000000000..756c72b94 --- /dev/null +++ b/src/test/base32_tests.cpp @@ -0,0 +1,20 @@ +#include + +#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 Date: Fri, 22 Jun 2012 11:43:34 -0400 Subject: [PATCH 29/36] RPC: add 'getrawmempool', listing all transaction ids in memory pool --- src/bitcoinrpc.cpp | 18 ++++++++++++++++++ src/main.cpp | 8 ++++++++ src/main.h | 1 + 3 files changed, 27 insertions(+) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 8c3a615fd..9dd677498 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -2194,6 +2194,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 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) @@ -2317,6 +2334,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/main.cpp b/src/main.cpp index 2d3e35138..6765ed5f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -652,7 +652,15 @@ bool CTxMemPool::remove(CTransaction &tx) return true; } +void CTxMemPool::queryHashes(std::vector& vtxid) +{ + vtxid.clear(); + LOCK(cs); + vtxid.reserve(mapTx.size()); + for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + vtxid.push_back((*mi).first); +} diff --git a/src/main.h b/src/main.h index 29c9a8bce..bb094ad3c 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& vtxid); unsigned long size() { From e6332751c613b3a248ec9638f0cce7964fd86da0 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 22 Jun 2012 11:50:52 -0400 Subject: [PATCH 30/36] Remove some rule differences which aren't needed with testnet3. Bip16 and Bip30 had early activation dates for testnet, but with the reset they might as well use the same dates as the main network. --- src/main.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2d3e35138..e301ee7c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1317,8 +1317,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 +1331,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 From d07eaba195984410522b78884ff7ff72ec2ecc78 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 22 Jun 2012 13:11:57 -0400 Subject: [PATCH 31/36] Introduce -debugnet option, thereby quieting some redundant debug messages Prior to this change, each TX typically generated 3+ debug messages, askfor tx 8644cc97480ba1537214 0 sending getdata: tx 8644cc97480ba1537214 askfor tx 8644cc97480ba1537214 1339640761000000 askfor tx 8644cc97480ba1537214 1339640881000000 CTxMemPool::accept() : accepted 8644cc9748 (poolsz 6857) After this change, there is only one message for each valid TX received CTxMemPool::accept() : accepted 22a73c5d8c (poolsz 42) and two messages for each orphan tx received ERROR: FetchInputs() : 673dc195aa mempool Tx prev not found 1e439346fc stored orphan tx 673dc195aa (mapsz 19) The -debugnet option, or its superset -debug, will restore the full debug output. --- src/init.cpp | 7 +++++++ src/main.cpp | 3 ++- src/net.h | 3 ++- src/util.cpp | 1 + src/util.h | 1 + 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index bf9551e85..04541c540 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -344,6 +344,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) diff --git a/src/main.cpp b/src/main.cpp index 50a740d16..c82b6fd5e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3142,7 +3142,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/net.h b/src/net.h index c9c965722..f059c7a44 100644 --- a/src/net.h +++ b/src/net.h @@ -296,7 +296,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/util.cpp b/src/util.cpp index b07c9c1b7..4b1c1ae11 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -58,6 +58,7 @@ using namespace std; map mapArgs; map > mapMultiArgs; bool fDebug = false; +bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; bool fRequestShutdown = false; diff --git a/src/util.h b/src/util.h index c1c91bdbc..82509e925 100644 --- a/src/util.h +++ b/src/util.h @@ -105,6 +105,7 @@ inline void Sleep(int64 n) extern std::map mapArgs; extern std::map > mapMultiArgs; extern bool fDebug; +extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; extern bool fRequestShutdown; From 70f7f0038592a28e846f02d084f0119fc34eb52f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 29 Apr 2012 02:11:56 +0200 Subject: [PATCH 32/36] Node support for Tor hidden services This commit adds support for .onion addresses (mapped into the IPv6 by using OnionCat's range and encoding), and the ability to connect to them via a SOCKS5 proxy. --- src/netbase.cpp | 91 +++++++++++++++++++++++++++++++------- src/netbase.h | 7 +-- src/test/base32_tests.cpp | 2 +- src/test/netbase_tests.cpp | 13 +++++- src/util.cpp | 2 +- 5 files changed, 94 insertions(+), 21 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index ffd3ea68a..21fca4737 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -57,6 +57,15 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { bool static LookupIntern(const char *pszName, std::vector& 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)); @@ -530,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 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 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(); @@ -576,7 +611,7 @@ bool CNetAddr::IsIPv4() const bool CNetAddr::IsIPv6() const { - return (!IsIPv4()); + return (!IsIPv4() && !IsTor() && !IsI2P()); } bool CNetAddr::IsRFC1918() const @@ -635,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); } @@ -705,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 @@ -716,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; @@ -727,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; @@ -739,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", @@ -828,6 +865,18 @@ std::vector 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; @@ -861,11 +910,11 @@ 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 +// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners: for Tor partners: for I2P partners: +// 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable +// 1 - teredo // 1 - teredo // 1 - ipv4 // 1 - the rest // 1 - the rest +// 2 - tunneled ipv6 // 2 - tunneled ipv6 // 2 - ip4 // 2 - I2P +// 3 - ipv4 // 3 - ipv6 // 3 - tor // 4 - ipv6 // 4 - ipv4 int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { @@ -873,6 +922,18 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const return 0; if (paddrPartner && paddrPartner->IsIPv4()) return IsIPv4() ? 1 : 0; + if (paddrPartner && paddrPartner->IsTor()) { + if (IsIPv4()) + return 2; + if (IsTor()) + return 3; + return 1; + } + if (paddrPartner && paddrPartner->IsI2P()) { + if (IsI2P()) + return 2; + return 1; + } if (IsRFC4380()) return 1; if (IsRFC3964() || IsRFC6052()) @@ -1036,7 +1097,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 7a797e2fd..36f29b0b3 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -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; diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 756c72b94..fdf328591 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -7,7 +7,7 @@ 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======"}; + static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"}; for (unsigned int i=0; i Date: Tue, 1 May 2012 17:32:42 +0200 Subject: [PATCH 33/36] Rewrite CNetAddr::GetReachabilityFrom() Add support for Tor/I2P networks, and make code more readable. --- src/netbase.cpp | 103 ++++++++++++++++++++++++++++++++++-------------- src/netbase.h | 2 +- 2 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 21fca4737..aa767cd3e 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -910,39 +910,82 @@ void CNetAddr::print() const printf("CNetAddr(%s)\n", ToString().c_str()); } -// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners: for Tor partners: for I2P partners: -// 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable -// 1 - teredo // 1 - teredo // 1 - ipv4 // 1 - the rest // 1 - the rest -// 2 - tunneled ipv6 // 2 - tunneled ipv6 // 2 - ip4 // 2 - I2P -// 3 - ipv4 // 3 - ipv6 // 3 - tor -// 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 (paddrPartner && paddrPartner->IsTor()) { - if (IsIPv4()) - return 2; - if (IsTor()) - return 3; - return 1; + 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 + } } - if (paddrPartner && paddrPartner->IsI2P()) { - if (IsI2P()) - return 2; - return 1; - } - 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; } void CService::Init() diff --git a/src/netbase.h b/src/netbase.h index 36f29b0b3..f097d7f5a 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; From 54ce3bad64ea4dff64f16c12b287383ad96a875a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 May 2012 21:04:07 +0200 Subject: [PATCH 34/36] Add -tor and related configuration --- src/init.cpp | 23 ++++++++++++++++++++--- src/net.cpp | 12 +++++++++--- src/net.h | 1 + 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4ab7bdc42..62fff5f9e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -222,6 +222,7 @@ std::string HelpMessage() " -timeout= " + _("Specify connection timeout (in milliseconds)") + "\n" + " -proxy= " + _("Connect through socks proxy") + "\n" + " -socks= " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" + + " -tor= " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n" " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + " -port= " + _("Listen for connections on (default: 8333 or testnet: 18333)") + "\n" + " -maxconnections= " + _("Maintain at most connections to peers (default: 125)") + "\n" + @@ -229,12 +230,12 @@ std::string HelpMessage() " -connect= " + _("Connect only to the specified node(s)") + "\n" + " -seednode= " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + " -externalip= " + _("Specify your own public address") + "\n" + - " -onlynet= " + _("Only connect to nodes in network (IPv4 or IPv6)") + "\n" + + " -onlynet= " + _("Only connect to nodes in network (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= " + _("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= " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -bantime= " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + " -maxreceivebuffer= " + _("Maximum per-connection receive buffer, *1000 bytes (default: 10000)") + "\n" + @@ -469,8 +470,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())); @@ -483,6 +486,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/net.cpp b/src/net.cpp index 804cb0f54..441d28bb9 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(); diff --git a/src/net.h b/src/net.h index c9c965722..fb998a29e 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); From 863e995b79ec388bf292d80f181912d01e20e2e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 May 2012 22:03:51 +0200 Subject: [PATCH 35/36] Debug version messages --- src/main.cpp | 2 +- src/net.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 2d3e35138..9ca4889be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2419,7 +2419,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); } diff --git a/src/net.cpp b/src/net.cpp index 441d28bb9..77fd334ee 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -549,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()), nBestHeight); } From d789a3f1403fb6709a3ca26ef9ecc75b0b0a68a4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 May 2012 21:53:44 +0200 Subject: [PATCH 36/36] Some documentation about tor --- doc/Tor.txt | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 doc/Tor.txt diff --git a/doc/Tor.txt b/doc/Tor.txt new file mode 100644 index 000000000..f44b016f2 --- /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 +