* update translations (ping tcatm on IRC for now)
* update (commit) version in sources
+ bitcoin-qt.pro
src/serialize.h
share/setup.nsi
doc/README*
-* update (commit) version in OSX app bundle
- contrib/Bitcoin.app/Contents/Info.plist
-
- * CFBundleShortVersionString should have value like 0.3.23
- * CFBundleVersion should have value like 323
-
* tag version in git
- $ git tag -a v0.3.23
+ git tag -a v0.5.1
* write release notes. git shortlog helps a lot:
- $ git shortlog --no-merges v0.3.22..
-
-* create source-only archive
-
- $ git archive --format=tar --prefix=bitcoin-0.3.23/ HEAD | \
- gzip -9c > ~/tmp/bitcoin-0.3.23-src.tar.gz
+ git shortlog --no-merges v0.5.0..
* perform gitian builds
- * From the bitcoin source dir
- $ cd ../gitian-builder
- $ ./bin/gbuild --commit bitcoin=v0.3.23 ../bitcoin/contrib/gitian.yml
- $ ./bin/gbuild --commit bitcoin=v0.3.23 ../bitcoin/contrib/gitian-win32.yml
-
- Build output expected:
- 1. linux 32-bit and 64-bit binaries + source
- 2. windows 32-bit binary + source
- 3. windows installer
+ * From a directory containing the bitcoin source, gitian-builder and gitian.sigs
+ export SIGNER=(your gitian key, ie bluematt, sipa, etc)
+ export VERSION=0.5.1
+ cd ./gitian-builder
+
+ * Fetch and build inputs:
+ mkdir -p inputs; cd inputs/
+ wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz
+ wget 'http://www.openssl.org/source/openssl-1.0.1b.tar.gz'
+ wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
+ wget 'http://downloads.sourceforge.net/project/boost/boost/1.47.0/boost_1_47_0.tar.bz2'
+ wget 'http://download.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.7.4.tar.gz'
+ cd ..
+ ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml
+ cp build/out/boost-win32-1.47.0-gitian.zip inputs/
+ ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml
+ cp build/out/qt-win32-4.7.4-gitian.zip inputs/
+
+ * Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32:
+ ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml
+ ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml
+ pushd build/out
+ zip -r bitcoin-${VERSION}-linux-gitian.zip *
+ mv bitcoin-${VERSION}-linux-gitian.zip ../../
+ popd
+ ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml
+ ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml
+ pushd build/out
+ zip -r bitcoin-${VERSION}-win32-gitian.zip *
+ mv bitcoin-${VERSION}-win32-gitian.zip ../../
+ popd
-* upload builds to SF
+ Build output expected:
+ 1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip)
+ 2. windows 32-bit binary, installer + source (bitcoin-${VERSION}-win32-gitian.zip)
+ 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/
+
+* repackage gitian builds for release as stand-alone zip/tar/installer exe
+
+ * Linux .tar.gz:
+ unzip bitcoin-${VERSION}-linux-gitian.zip -d bitcoin-${VERSION}-linux
+ tar czvf bitcoin-${VERSION}-linux.tar.gz bitcoin-${VERSION}-linux
+ rm -rf bitcoin-${VERSION}-linux
+
+ * Windows .zip and setup.exe:
+ unzip bitcoin-${VERSION}-win32-gitian.zip -d bitcoin-${VERSION}-win32
+ mv bitcoin-${VERSION}-win32/bitcoin-*-setup.exe .
+ zip -r bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32
+ rm -rf bitcoin-${VERSION}-win32
+
+* perform Mac build
+ See this blog post for how Gavin set up his build environment and
+ patched macdeployqt to build the OSX release:
+ http://gavintech.blogspot.com/2011/11/deploying-bitcoin-qt-on-osx.html
+ qmake USE_SSL=1 USE_UPNP=1 bitcoin-qt.pro
+ make
+ export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files
+ T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale)
+ contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist
+
+ Build output expected:
+ Bitcoin-Qt.dmg
+
+* upload builds to SourceForge
* create SHA256SUMS for builds, and PGP-sign it
* update forum version
-* update wiki
-
* update wiki download links
+ * update wiki changelog: https://en.bitcoin.it/wiki/Changelog
+
+* Commit your signature to gitian.sigs:
+ pushd gitian.sigs
+ git add ${VERSION}/${SIGNER}
+ git add ${VERSION}-win32/${SIGNER}
+ git commit -a
+ git push # Assuming you can push to the gitian.sigs tree
+ popd
+
+-------------------------------------------------------------------------
+
+* After 3 or more people have gitian-built, repackage gitian-signed zips:
+
+ * From a directory containing bitcoin source, gitian.sigs and gitian zips
+ export VERSION=0.5.1
+ mkdir bitcoin-${VERSION}-linux-gitian
+ pushd bitcoin-${VERSION}-linux-gitian
+ unzip ../bitcoin-${VERSION}-linux-gitian.zip
+ mkdir gitian
+ cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
+ for signer in $(ls ../gitian.sigs/${VERSION}/); do
+ cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
+ cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
+ done
+ zip -r bitcoin-${VERSION}-linux-gitian.zip *
+ cp bitcoin-${VERSION}-linux-gitian.zip ../
+ popd
+ mkdir bitcoin-${VERSION}-win32-gitian
+ pushd bitcoin-${VERSION}-win32-gitian
+ unzip ../bitcoin-${VERSION}-win32-gitian.zip
+ mkdir gitian
+ cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
+ for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do
+ cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
+ cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
+ done
+ zip -r bitcoin-${VERSION}-win32-gitian.zip *
+ cp bitcoin-${VERSION}-win32-gitian.zip ../
+ popd
+
+ * Upload gitian zips to SourceForge
#include "init.h"
#include "strlcpy.h"
-#ifdef __WXMSW__
+#ifdef WIN32
#include <string.h>
#else
#include <netinet/in.h>
bool fProxy = (fUseProxy && addrConnect.IsRoutable());
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
-#ifdef __WXMSW__
+#ifdef WIN32
u_long fNonblock = 1;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
return false;
}
socklen_t nRetSize = sizeof(nRet);
-#ifdef __WXMSW__
+#ifdef WIN32
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
#else
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
return false;
}
}
-#ifdef __WXMSW__
+#ifdef WIN32
else if (WSAGetLastError() != WSAEISCONN)
#else
else
CNode::ConnectNode immediately turns the socket back to non-blocking
but we'll turn it back to blocking just in case
*/
-#ifdef __WXMSW__
+#ifdef WIN32
fNonblock = 0;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
printf("connected %s\n", addrConnect.ToString().c_str());
// Set to nonblocking
-#ifdef __WXMSW__
+#ifdef WIN32
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
}
+std::map<unsigned int, int64> CNode::setBanned;
+CCriticalSection CNode::cs_setBanned;
+
+void CNode::ClearBanned()
+{
+ setBanned.clear();
+}
+
+bool CNode::IsBanned(unsigned int ip)
+{
+ bool fResult = false;
+ CRITICAL_BLOCK(cs_setBanned)
+ {
+ std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
+ if (i != setBanned.end())
+ {
+ int64 t = (*i).second;
+ if (GetTime() < t)
+ fResult = true;
+ }
+ }
+ return fResult;
+}
+
+bool CNode::Misbehaving(int howmuch)
+{
+ if (addr.IsLocal())
+ {
+ printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
+ return false;
+ }
+
+ nMisbehavior += howmuch;
+ if (nMisbehavior >= GetArg("-banscore", 100))
+ {
+ int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
+ CRITICAL_BLOCK(cs_setBanned)
+ if (setBanned[addr.ip] < banTime)
+ setBanned[addr.ip] = banTime;
+ CloseSocketDisconnect();
+ printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
+ return true;
+ }
+ return false;
+}
+
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
- if (hSocketMax > -1)
+ if (hSocketMax != INVALID_SOCKET)
{
printf("socket select error %d\n", nErr);
for (unsigned int i = 0; i <= hSocketMax; i++)
{
closesocket(hSocket);
}
+ else if (CNode::IsBanned(addr.ip))
+ {
+ printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
+ closesocket(hSocket);
+ }
else
{
printf("accepted connection %s\n", addr.ToString().c_str());
BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff);
+ int64 nANow = GetAdjustedTime();
+
CRITICAL_BLOCK(cs_mapAddresses)
{
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
continue;
- int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
- int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
+ int64 nSinceLastSeen = nANow - addr.nTime;
+ int64 nSinceLastTry = nANow - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
//
if (fShutdown)
return false;
- if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+ if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
+ FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
return false;
vnThreadsRunning[1]--;
vnThreadsRunning[2]--;
Sleep(100);
if (fRequestShutdown)
- Shutdown(NULL);
+ StartShutdown();
vnThreadsRunning[2]++;
if (fShutdown)
return;
int nOne = 1;
addrLocalHost.port = htons(GetListenPort());
-#ifdef __WXMSW__
+#ifdef WIN32
// Initialize Windows Sockets
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
-#ifndef __WXMSW__
+#ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted. Not an issue on windows.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
-#ifdef __WXMSW__
+#ifdef WIN32
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
#else
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
-#ifdef __WXMSW__
+#ifdef WIN32
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
-#ifdef __WXMSW__
+#ifdef WIN32
// Shutdown Windows Sockets
WSACleanup();
#endif
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/foreach.hpp>
+ #include <boost/thread.hpp>
using namespace std;
using namespace boost;
ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
CRYPTO_set_locking_callback(locking_callback);
-#ifdef __WXMSW__
+#ifdef WIN32
// Seed random number generator with screen scrape and other hardware sources
RAND_screen();
#endif
return;
nLastPerfmon = GetTime();
-#ifdef __WXMSW__
+#ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata[250000];
if (fileout)
{
static bool fStartedNewLine = true;
+ static boost::mutex mutexDebugLog;
+ boost::mutex::scoped_lock scoped_lock(mutexDebugLog);
// Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine)
}
}
-#ifdef __WXMSW__
+#ifdef WIN32
if (fPrintToDebugger)
{
static CCriticalSection cs_OutputDebugStringF;
return ret;
}
-
-string strprintf(const char* format, ...)
+string strprintf(const std::string &format, ...)
{
char buffer[50000];
char* p = buffer;
{
va_list arg_ptr;
va_start(arg_ptr, format);
- ret = _vsnprintf(p, limit, format, arg_ptr);
+ ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
break;
return str;
}
-
-bool error(const char* format, ...)
+bool error(const std::string &format, ...)
{
char buffer[50000];
int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+ int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
return ParseHex(str.c_str());
}
-
void ParseParameters(int argc, char* argv[])
{
mapArgs.clear();
pszValue = strchr(psz, '=');
*pszValue++ = '\0';
}
- #ifdef __WXMSW__
+ #ifdef WIN32
_strlwr(psz);
if (psz[0] == '/')
psz[0] = '-';
}
+string EncodeBase64(const unsigned char* pch, size_t len)
+{
+ static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ string strRet="";
+ strRet.reserve((len+2)/3*4);
+
+ int mode=0, left=0;
+ const unsigned char *pchEnd = pch+len;
-const char* wxGetTranslation(const char* pszEnglish)
+ while (pch<pchEnd)
+ {
+ int enc = *(pch++);
+ switch (mode)
+ {
+ case 0: // we have no bits
+ strRet += pbase64[enc >> 2];
+ left = (enc & 3) << 4;
+ mode = 1;
+ break;
+
+ case 1: // we have two bits
+ strRet += pbase64[left | (enc >> 4)];
+ left = (enc & 15) << 2;
+ mode = 2;
+ break;
+
+ case 2: // we have four bits
+ strRet += pbase64[left | (enc >> 6)];
+ strRet += pbase64[enc & 63];
+ mode = 0;
+ break;
+ }
+ }
+
+ if (mode)
+ {
+ strRet += pbase64[left];
+ strRet += '=';
+ if (mode == 1)
+ strRet += '=';
+ }
+
+ return strRet;
+}
+
+string EncodeBase64(const string& str)
{
-#ifdef GUI
- // Wrapper of wxGetTranslation returning the same const char* type as was passed in
- static CCriticalSection cs;
- CRITICAL_BLOCK(cs)
+ return EncodeBase64((const unsigned char*)str.c_str(), str.size());
+}
+
+vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
+{
+ static const int decode64_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, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -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, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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)*3/4);
+
+ int mode = 0;
+ int left = 0;
+
+ while (1)
{
- // Look in cache
- static map<string, char*> mapCache;
- map<string, char*>::iterator mi = mapCache.find(pszEnglish);
- if (mi != mapCache.end())
- return (*mi).second;
-
- // wxWidgets translation
- wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
-
- // We don't cache unknown strings because caller might be passing in a
- // dynamic string and we would keep allocating memory for each variation.
- if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
- return pszEnglish;
-
- // Add to cache, memory doesn't need to be freed. We only cache because
- // we must pass back a pointer to permanently allocated memory.
- char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
- strcpy(pszCached, strTranslated.utf8_str());
- mapCache[pszEnglish] = pszCached;
- return pszCached;
+ int dec = decode64_table[(unsigned char)*p];
+ if (dec == -1) break;
+ p++;
+ switch (mode)
+ {
+ case 0: // we have no bits and get 6
+ left = dec;
+ mode = 1;
+ break;
+
+ case 1: // we have 6 bits and keep 4
+ vchRet.push_back((left<<2) | (dec>>4));
+ left = dec & 15;
+ mode = 2;
+ break;
+
+ case 2: // we have 4 bits and get 6, we keep 2
+ vchRet.push_back((left<<4) | (dec>>2));
+ left = dec & 3;
+ mode = 3;
+ break;
+
+ case 3: // we have 2 bits and get 6
+ vchRet.push_back((left<<6) | dec);
+ mode = 0;
+ break;
+ }
}
- return NULL;
-#else
- return pszEnglish;
-#endif
+
+ if (pfInvalid)
+ switch (mode)
+ {
+ case 0: // 4n base64 characters processed: ok
+ break;
+
+ case 1: // 4n+1 base64 character processed: impossible
+ *pfInvalid = true;
+ break;
+
+ case 2: // 4n+2 base64 characters processed: require '=='
+ if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 3: // 4n+3 base64 characters processed: require '='
+ if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
+ *pfInvalid = true;
+ break;
+ }
+
+ return vchRet;
+}
+
+string DecodeBase64(const string& str)
+{
+ vector<unsigned char> vchRet = DecodeBase64(str.c_str());
+ return string((const char*)&vchRet[0], vchRet.size());
}
void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
{
-#ifdef __WXMSW__
+#ifdef WIN32
char pszModule[MAX_PATH];
pszModule[0] = '\0';
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
-#ifdef GUI
- if (wxTheApp && !fDaemon)
- MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
-#endif
throw;
}
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
-#ifdef GUI
- if (wxTheApp && !fDaemon)
- boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
-#endif
}
-#ifdef __WXMSW__
+#ifdef WIN32
typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
string MyGetSpecialFolderPath(int nFolder, bool fCreate)
// Windows: C:\Documents and Settings\username\Application Data\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
-#ifdef __WXMSW__
+#ifdef WIN32
// Windows
return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
#else
string strHome = pszHome;
if (strHome[strHome.size()-1] != '/')
strHome += '/';
-#ifdef __WXMAC_OSX__
+#ifdef MAC_OSX
// Mac
strHome += "Library/Application Support/";
filesystem::create_directory(strHome.c_str());
// - Median of other nodes's clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
+static int64 nMockTime = 0; // For unit testing
+
int64 GetTime()
{
+ if (nMockTime) return nMockTime;
+
return time(NULL);
}
+void SetMockTime(int64 nMockTimeIn)
+{
+ nMockTime = nMockTimeIn;
+}
+
static int64 nTimeOffset = 0;
int64 GetAdjustedTime()